Changes of Revision 140
[-] | Changed | nginx.spec |
x 1
2 --http-fastcgi-temp-path=%{nginx_home_tmp}/fastcgi \ 3 --pid-path=%{_localstatedir}/run/%{name}.pid \ 4 --lock-path=%{_localstatedir}/lock/subsys/%{name} \ 5 + --with-poll_module \ 6 --with-http_ssl_module \ 7 --with-http_v2_module \ 8 --with-http_realip_module \ 9 --with-http_addition_module \ 10 - --with-http_xslt_module \ 11 - --with-http_image_filter_module \ 12 - --with-http_geoip_module \ 13 --with-http_sub_module \ 14 --with-http_dav_module \ 15 --with-http_flv_module \ 16
17 --with-http_secure_link_module \ 18 --with-http_degradation_module \ 19 --with-http_stub_status_module \ 20 - --with-stream \ 21 + --with-http_xslt_module=dynamic \ 22 + --with-http_image_filter_module=dynamic \ 23 + --with-http_geoip_module=dynamic \ 24 + --with-http_perl_module=dynamic \ 25 + --with-stream=dynamic \ 26 --with-stream_ssl_module \ 27 --with-threads \ 28 --with-libatomic \ 29
30 %if 0%{with_rtmp_ext} 31 --add-module=%{_builddir}/nginx-%{version}/%{rtmp} \ 32 %endif 33 - --with-mail \ 34 + --with-mail=dynamic \ 35 --with-mail_ssl_module 36 37 make 38 |
||
[+] | Changed | nginx-1.9.13.tar.gz/CHANGES ^ |
@@ -1,4 +1,51 @@ +Changes with nginx 1.9.13 29 Mar 2016 + + *) Change: non-idempotent requests (POST, LOCK, PATCH) are no longer + passed to the next server by default if a request has been sent to a + backend; the "non_idempotent" parameter of the "proxy_next_upstream" + directive explicitly allows retrying such requests. + + *) Feature: the ngx_http_perl_module can be built dynamically. + + *) Feature: UDP support in the stream module. + + *) Feature: the "aio_write" directive. + + *) Feature: now cache manager monitors number of elements in caches and + tries to avoid cache keys zone overflows. + + *) Bugfix: "task already active" and "second aio post" alerts might + appear in logs when using the "sendfile" and "aio" directives with + subrequests. + + *) Bugfix: "zero size buf in output" alerts might appear in logs if + caching was used and a client closed a connection prematurely. + + *) Bugfix: connections with clients might be closed needlessly if + caching was used. + Thanks to Justin Li. + + *) Bugfix: nginx might hog CPU if the "sendfile" directive was used on + Linux or Solaris and a file being sent was changed during sending. + + *) Bugfix: connections might hang when using the "sendfile" and "aio + threads" directives. + + *) Bugfix: in the "proxy_pass", "fastcgi_pass", "scgi_pass", and + "uwsgi_pass" directives when using variables. + Thanks to Piotr Sikora. + + *) Bugfix: in the ngx_http_sub_filter_module. + + *) Bugfix: if an error occurred in a cached backend connection, the + request was passed to the next server regardless of the + proxy_next_upstream directive. + + *) Bugfix: "CreateFile() failed" errors when creating temporary files on + Windows. + + Changes with nginx 1.9.12 24 Feb 2016 *) Feature: Huffman encoding of response headers in HTTP/2. | ||
[+] | Changed | nginx-1.9.13.tar.gz/CHANGES.ru ^ |
@@ -1,4 +1,54 @@ +Изменения в nginx 1.9.13 29.03.2016 + + *) Изменение: неидемпотентные запросы (POST, LOCK, PATCH) теперь по + умолчанию не передаются на другой сервер, если запрос уже был + отправлен на бэкенд; параметр non_idempotent директивы + proxy_next_upstream явно разрешает повторять такие запросы. + + *) Добавление: модуль ngx_http_perl_module теперь можно собрать + динамически. + + *) Добавление: поддержка UDP в модуле stream. + + *) Добавление: директива aio_write. + + *) Добавление: теперь cache manager следит за количеством элементов в + кэше и старается не допускать переполнений зоны разделяемой памяти. + + *) Исправление: при использовании директив sendfile и aio с подзапросами + в логах могли появляться сообщения "task already active" и "second + aio post". + + *) Исправление: при использовании кэширования в логах могли появляться + сообщения "zero size buf in output", если клиент закрывал соединение + преждевременно. + + *) Исправление: при использовании кэширования соединения с клиентами + могли закрываться без необходимости. + Спасибо Justin Li. + + *) Исправление: nginx мог нагружать процессор при использовании + директивы sendfile на Linux и Solaris, если отправляемый файл был + изменён в процессе отправки. + + *) Исправление: при использовании директив sendfile и "aio threads" + соединения могли зависать. + + *) Исправление: в директивах proxy_pass, fastcgi_pass, scgi_pass и + uwsgi_pass при использовании переменных. + Спасибо Piotr Sikora. + + *) Исправление: в модуле ngx_http_sub_filter_module. + + *) Исправление: если в закэшированном соединении к бэкенду происходила + ошибка, запрос передавался на другой сервер без учёта директивы + proxy_next_upstream. + + *) Исправление: ошибки "CreateFile() failed" при создании временных + файлов на Windows. + + Изменения в nginx 1.9.12 24.02.2016 *) Добавление: кодирование Хаффмана заголовков ответов в HTTP/2. | ||
[+] | Changed | nginx-1.9.13.tar.gz/auto/init ^ |
@@ -5,7 +5,6 @@ NGX_MAKEFILE=$NGX_OBJS/Makefile NGX_MODULES_C=$NGX_OBJS/ngx_modules.c -NGX_MODULES= NGX_AUTO_HEADERS_H=$NGX_OBJS/ngx_auto_headers.h NGX_AUTO_CONFIG_H=$NGX_OBJS/ngx_auto_config.h | ||
[+] | Changed | nginx-1.9.13.tar.gz/auto/install ^ |
@@ -3,7 +3,7 @@ # Copyright (C) Nginx, Inc. -if [ $USE_PERL = YES ]; then +if [ $USE_PERL != NO ]; then cat << END >> $NGX_MAKEFILE @@ -107,54 +107,54 @@ install: build $NGX_INSTALL_PERL_MODULES test -d '\$(DESTDIR)$NGX_PREFIX' || mkdir -p '\$(DESTDIR)$NGX_PREFIX' - test -d '\$(DESTDIR)`dirname "$NGX_SBIN_PATH"`' \ + test -d '\$(DESTDIR)`dirname "$NGX_SBIN_PATH"`' \\ || mkdir -p '\$(DESTDIR)`dirname "$NGX_SBIN_PATH"`' - test ! -f '\$(DESTDIR)$NGX_SBIN_PATH' \ - || mv '\$(DESTDIR)$NGX_SBIN_PATH' \ + test ! -f '\$(DESTDIR)$NGX_SBIN_PATH' \\ + || mv '\$(DESTDIR)$NGX_SBIN_PATH' \\ '\$(DESTDIR)$NGX_SBIN_PATH.old' cp $NGX_OBJS/nginx '\$(DESTDIR)$NGX_SBIN_PATH' - test -d '\$(DESTDIR)$NGX_CONF_PREFIX' \ + test -d '\$(DESTDIR)$NGX_CONF_PREFIX' \\ || mkdir -p '\$(DESTDIR)$NGX_CONF_PREFIX' cp conf/koi-win '\$(DESTDIR)$NGX_CONF_PREFIX' cp conf/koi-utf '\$(DESTDIR)$NGX_CONF_PREFIX' cp conf/win-utf '\$(DESTDIR)$NGX_CONF_PREFIX' - test -f '\$(DESTDIR)$NGX_CONF_PREFIX/mime.types' \ + test -f '\$(DESTDIR)$NGX_CONF_PREFIX/mime.types' \\ || cp conf/mime.types '\$(DESTDIR)$NGX_CONF_PREFIX' cp conf/mime.types '\$(DESTDIR)$NGX_CONF_PREFIX/mime.types.default' - test -f '\$(DESTDIR)$NGX_CONF_PREFIX/fastcgi_params' \ + test -f '\$(DESTDIR)$NGX_CONF_PREFIX/fastcgi_params' \\ || cp conf/fastcgi_params '\$(DESTDIR)$NGX_CONF_PREFIX' - cp conf/fastcgi_params \ + cp conf/fastcgi_params \\ '\$(DESTDIR)$NGX_CONF_PREFIX/fastcgi_params.default' - test -f '\$(DESTDIR)$NGX_CONF_PREFIX/fastcgi.conf' \ + test -f '\$(DESTDIR)$NGX_CONF_PREFIX/fastcgi.conf' \\ || cp conf/fastcgi.conf '\$(DESTDIR)$NGX_CONF_PREFIX' cp conf/fastcgi.conf '\$(DESTDIR)$NGX_CONF_PREFIX/fastcgi.conf.default' - test -f '\$(DESTDIR)$NGX_CONF_PREFIX/uwsgi_params' \ + test -f '\$(DESTDIR)$NGX_CONF_PREFIX/uwsgi_params' \\ || cp conf/uwsgi_params '\$(DESTDIR)$NGX_CONF_PREFIX' - cp conf/uwsgi_params \ + cp conf/uwsgi_params \\ '\$(DESTDIR)$NGX_CONF_PREFIX/uwsgi_params.default' - test -f '\$(DESTDIR)$NGX_CONF_PREFIX/scgi_params' \ + test -f '\$(DESTDIR)$NGX_CONF_PREFIX/scgi_params' \\ || cp conf/scgi_params '\$(DESTDIR)$NGX_CONF_PREFIX' - cp conf/scgi_params \ + cp conf/scgi_params \\ '\$(DESTDIR)$NGX_CONF_PREFIX/scgi_params.default' - test -f '\$(DESTDIR)$NGX_CONF_PATH' \ + test -f '\$(DESTDIR)$NGX_CONF_PATH' \\ || cp conf/nginx.conf '\$(DESTDIR)$NGX_CONF_PATH' cp conf/nginx.conf '\$(DESTDIR)$NGX_CONF_PREFIX/nginx.conf.default' - test -d '\$(DESTDIR)`dirname "$NGX_PID_PATH"`' \ + test -d '\$(DESTDIR)`dirname "$NGX_PID_PATH"`' \\ || mkdir -p '\$(DESTDIR)`dirname "$NGX_PID_PATH"`' - test -d '\$(DESTDIR)`dirname "$NGX_HTTP_LOG_PATH"`' || \ - mkdir -p '\$(DESTDIR)`dirname "$NGX_HTTP_LOG_PATH"`' + test -d '\$(DESTDIR)`dirname "$NGX_HTTP_LOG_PATH"`' \\ + || mkdir -p '\$(DESTDIR)`dirname "$NGX_HTTP_LOG_PATH"`' - test -d '\$(DESTDIR)$NGX_PREFIX/html' \ + test -d '\$(DESTDIR)$NGX_PREFIX/html' \\ || cp -R $NGX_HTML '\$(DESTDIR)$NGX_PREFIX' END @@ -162,24 +162,38 @@ if test -n "$NGX_ERROR_LOG_PATH"; then cat << END >> $NGX_MAKEFILE - test -d '\$(DESTDIR)`dirname "$NGX_ERROR_LOG_PATH"`' || \ - mkdir -p '\$(DESTDIR)`dirname "$NGX_ERROR_LOG_PATH"`' + test -d '\$(DESTDIR)`dirname "$NGX_ERROR_LOG_PATH"`' \\ + || mkdir -p '\$(DESTDIR)`dirname "$NGX_ERROR_LOG_PATH"`' END fi -if test -n "$NGX_MODULES"; then +if test -n "$DYNAMIC_MODULES"; then cat << END >> $NGX_MAKEFILE - test -d '\$(DESTDIR)$NGX_MODULES_PATH' \ + test -d '\$(DESTDIR)$NGX_MODULES_PATH' \\ || mkdir -p '\$(DESTDIR)$NGX_MODULES_PATH' - cp $NGX_MODULES '\$(DESTDIR)$NGX_MODULES_PATH' END fi +for ngx_module in $DYNAMIC_MODULES +do + ngx_module=$ngx_module$ngx_modext + + cat << END >> $NGX_MAKEFILE + + test ! -f '\$(DESTDIR)$NGX_MODULES_PATH/$ngx_module' \\ + || mv '\$(DESTDIR)$NGX_MODULES_PATH/$ngx_module' \\ + '\$(DESTDIR)$NGX_MODULES_PATH/$ngx_module.old' + cp $NGX_OBJS/$ngx_module '\$(DESTDIR)$NGX_MODULES_PATH/$ngx_module' +END + +done + + # create Makefile cat << END >> Makefile @@ -190,6 +204,9 @@ install: \$(MAKE) -f $NGX_MAKEFILE install +modules: + \$(MAKE) -f $NGX_MAKEFILE modules + upgrade: $NGX_SBIN_PATH -t | ||
[+] | Changed | nginx-1.9.13.tar.gz/auto/lib/conf ^ |
@@ -66,7 +66,7 @@ . auto/lib/libgd/conf fi -if [ $USE_PERL = YES ]; then +if [ $USE_PERL != NO ]; then . auto/lib/perl/conf fi | ||
[+] | Changed | nginx-1.9.13.tar.gz/auto/lib/make ^ |
@@ -27,6 +27,6 @@ . auto/lib/libatomic/make fi -if [ $USE_PERL = YES ]; then +if [ $USE_PERL != NO ]; then . auto/lib/perl/make fi | ||
[+] | Changed | nginx-1.9.13.tar.gz/auto/lib/perl/conf ^ |
@@ -60,8 +60,11 @@ | sed -e 's/-arch i386//' -e 's/-arch x86_64//'` fi - CORE_LINK="$CORE_LINK $ngx_perl_ldopts" - LINK_DEPS="$LINK_DEPS $NGX_OBJS/$ngx_perl_module" + if [ $USE_PERL = YES ]; then + CORE_LINK="$CORE_LINK $ngx_perl_ldopts" + fi + + NGX_LIB_PERL="$ngx_perl_ldopts" if test -n "$NGX_PERL_MODULES"; then have=NGX_PERL_MODULES value="(u_char *) \"$NGX_PERL_MODULES\"" | ||
[+] | Changed | nginx-1.9.13.tar.gz/auto/lib/perl/make ^ |
@@ -8,7 +8,10 @@ cat << END >> $NGX_MAKEFILE -$NGX_OBJS/src/http/modules/perl/blib/arch/auto/nginx/nginx.$ngx_perl_dlext: \\ +$NGX_OBJS/src/http/modules/perl/ngx_http_perl_module.o: \\ + $NGX_OBJS/$ngx_perl_module + +$NGX_OBJS/$ngx_perl_module: \\ \$(CORE_DEPS) \$(HTTP_DEPS) \\ src/http/modules/perl/ngx_http_perl_module.h \\ $NGX_OBJS/src/http/modules/perl/Makefile | ||
[+] | Changed | nginx-1.9.13.tar.gz/auto/make ^ |
@@ -225,12 +225,12 @@ build: binary modules manpage -binary: $NGX_OBJS${ngx_dirsep}nginx${ngx_binext} +binary: $NGX_OBJS${ngx_dirsep}nginx$ngx_binext -$NGX_OBJS${ngx_dirsep}nginx${ngx_binext}: $ngx_deps$ngx_spacer - \$(LINK) ${ngx_long_start}${ngx_binout}$NGX_OBJS${ngx_dirsep}nginx$ngx_long_cont$ngx_objs$ngx_libs$ngx_link$ngx_main_link +$NGX_OBJS${ngx_dirsep}nginx$ngx_binext: $ngx_deps$ngx_spacer + \$(LINK) $ngx_long_start$ngx_binout$NGX_OBJS${ngx_dirsep}nginx$ngx_long_cont$ngx_objs$ngx_libs$ngx_link$ngx_main_link $ngx_rcc -${ngx_long_end} +$ngx_long_end modules: END @@ -281,7 +281,7 @@ ngx_cc="\$(CC) $ngx_compile_opt \$(CFLAGS) $ngx_use_pch \$(ALL_INCS)" else ngx_cc="\$(CC) $ngx_compile_opt \$(CFLAGS) \$(CORE_INCS) \$(HTTP_INCS)" - ngx_perl_cc="\$(CC) $ngx_compile_opt \$(NGX_PERL_CFLAGS) " + ngx_perl_cc="\$(CC) $ngx_compile_opt \$(NGX_PERL_CFLAGS)" ngx_perl_cc="$ngx_perl_cc \$(CORE_INCS) \$(HTTP_INCS)" fi @@ -437,9 +437,9 @@ # the addons config.make -if test -n "$NGX_ADDONS"; then +if test -n "$NGX_ADDONS$DYNAMIC_ADDONS"; then - for ngx_addon_dir in $NGX_ADDONS + for ngx_addon_dir in $NGX_ADDONS $DYNAMIC_ADDONS do if test -f $ngx_addon_dir/config.make; then . $ngx_addon_dir/config.make @@ -494,6 +494,8 @@ ngx_cc="\$(CC) $ngx_compile_opt $ngx_pic_opt \$(CFLAGS) $ngx_use_pch \$(ALL_INCS)" else ngx_cc="\$(CC) $ngx_compile_opt $ngx_pic_opt \$(CFLAGS) \$(ALL_INCS)" + ngx_perl_cc="\$(CC) $ngx_compile_opt $ngx_pic_opt \$(NGX_PERL_CFLAGS)" + ngx_perl_cc="$ngx_perl_cc \$(ALL_INCS)" fi ngx_obj_deps="\$(CORE_DEPS)" @@ -605,9 +607,7 @@ | sed -e "s/ *\([^ ][^ ]*\)/$ngx_long_regex_cont\1/g" \ -e "s/\//$ngx_regex_dirsep/g"` - ngx_obj=$NGX_OBJS${ngx_dirsep}${ngx_module}${ngx_modext} - - NGX_MODULES="$NGX_MODULES $ngx_obj" + ngx_obj=$NGX_OBJS$ngx_dirsep$ngx_module$ngx_modext if [ "$NGX_PLATFORM" = win32 ]; then ngx_module_libs="$CORE_LIBS $ngx_module_libs" @@ -639,15 +639,15 @@ END - for ngx_src in $ngx_module_srcs + for ngx_source in $ngx_module_srcs do - case "$ngx_src" in + case "$ngx_source" in src/*) - ngx_obj=`echo $ngx_src | sed -e "s/\//$ngx_regex_dirsep/g"` + ngx_obj=`echo $ngx_source | sed -e "s/\//$ngx_regex_dirsep/g"` ;; *) - ngx_obj="addon/`basename \`dirname $ngx_src\``" - ngx_obj=`echo $ngx_obj/\`basename $ngx_src\` \ + ngx_obj="addon/`basename \`dirname $ngx_source\``" + ngx_obj=`echo $ngx_obj/\`basename $ngx_source\` \ | sed -e "s/\//$ngx_regex_dirsep/g"` ;; esac @@ -658,14 +658,25 @@ -e "s#^\(.*\.\)c\\$#$ngx_objs_dir\1$ngx_objext#g" \ -e "s#^\(.*\.\)S\\$#$ngx_objs_dir\1$ngx_objext#g"` - ngx_src=`echo $ngx_src | sed -e "s/\//$ngx_regex_dirsep/g"` + ngx_src=`echo $ngx_source | sed -e "s/\//$ngx_regex_dirsep/g"` - cat << END >> $NGX_MAKEFILE + if [ $ngx_source = src/http/modules/perl/ngx_http_perl_module.c ]; then + + cat << END >> $NGX_MAKEFILE + +$ngx_obj: $ngx_obj_deps$ngx_cont$ngx_src + $ngx_perl_cc$ngx_tab$ngx_objout$ngx_obj$ngx_tab$ngx_src$NGX_AUX + +END + else + + cat << END >> $NGX_MAKEFILE $ngx_obj: $ngx_obj_deps$ngx_cont$ngx_src $ngx_cc$ngx_tab$ngx_objout$ngx_obj$ngx_tab$ngx_src$NGX_AUX END + fi done done | ||
[+] | Changed | nginx-1.9.13.tar.gz/auto/module ^ |
@@ -40,7 +40,7 @@ do case $lib in - LIBXSLT | LIBGD | GEOIP) + LIBXSLT | LIBGD | GEOIP | PERL) libs="$libs \$NGX_LIB_$lib" if eval [ "\$USE_${lib}" = NO ] ; then @@ -48,7 +48,7 @@ fi ;; - PCRE | OPENSSL | MD5 | SHA1 | ZLIB | PERL) + PCRE | OPENSSL | MD5 | SHA1 | ZLIB) eval USE_${lib}=YES ;; | ||
[+] | Changed | nginx-1.9.13.tar.gz/auto/modules ^ |
@@ -727,14 +727,12 @@ . auto/module fi -if [ $HTTP_PERL = YES ]; then - USE_PERL=YES - +if [ $HTTP_PERL != NO ]; then ngx_module_name=ngx_http_perl_module ngx_module_incs=src/http/modules/perl ngx_module_deps=src/http/modules/perl/ngx_http_perl_module.h ngx_module_srcs=src/http/modules/perl/ngx_http_perl_module.c - ngx_module_libs= + ngx_module_libs=PERL ngx_module_link=$HTTP_PERL . auto/module | ||
[+] | Changed | nginx-1.9.13.tar.gz/auto/options ^ |
@@ -271,6 +271,7 @@ --without-http_upstream_zone_module) HTTP_UPSTREAM_ZONE=NO ;; --with-http_perl_module) HTTP_PERL=YES ;; + --with-http_perl_module=dynamic) HTTP_PERL=DYNAMIC ;; --with-perl_modules_path=*) NGX_PERL_MODULES="$value" ;; --with-perl=*) NGX_PERL="$value" ;; @@ -452,6 +453,7 @@ disable ngx_http_upstream_zone_module --with-http_perl_module enable ngx_http_perl_module + --with-http_perl_module=dynamic enable dynamic ngx_http_perl_module --with-perl_modules_path=PATH set Perl modules path --with-perl=PATH set perl binary pathname @@ -477,8 +479,8 @@ --without-mail_imap_module disable ngx_mail_imap_module --without-mail_smtp_module disable ngx_mail_smtp_module - --with-stream enable TCP proxy module - --with-stream=dynamic enable dynamic TCP proxy module + --with-stream enable TCP/UDP proxy module + --with-stream=dynamic enable dynamic TCP/UDP proxy module --with-stream_ssl_module enable ngx_stream_ssl_module --without-stream_limit_conn_module disable ngx_stream_limit_conn_module --without-stream_access_module disable ngx_stream_access_module | ||
[+] | Changed | nginx-1.9.13.tar.gz/auto/sources ^ |
@@ -165,6 +165,7 @@ src/os/unix/ngx_udp_recv.c \ src/os/unix/ngx_send.c \ src/os/unix/ngx_writev_chain.c \ + src/os/unix/ngx_udp_send.c \ src/os/unix/ngx_channel.c \ src/os/unix/ngx_shmem.c \ src/os/unix/ngx_process.c \ | ||
[+] | Changed | nginx-1.9.13.tar.gz/auto/unix ^ |
@@ -329,6 +329,45 @@ . auto/feature +# BSD way to get IPv4 datagram destination address + +ngx_feature="IP_RECVDSTADDR" +ngx_feature_name="NGX_HAVE_IP_RECVDSTADDR" +ngx_feature_run=no +ngx_feature_incs="#include <sys/socket.h> + #include <netinet/in.h>" +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="setsockopt(0, IPPROTO_IP, IP_RECVDSTADDR, NULL, 0)" +. auto/feature + + +# Linux way to get IPv4 datagram destination address + +ngx_feature="IP_PKTINFO" +ngx_feature_name="NGX_HAVE_IP_PKTINFO" +ngx_feature_run=no +ngx_feature_incs="#include <sys/socket.h> + #include <netinet/in.h>" +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="setsockopt(0, IPPROTO_IP, IP_PKTINFO, NULL, 0)" +. auto/feature + + +# RFC 3542 way to get IPv6 datagram destination address + +ngx_feature="IPV6_RECVPKTINFO" +ngx_feature_name="NGX_HAVE_IPV6_RECVPKTINFO" +ngx_feature_run=no +ngx_feature_incs="#include <sys/socket.h> + #include <netinet/in.h>" +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="setsockopt(0, IPPROTO_IPV6, IPV6_RECVPKTINFO, NULL, 0)" +. auto/feature + + ngx_feature="TCP_DEFER_ACCEPT" ngx_feature_name="NGX_HAVE_DEFERRED_ACCEPT" ngx_feature_run=no | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/core/nginx.c ^ |
@@ -10,7 +10,7 @@ #include <nginx.h> -static void ngx_show_version_info(); +static void ngx_show_version_info(void); static ngx_int_t ngx_add_inherited_sockets(ngx_cycle_t *cycle); static ngx_int_t ngx_get_options(int argc, char *const *argv); static ngx_int_t ngx_process_options(ngx_cycle_t *cycle); @@ -372,7 +372,7 @@ static void -ngx_show_version_info() +ngx_show_version_info(void) { ngx_write_stderr("nginx version: " NGINX_VER_BUILD NGX_LINEFEED); | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/core/nginx.h ^ |
@@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1009012 -#define NGINX_VERSION "1.9.12" +#define nginx_version 1009013 +#define NGINX_VERSION "1.9.13" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/core/ngx_connection.c ^ |
@@ -210,6 +210,18 @@ olen = sizeof(int); + if (getsockopt(ls[i].fd, SOL_SOCKET, SO_TYPE, (void *) &ls[i].type, + &olen) + == -1) + { + ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno, + "getsockopt(SO_TYPE) %V failed", &ls[i].addr_text); + ls[i].ignore = 1; + continue; + } + + olen = sizeof(int); + if (getsockopt(ls[i].fd, SOL_SOCKET, SO_RCVBUF, (void *) &ls[i].rcvbuf, &olen) == -1) @@ -274,6 +286,10 @@ #endif + if (ls[i].type != SOCK_STREAM) { + continue; + } + #if (NGX_HAVE_TCP_FASTOPEN) olen = sizeof(int); @@ -566,6 +582,11 @@ } #endif + if (ls[i].type != SOCK_STREAM) { + ls[i].fd = s; + continue; + } + if (listen(s, ls[i].backlog) == -1) { err = ngx_socket_errno; @@ -865,6 +886,67 @@ #endif #endif /* NGX_HAVE_DEFERRED_ACCEPT */ + +#if (NGX_HAVE_IP_RECVDSTADDR) + + if (ls[i].wildcard + && ls[i].type == SOCK_DGRAM + && ls[i].sockaddr->sa_family == AF_INET) + { + value = 1; + + if (setsockopt(ls[i].fd, IPPROTO_IP, IP_RECVDSTADDR, + (const void *) &value, sizeof(int)) + == -1) + { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, + "setsockopt(IP_RECVDSTADDR) " + "for %V failed, ignored", + &ls[i].addr_text); + } + } + +#elif (NGX_HAVE_IP_PKTINFO) + + if (ls[i].wildcard + && ls[i].type == SOCK_DGRAM + && ls[i].sockaddr->sa_family == AF_INET) + { + value = 1; + + if (setsockopt(ls[i].fd, IPPROTO_IP, IP_PKTINFO, + (const void *) &value, sizeof(int)) + == -1) + { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, + "setsockopt(IP_PKTINFO) " + "for %V failed, ignored", + &ls[i].addr_text); + } + } + +#endif + +#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO) + + if (ls[i].wildcard + && ls[i].type == SOCK_DGRAM + && ls[i].sockaddr->sa_family == AF_INET6) + { + value = 1; + + if (setsockopt(ls[i].fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, + (const void *) &value, sizeof(int)) + == -1) + { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno, + "setsockopt(IPV6_RECVPKTINFO) " + "for %V failed, ignored", + &ls[i].addr_text); + } + } + +#endif } return; @@ -978,7 +1060,7 @@ ngx_cycle->free_connections = c->data; ngx_cycle->free_connection_n--; - if (ngx_cycle->files) { + if (ngx_cycle->files && ngx_cycle->files[s] == NULL) { ngx_cycle->files[s] = c; } @@ -1019,7 +1101,7 @@ ngx_cycle->free_connections = c; ngx_cycle->free_connection_n++; - if (ngx_cycle->files) { + if (ngx_cycle->files && ngx_cycle->files[c->fd] == c) { ngx_cycle->files[c->fd] = NULL; } } @@ -1045,16 +1127,18 @@ ngx_del_timer(c->write); } - if (ngx_del_conn) { - ngx_del_conn(c, NGX_CLOSE_EVENT); + if (!c->shared) { + if (ngx_del_conn) { + ngx_del_conn(c, NGX_CLOSE_EVENT); - } else { - if (c->read->active || c->read->disabled) { - ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT); - } + } else { + if (c->read->active || c->read->disabled) { + ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT); + } - if (c->write->active || c->write->disabled) { - ngx_del_event(c->write, NGX_WRITE_EVENT, NGX_CLOSE_EVENT); + if (c->write->active || c->write->disabled) { + ngx_del_event(c->write, NGX_WRITE_EVENT, NGX_CLOSE_EVENT); + } } } @@ -1078,6 +1162,10 @@ fd = c->fd; c->fd = (ngx_socket_t) -1; + if (c->shared) { + return; + } + if (ngx_close_socket(fd) == -1) { err = ngx_socket_errno; | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/core/ngx_connection.h ^ |
@@ -64,6 +64,7 @@ unsigned nonblocking:1; unsigned shared:1; /* shared between threads or processes */ unsigned addr_ntop:1; + unsigned wildcard:1; #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) unsigned ipv6only:1; @@ -141,6 +142,8 @@ ngx_pool_t *pool; + int type; + struct sockaddr *sockaddr; socklen_t socklen; ngx_str_t addr_text; @@ -174,6 +177,7 @@ unsigned idle:1; unsigned reusable:1; unsigned close:1; + unsigned shared:1; unsigned sendfile:1; unsigned sndlowat:1; | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/core/ngx_cycle.c ^ |
@@ -512,6 +512,10 @@ continue; } + if (ls[i].type != nls[n].type) { + continue; + } + if (ngx_cmp_sockaddr(nls[n].sockaddr, nls[n].socklen, ls[i].sockaddr, ls[i].socklen, 1) == NGX_OK) | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/core/ngx_file.c ^ |
@@ -124,6 +124,15 @@ } } +#if (NGX_THREADS && NGX_HAVE_PWRITEV) + + if (tf->thread_write) { + return ngx_thread_write_chain_to_file(&tf->file, chain, tf->offset, + tf->pool); + } + +#endif + return ngx_write_chain_to_file(&tf->file, chain, tf->offset, tf->pool); } @@ -187,7 +196,7 @@ err = ngx_errno; - if (err == NGX_EEXIST) { + if (err == NGX_EEXIST_FILE) { n = (uint32_t) ngx_next_temp_number(1); continue; } @@ -683,7 +692,7 @@ #if (NGX_WIN32) - if (err == NGX_EEXIST) { + if (err == NGX_EEXIST || err == NGX_EEXIST_FILE) { err = ngx_win32_rename_file(src, to, ext->log); if (err == 0) { | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/core/ngx_file.h ^ |
@@ -27,6 +27,7 @@ ngx_int_t (*thread_handler)(ngx_thread_task_t *task, ngx_file_t *file); void *thread_ctx; + ngx_thread_task_t *thread_task; #endif #if (NGX_HAVE_FILE_AIO) @@ -77,6 +78,7 @@ unsigned log_level:8; unsigned persistent:1; unsigned clean:1; + unsigned thread_write:1; } ngx_temp_file_t; | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/core/ngx_inet.c ^ |
@@ -529,14 +529,16 @@ ngx_parse_url(ngx_pool_t *pool, ngx_url_t *u) { u_char *p; + size_t len; p = u->url.data; + len = u->url.len; - if (ngx_strncasecmp(p, (u_char *) "unix:", 5) == 0) { + if (len >= 5 && ngx_strncasecmp(p, (u_char *) "unix:", 5) == 0) { return ngx_parse_unix_domain_url(pool, u); } - if (p[0] == '[') { + if (len && p[0] == '[') { return ngx_parse_inet6_url(pool, u); } | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/core/ngx_module.c ^ |
@@ -23,11 +23,10 @@ ngx_int_t -ngx_preinit_modules() +ngx_preinit_modules(void) { ngx_uint_t i; - ngx_max_module = 0; for (i = 0; ngx_modules[i]; i++) { ngx_modules[i]->index = i; ngx_modules[i]->name = ngx_module_names[i]; | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/core/ngx_module.h ^ |
@@ -288,7 +288,7 @@ } ngx_core_module_t; -ngx_int_t ngx_preinit_modules(); +ngx_int_t ngx_preinit_modules(void); ngx_int_t ngx_cycle_modules(ngx_cycle_t *cycle); ngx_int_t ngx_init_modules(ngx_cycle_t *cycle); ngx_int_t ngx_count_modules(ngx_cycle_t *cycle, ngx_uint_t type); | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/core/ngx_output_chain.c ^ |
@@ -577,11 +577,15 @@ } else #endif #if (NGX_THREADS) - if (src->file->thread_handler) { - n = ngx_thread_read(&ctx->thread_task, src->file, dst->pos, - (size_t) size, src->file_pos, ctx->pool); + if (ctx->thread_handler) { + src->file->thread_task = ctx->thread_task; + src->file->thread_handler = ctx->thread_handler; + src->file->thread_ctx = ctx->filter_ctx; + + n = ngx_thread_read(src->file, dst->pos, (size_t) size, + src->file_pos, ctx->pool); if (n == NGX_AGAIN) { - ctx->aio = 1; + ctx->thread_task = src->file->thread_task; return NGX_AGAIN; } | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/core/ngx_palloc.c ^ |
@@ -9,6 +9,8 @@ #include <ngx_core.h> +static ngx_inline void *ngx_palloc_small(ngx_pool_t *pool, size_t size, + ngx_uint_t align); static void *ngx_palloc_block(ngx_pool_t *pool, size_t size); static void *ngx_palloc_large(ngx_pool_t *pool, size_t size); @@ -56,15 +58,6 @@ } } - for (l = pool->large; l; l = l->next) { - - ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0, "free: %p", l->alloc); - - if (l->alloc) { - ngx_free(l->alloc); - } - } - #if (NGX_DEBUG) /* @@ -72,6 +65,10 @@ * so we cannot use this log while free()ing the pool */ + for (l = pool->large; l; l = l->next) { + ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0, "free: %p", l->alloc); + } + for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) { ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, pool->log, 0, "free: %p, unused: %uz", p, p->d.end - p->d.last); @@ -83,6 +80,12 @@ #endif + for (l = pool->large; l; l = l->next) { + if (l->alloc) { + ngx_free(l->alloc); + } + } + for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) { ngx_free(p); @@ -119,60 +122,55 @@ void * ngx_palloc(ngx_pool_t *pool, size_t size) { - u_char *m; - ngx_pool_t *p; - +#if !(NGX_DEBUG_PALLOC) if (size <= pool->max) { + return ngx_palloc_small(pool, size, 1); + } +#endif - p = pool->current; - - do { - m = ngx_align_ptr(p->d.last, NGX_ALIGNMENT); - - if ((size_t) (p->d.end - m) >= size) { - p->d.last = m + size; - - return m; - } - - p = p->d.next; + return ngx_palloc_large(pool, size); +} - } while (p); - return ngx_palloc_block(pool, size); +void * +ngx_pnalloc(ngx_pool_t *pool, size_t size) +{ +#if !(NGX_DEBUG_PALLOC) + if (size <= pool->max) { + return ngx_palloc_small(pool, size, 0); } +#endif return ngx_palloc_large(pool, size); } -void * -ngx_pnalloc(ngx_pool_t *pool, size_t size) +static ngx_inline void * +ngx_palloc_small(ngx_pool_t *pool, size_t size, ngx_uint_t align) { u_char *m; ngx_pool_t *p; - if (size <= pool->max) { - - p = pool->current; + p = pool->current; - do { - m = p->d.last; + do { + m = p->d.last; - if ((size_t) (p->d.end - m) >= size) { - p->d.last = m + size; + if (align) { + m = ngx_align_ptr(m, NGX_ALIGNMENT); + } - return m; - } + if ((size_t) (p->d.end - m) >= size) { + p->d.last = m + size; - p = p->d.next; + return m; + } - } while (p); + p = p->d.next; - return ngx_palloc_block(pool, size); - } + } while (p); - return ngx_palloc_large(pool, size); + return ngx_palloc_block(pool, size); } @@ -237,7 +235,7 @@ } } - large = ngx_palloc(pool, sizeof(ngx_pool_large_t)); + large = ngx_palloc_small(pool, sizeof(ngx_pool_large_t), 1); if (large == NULL) { ngx_free(p); return NULL; @@ -262,7 +260,7 @@ return NULL; } - large = ngx_palloc(pool, sizeof(ngx_pool_large_t)); + large = ngx_palloc_small(pool, sizeof(ngx_pool_large_t), 1); if (large == NULL) { ngx_free(p); return NULL; | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/core/ngx_resolver.c ^ |
@@ -74,8 +74,10 @@ ngx_resolver_connection_t *rec, u_char *query, u_short qlen); static ngx_int_t ngx_resolver_create_name_query(ngx_resolver_t *r, ngx_resolver_node_t *rn, ngx_str_t *name); +static ngx_int_t ngx_resolver_create_srv_query(ngx_resolver_t *r, + ngx_resolver_node_t *rn, ngx_str_t *name); static ngx_int_t ngx_resolver_create_addr_query(ngx_resolver_t *r, - ngx_resolver_node_t *rn, ngx_addr_t *addr); + ngx_resolver_node_t *rn, ngx_resolver_addr_t *addr); static void ngx_resolver_resend_handler(ngx_event_t *ev); static time_t ngx_resolver_resend(ngx_resolver_t *r, ngx_rbtree_t *tree, ngx_queue_t *queue); @@ -88,10 +90,15 @@ static void ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t n, ngx_uint_t ident, ngx_uint_t code, ngx_uint_t qtype, ngx_uint_t nan, ngx_uint_t trunc, ngx_uint_t ans); +static void ngx_resolver_process_srv(ngx_resolver_t *r, u_char *buf, size_t n, + ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan, + ngx_uint_t trunc, ngx_uint_t ans); static void ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n, ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan); static ngx_resolver_node_t *ngx_resolver_lookup_name(ngx_resolver_t *r, ngx_str_t *name, uint32_t hash); +static ngx_resolver_node_t *ngx_resolver_lookup_srv(ngx_resolver_t *r, + ngx_str_t *name, uint32_t hash); static ngx_resolver_node_t *ngx_resolver_lookup_addr(ngx_resolver_t *r, in_addr_t addr); static void ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t *temp, @@ -105,9 +112,14 @@ static void ngx_resolver_free(ngx_resolver_t *r, void *p); static void ngx_resolver_free_locked(ngx_resolver_t *r, void *p); static void *ngx_resolver_dup(ngx_resolver_t *r, void *src, size_t size); -static ngx_addr_t *ngx_resolver_export(ngx_resolver_t *r, +static ngx_resolver_addr_t *ngx_resolver_export(ngx_resolver_t *r, ngx_resolver_node_t *rn, ngx_uint_t rotate); +static void ngx_resolver_report_srv(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx); static u_char *ngx_resolver_log_error(ngx_log_t *log, u_char *buf, size_t len); +static void ngx_resolver_resolve_srv_names(ngx_resolver_ctx_t *ctx, + ngx_resolver_node_t *rn); +static void ngx_resolver_srv_names_handler(ngx_resolver_ctx_t *ctx); +static ngx_int_t ngx_resolver_cmp_srvs(const void *one, const void *two); #if (NGX_HAVE_INET6) static void ngx_resolver_rbtree_insert_addr6_value(ngx_rbtree_node_t *temp, @@ -149,13 +161,18 @@ ngx_rbtree_init(&r->name_rbtree, &r->name_sentinel, ngx_resolver_rbtree_insert_value); + ngx_rbtree_init(&r->srv_rbtree, &r->srv_sentinel, + ngx_resolver_rbtree_insert_value); + ngx_rbtree_init(&r->addr_rbtree, &r->addr_sentinel, ngx_rbtree_insert_value); ngx_queue_init(&r->name_resend_queue); + ngx_queue_init(&r->srv_resend_queue); ngx_queue_init(&r->addr_resend_queue); ngx_queue_init(&r->name_expire_queue); + ngx_queue_init(&r->srv_expire_queue); ngx_queue_init(&r->addr_expire_queue); #if (NGX_HAVE_INET6) @@ -274,6 +291,8 @@ ngx_resolver_cleanup_tree(r, &r->name_rbtree); + ngx_resolver_cleanup_tree(r, &r->srv_rbtree); + ngx_resolver_cleanup_tree(r, &r->addr_rbtree); #if (NGX_HAVE_INET6) @@ -383,7 +402,9 @@ ngx_int_t ngx_resolve_name(ngx_resolver_ctx_t *ctx) { + size_t slen; ngx_int_t rc; + ngx_str_t name; ngx_resolver_t *r; r = ctx->resolver; @@ -400,9 +421,41 @@ return NGX_OK; } - /* lock name mutex */ + if (ctx->service.len) { + slen = ctx->service.len; + + if (ngx_strlchr(ctx->service.data, + ctx->service.data + ctx->service.len, '.') + == NULL) + { + slen += sizeof("_._tcp") - 1; + } + + name.len = slen + 1 + ctx->name.len; + + name.data = ngx_resolver_alloc(r, name.len); + if (name.data == NULL) { + return NGX_ERROR; + } + + if (slen == ctx->service.len) { + ngx_sprintf(name.data, "%V.%V", &ctx->service, &ctx->name); + + } else { + ngx_sprintf(name.data, "_%V._tcp.%V", &ctx->service, &ctx->name); + } + + /* lock name mutex */ + + rc = ngx_resolve_name_locked(r, ctx, &name); + + ngx_resolver_free(r, name.data); + + } else { + /* lock name mutex */ - rc = ngx_resolve_name_locked(r, ctx, &ctx->name); + rc = ngx_resolve_name_locked(r, ctx, &ctx->name); + } if (rc == NGX_OK) { return NGX_OK; @@ -429,6 +482,7 @@ void ngx_resolve_name_done(ngx_resolver_ctx_t *ctx) { + ngx_uint_t i; ngx_resolver_t *r; ngx_resolver_ctx_t *w, **p; ngx_resolver_node_t *rn; @@ -448,6 +502,23 @@ /* lock name mutex */ + if (ctx->nsrvs) { + for (i = 0; i < ctx->nsrvs; i++) { + if (ctx->srvs[i].ctx) { + ngx_resolve_name_done(ctx->srvs[i].ctx); + } + + if (ctx->srvs[i].addrs) { + ngx_resolver_free(r, ctx->srvs[i].addrs->sockaddr); + ngx_resolver_free(r, ctx->srvs[i].addrs); + } + + ngx_resolver_free(r, ctx->srvs[i].name.data); + } + + ngx_resolver_free(r, ctx->srvs); + } + if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) { rn = ctx->node; @@ -466,15 +537,20 @@ p = &w->next; w = w->next; } - } - ngx_log_error(NGX_LOG_ALERT, r->log, 0, - "could not cancel %V resolving", &ctx->name); + ngx_log_error(NGX_LOG_ALERT, r->log, 0, + "could not cancel %V resolving", &ctx->name); + } } done: - ngx_resolver_expire(r, &r->name_rbtree, &r->name_expire_queue); + if (ctx->service.len) { + ngx_resolver_expire(r, &r->srv_rbtree, &r->srv_expire_queue); + + } else { + ngx_resolver_expire(r, &r->name_rbtree, &r->name_expire_queue); + } /* unlock name mutex */ @@ -501,16 +577,31 @@ uint32_t hash; ngx_int_t rc; ngx_str_t cname; - ngx_uint_t naddrs; - ngx_addr_t *addrs; + ngx_uint_t i, naddrs; + ngx_queue_t *resend_queue, *expire_queue; + ngx_rbtree_t *tree; ngx_resolver_ctx_t *next, *last; + ngx_resolver_addr_t *addrs; ngx_resolver_node_t *rn; ngx_strlow(name->data, name->data, name->len); hash = ngx_crc32_short(name->data, name->len); - rn = ngx_resolver_lookup_name(r, name, hash); + if (ctx->service.len) { + rn = ngx_resolver_lookup_srv(r, name, hash); + + tree = &r->srv_rbtree; + resend_queue = &r->srv_resend_queue; + expire_queue = &r->srv_expire_queue; + + } else { + rn = ngx_resolver_lookup_name(r, name, hash); + + tree = &r->name_rbtree; + resend_queue = &r->name_resend_queue; + expire_queue = &r->name_expire_queue; + } if (rn) { @@ -525,7 +616,7 @@ rn->expire = ngx_time() + r->expire; - ngx_queue_insert_head(&r->name_expire_queue, &rn->queue); + ngx_queue_insert_head(expire_queue, &rn->queue); naddrs = (rn->naddrs == (u_short) -1) ? 0 : rn->naddrs; #if (NGX_HAVE_INET6) @@ -551,6 +642,7 @@ do { ctx->state = NGX_OK; + ctx->valid = rn->valid; ctx->naddrs = naddrs; if (addrs == NULL) { @@ -580,6 +672,23 @@ return NGX_OK; } + if (rn->nsrvs) { + last->next = rn->waiting; + rn->waiting = NULL; + + /* unlock name mutex */ + + do { + next = ctx->next; + + ngx_resolver_resolve_srv_names(ctx, rn); + + ctx = next; + } while (ctx); + + return NGX_OK; + } + /* NGX_RESOLVE_CNAME */ if (ctx->recursion++ < NGX_RESOLVER_MAX_RECURSION) { @@ -597,6 +706,7 @@ do { ctx->state = NGX_RESOLVE_NXDOMAIN; + ctx->valid = ngx_time() + (r->valid ? r->valid : 10); next = ctx->next; ctx->handler(ctx); @@ -609,7 +719,7 @@ if (rn->waiting) { - if (ctx->event == NULL) { + if (ctx->event == NULL && ctx->timeout) { ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t)); if (ctx->event == NULL) { return NGX_ERROR; @@ -661,6 +771,16 @@ } #endif + if (rn->nsrvs) { + for (i = 0; i < rn->nsrvs; i++) { + if (rn->u.srvs[i].name.data) { + ngx_resolver_free_locked(r, rn->u.srvs[i].name.data); + } + } + + ngx_resolver_free_locked(r, rn->u.srvs); + } + /* unlock alloc mutex */ } else { @@ -683,17 +803,22 @@ rn->query6 = NULL; #endif - ngx_rbtree_insert(&r->name_rbtree, &rn->node); + ngx_rbtree_insert(tree, &rn->node); } - rc = ngx_resolver_create_name_query(r, rn, name); + if (ctx->service.len) { + rc = ngx_resolver_create_srv_query(r, rn, name); + + } else { + rc = ngx_resolver_create_name_query(r, rn, name); + } if (rc == NGX_ERROR) { goto failed; } if (rc == NGX_DECLINED) { - ngx_rbtree_delete(&r->name_rbtree, &rn->node); + ngx_rbtree_delete(tree, &rn->node); ngx_resolver_free(r, rn->query); ngx_resolver_free(r, rn->name); @@ -722,12 +847,13 @@ rn->naddrs6 = r->ipv6 ? (u_short) -1 : 0; rn->tcp6 = 0; #endif + rn->nsrvs = 0; if (ngx_resolver_send_query(r, rn) != NGX_OK) { goto failed; } - if (ctx->event == NULL) { + if (ctx->event == NULL && ctx->timeout) { ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t)); if (ctx->event == NULL) { goto failed; @@ -741,13 +867,13 @@ ngx_add_timer(ctx->event, ctx->timeout); } - if (ngx_queue_empty(&r->name_resend_queue)) { + if (ngx_queue_empty(resend_queue)) { ngx_add_timer(r->event, (ngx_msec_t) (r->resend_timeout * 1000)); } rn->expire = ngx_time() + r->resend_timeout; - ngx_queue_insert_head(&r->name_resend_queue, &rn->queue); + ngx_queue_insert_head(resend_queue, &rn->queue); rn->code = 0; rn->cnlen = 0; @@ -766,7 +892,7 @@ failed: - ngx_rbtree_delete(&r->name_rbtree, &rn->node); + ngx_rbtree_delete(tree, &rn->node); if (rn->query) { ngx_resolver_free(r, rn->query); @@ -859,6 +985,7 @@ /* unlock addr mutex */ ctx->state = NGX_OK; + ctx->valid = rn->valid; ctx->handler(ctx); @@ -869,17 +996,19 @@ if (rn->waiting) { - ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t)); - if (ctx->event == NULL) { - return NGX_ERROR; - } + if (ctx->event == NULL && ctx->timeout) { + ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t)); + if (ctx->event == NULL) { + return NGX_ERROR; + } - ctx->event->handler = ngx_resolver_timeout_handler; - ctx->event->data = ctx; - ctx->event->log = r->log; - ctx->ident = -1; + ctx->event->handler = ngx_resolver_timeout_handler; + ctx->event->data = ctx; + ctx->event->log = r->log; + ctx->ident = -1; - ngx_add_timer(ctx->event, ctx->timeout); + ngx_add_timer(ctx->event, ctx->timeout); + } ctx->next = rn->waiting; rn->waiting = ctx; @@ -941,22 +1070,25 @@ rn->naddrs6 = (u_short) -1; rn->tcp6 = 0; #endif + rn->nsrvs = 0; if (ngx_resolver_send_query(r, rn) != NGX_OK) { goto failed; } - ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t)); - if (ctx->event == NULL) { - goto failed; - } + if (ctx->event == NULL && ctx->timeout) { + ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t)); + if (ctx->event == NULL) { + goto failed; + } - ctx->event->handler = ngx_resolver_timeout_handler; - ctx->event->data = ctx; - ctx->event->log = r->log; - ctx->ident = -1; + ctx->event->handler = ngx_resolver_timeout_handler; + ctx->event->data = ctx; + ctx->event->log = r->log; + ctx->ident = -1; - ngx_add_timer(ctx->event, ctx->timeout); + ngx_add_timer(ctx->event, ctx->timeout); + } if (ngx_queue_empty(resend_queue)) { ngx_add_timer(r->event, (ngx_msec_t) (r->resend_timeout * 1000)); @@ -1294,7 +1426,7 @@ static void ngx_resolver_resend_handler(ngx_event_t *ev) { - time_t timer, atimer, ntimer; + time_t timer, atimer, stimer, ntimer; #if (NGX_HAVE_INET6) time_t a6timer; #endif @@ -1309,6 +1441,8 @@ ntimer = ngx_resolver_resend(r, &r->name_rbtree, &r->name_resend_queue); + stimer = ngx_resolver_resend(r, &r->srv_rbtree, &r->srv_resend_queue); + /* unlock name mutex */ /* lock addr mutex */ @@ -1336,6 +1470,13 @@ timer = ngx_min(timer, atimer); } + if (timer == 0) { + timer = stimer; + + } else if (stimer) { + timer = ngx_min(timer, stimer); + } + #if (NGX_HAVE_INET6) if (timer == 0) { @@ -1696,6 +1837,13 @@ break; + case NGX_RESOLVE_SRV: + + ngx_resolver_process_srv(r, buf, n, ident, code, nan, trunc, + i + sizeof(ngx_resolver_qs_t)); + + break; + case NGX_RESOLVE_PTR: ngx_resolver_process_ptr(r, buf, n, ident, code, nan); @@ -1749,7 +1897,6 @@ uint32_t hash; in_addr_t *addr; ngx_str_t name; - ngx_addr_t *addrs; ngx_uint_t type, class, qident, naddrs, a, i, j, start; #if (NGX_HAVE_INET6) struct in6_addr *addr6; @@ -1757,6 +1904,7 @@ ngx_resolver_an_t *an; ngx_resolver_ctx_t *ctx, *next; ngx_resolver_node_t *rn; + ngx_resolver_addr_t *addrs; ngx_resolver_connection_t *rec; if (ngx_resolver_copy(r, &name, buf, @@ -1948,6 +2096,7 @@ while (next) { ctx = next; ctx->state = code; + ctx->valid = ngx_time() + (r->valid ? r->valid : 10); next = ctx->next; ctx->handler(ctx); @@ -2262,6 +2411,7 @@ while (next) { ctx = next; ctx->state = NGX_OK; + ctx->valid = rn->valid; ctx->naddrs = naddrs; if (addrs == NULL) { @@ -2391,26 +2541,22 @@ static void -ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n, - ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan) +ngx_resolver_process_srv(ngx_resolver_t *r, u_char *buf, size_t n, + ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan, + ngx_uint_t trunc, ngx_uint_t ans) { - char *err; - size_t len; - in_addr_t addr; - int32_t ttl; - ngx_int_t octet; - ngx_str_t name; - ngx_uint_t mask, type, class, qident, a, i, start; - ngx_queue_t *expire_queue; - ngx_rbtree_t *tree; - ngx_resolver_an_t *an; - ngx_resolver_ctx_t *ctx, *next; - ngx_resolver_node_t *rn; -#if (NGX_HAVE_INET6) - uint32_t hash; - ngx_int_t digit; - struct in6_addr addr6; -#endif + char *err; + u_char *cname; + size_t len; + int32_t ttl; + uint32_t hash; + ngx_str_t name; + ngx_uint_t type, qident, class, start, nsrvs, a, i, j; + ngx_resolver_an_t *an; + ngx_resolver_ctx_t *ctx, *next; + ngx_resolver_srv_t *srvs; + ngx_resolver_node_t *rn; + ngx_resolver_connection_t *rec; if (ngx_resolver_copy(r, &name, buf, buf + sizeof(ngx_resolver_hdr_t), buf + n) @@ -2421,109 +2567,62 @@ ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver qs:%V", &name); - /* AF_INET */ - - addr = 0; - i = sizeof(ngx_resolver_hdr_t); - - for (mask = 0; mask < 32; mask += 8) { - len = buf[i++]; + hash = ngx_crc32_short(name.data, name.len); - octet = ngx_atoi(&buf[i], len); - if (octet == NGX_ERROR || octet > 255) { - goto invalid_in_addr_arpa; - } + rn = ngx_resolver_lookup_srv(r, &name, hash); - addr += octet << mask; - i += len; + if (rn == NULL || rn->query == NULL) { + ngx_log_error(r->log_level, r->log, 0, + "unexpected response for %V", &name); + ngx_resolver_free(r, name.data); + goto failed; } - if (ngx_strcasecmp(&buf[i], (u_char *) "\7in-addr\4arpa") == 0) { - i += sizeof("\7in-addr\4arpa"); - - /* lock addr mutex */ - - rn = ngx_resolver_lookup_addr(r, addr); - - tree = &r->addr_rbtree; - expire_queue = &r->addr_expire_queue; - - goto valid; + if (trunc && rn->tcp) { + ngx_resolver_free(r, name.data); + goto failed; } -invalid_in_addr_arpa: - -#if (NGX_HAVE_INET6) - - i = sizeof(ngx_resolver_hdr_t); + qident = (rn->query[0] << 8) + rn->query[1]; - for (octet = 15; octet >= 0; octet--) { - if (buf[i++] != '\1') { - goto invalid_ip6_arpa; - } + if (ident != qident) { + ngx_log_error(r->log_level, r->log, 0, + "wrong ident %ui response for %V, expect %ui", + ident, &name, qident); + ngx_resolver_free(r, name.data); + goto failed; + } - digit = ngx_hextoi(&buf[i++], 1); - if (digit == NGX_ERROR) { - goto invalid_ip6_arpa; - } + ngx_resolver_free(r, name.data); - addr6.s6_addr[octet] = (u_char) digit; + if (trunc) { - if (buf[i++] != '\1') { - goto invalid_ip6_arpa; - } + ngx_queue_remove(&rn->queue); - digit = ngx_hextoi(&buf[i++], 1); - if (digit == NGX_ERROR) { - goto invalid_ip6_arpa; + if (rn->waiting == NULL) { + ngx_rbtree_delete(&r->srv_rbtree, &rn->node); + ngx_resolver_free_node(r, rn); + return; } - addr6.s6_addr[octet] += (u_char) (digit * 16); - } - - if (ngx_strcasecmp(&buf[i], (u_char *) "\3ip6\4arpa") == 0) { - i += sizeof("\3ip6\4arpa"); - - /* lock addr mutex */ - - hash = ngx_crc32_short(addr6.s6_addr, 16); - rn = ngx_resolver_lookup_addr6(r, &addr6, hash); - - tree = &r->addr6_rbtree; - expire_queue = &r->addr6_expire_queue; + rec = r->connections.elts; + rec = &rec[rn->last_connection]; - goto valid; - } + rn->tcp = 1; -invalid_ip6_arpa: -#endif + (void) ngx_resolver_send_tcp_query(r, rec, rn->query, rn->qlen); - ngx_log_error(r->log_level, r->log, 0, - "invalid in-addr.arpa or ip6.arpa name in DNS response"); - ngx_resolver_free(r, name.data); - return; + rn->expire = ngx_time() + r->resend_timeout; -valid: + ngx_queue_insert_head(&r->srv_resend_queue, &rn->queue); - if (rn == NULL || rn->query == NULL) { - ngx_log_error(r->log_level, r->log, 0, - "unexpected response for %V", &name); - ngx_resolver_free(r, name.data); - goto failed; + return; } - qident = (rn->query[0] << 8) + rn->query[1]; - - if (ident != qident) { - ngx_log_error(r->log_level, r->log, 0, - "wrong ident %ui response for %V, expect %ui", - ident, &name, qident); - ngx_resolver_free(r, name.data); - goto failed; + if (code == 0 && rn->code) { + code = rn->code; } - ngx_resolver_free(r, name.data); - if (code == 0 && nan == 0) { code = NGX_RESOLVE_NXDOMAIN; } @@ -2534,13 +2633,12 @@ ngx_queue_remove(&rn->queue); - ngx_rbtree_delete(tree, &rn->node); - - /* unlock addr mutex */ + ngx_rbtree_delete(&r->srv_rbtree, &rn->node); while (next) { ctx = next; ctx->state = code; + ctx->valid = ngx_time() + (r->valid ? r->valid : 10); next = ctx->next; ctx->handler(ctx); @@ -2551,7 +2649,9 @@ return; } - i += sizeof(ngx_resolver_qs_t); + i = ans; + nsrvs = 0; + cname = NULL; for (a = 0; a < nan; a++) { @@ -2577,7 +2677,7 @@ test_length: if (i - start < 2) { - err = "invalid name in DNS response"; + err = "invalid name DNS response"; goto invalid; } @@ -2605,8 +2705,589 @@ ttl = 0; } - ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0, - "resolver qt:%ui cl:%ui len:%uz", + rn->ttl = ngx_min(rn->ttl, (uint32_t) ttl); + + i += sizeof(ngx_resolver_an_t); + + switch (type) { + + case NGX_RESOLVE_SRV: + + if (i + 6 > n) { + goto short_response; + } + + if (ngx_resolver_copy(r, NULL, buf, &buf[i + 6], buf + n) + != NGX_OK) + { + goto failed; + } + + nsrvs++; + + break; + + case NGX_RESOLVE_CNAME: + + cname = &buf[i]; + + break; + + case NGX_RESOLVE_DNAME: + + break; + + default: + + ngx_log_error(r->log_level, r->log, 0, + "unexpected RR type %ui", type); + } + + i += len; + } + + ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0, + "resolver nsrvs:%ui cname:%p ttl:%uD", + nsrvs, cname, rn->ttl); + + if (nsrvs) { + + srvs = ngx_resolver_calloc(r, nsrvs * sizeof(ngx_resolver_srv_t)); + if (srvs == NULL) { + goto failed; + } + + rn->u.srvs = srvs; + rn->nsrvs = (u_short) nsrvs; + + j = 0; + i = ans; + + for (a = 0; a < nan; a++) { + + for ( ;; ) { + + if (buf[i] & 0xc0) { + i += 2; + break; + } + + if (buf[i] == 0) { + i++; + break; + } + + i += 1 + buf[i]; + } + + an = (ngx_resolver_an_t *) &buf[i]; + + type = (an->type_hi << 8) + an->type_lo; + len = (an->len_hi << 8) + an->len_lo; + + i += sizeof(ngx_resolver_an_t); + + if (type == NGX_RESOLVE_SRV) { + + srvs[j].priority = (buf[i] << 8) + buf[i + 1]; + srvs[j].weight = (buf[i + 2] << 8) + buf[i + 3]; + + if (srvs[j].weight == 0) { + srvs[j].weight = 1; + } + + srvs[j].port = (buf[i + 4] << 8) + buf[i + 5]; + + if (ngx_resolver_copy(r, &srvs[j].name, buf, &buf[i + 6], + buf + n) + != NGX_OK) + { + goto failed; + } + + j++; + } + + i += len; + } + + ngx_sort(srvs, nsrvs, sizeof(ngx_resolver_srv_t), + ngx_resolver_cmp_srvs); + + ngx_resolver_free(r, rn->query); + rn->query = NULL; + + ngx_queue_remove(&rn->queue); + + rn->valid = ngx_time() + (r->valid ? r->valid : (time_t) rn->ttl); + rn->expire = ngx_time() + r->expire; + + ngx_queue_insert_head(&r->srv_expire_queue, &rn->queue); + + next = rn->waiting; + rn->waiting = NULL; + + while (next) { + ctx = next; + next = ctx->next; + + ngx_resolver_resolve_srv_names(ctx, rn); + } + + return; + } + + rn->nsrvs = 0; + + if (cname) { + + /* CNAME only */ + + if (ngx_resolver_copy(r, &name, buf, cname, buf + n) != NGX_OK) { + goto failed; + } + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, + "resolver cname:\"%V\"", &name); + + ngx_queue_remove(&rn->queue); + + rn->cnlen = (u_short) name.len; + rn->u.cname = name.data; + + rn->valid = ngx_time() + (r->valid ? r->valid : (time_t) rn->ttl); + rn->expire = ngx_time() + r->expire; + + ngx_queue_insert_head(&r->srv_expire_queue, &rn->queue); + + ngx_resolver_free(r, rn->query); + rn->query = NULL; +#if (NGX_HAVE_INET6) + rn->query6 = NULL; +#endif + + ctx = rn->waiting; + rn->waiting = NULL; + + if (ctx) { + + if (ctx->recursion++ >= NGX_RESOLVER_MAX_RECURSION) { + + /* unlock name mutex */ + + do { + ctx->state = NGX_RESOLVE_NXDOMAIN; + next = ctx->next; + + ctx->handler(ctx); + + ctx = next; + } while (ctx); + + return; + } + + for (next = ctx; next; next = next->next) { + next->node = NULL; + } + + (void) ngx_resolve_name_locked(r, ctx, &name); + } + + /* unlock name mutex */ + + return; + } + + ngx_log_error(r->log_level, r->log, 0, "no SRV type in DNS response"); + + return; + +short_response: + + err = "short DNS response"; + +invalid: + + /* unlock name mutex */ + + ngx_log_error(r->log_level, r->log, 0, err); + + return; + +failed: + + /* unlock name mutex */ + + return; +} + + +static void +ngx_resolver_resolve_srv_names(ngx_resolver_ctx_t *ctx, ngx_resolver_node_t *rn) +{ + ngx_uint_t i; + ngx_resolver_t *r; + ngx_resolver_ctx_t *cctx; + ngx_resolver_srv_name_t *srvs; + + r = ctx->resolver; + + ctx->node = NULL; + ctx->state = NGX_OK; + ctx->valid = rn->valid; + ctx->count = rn->nsrvs; + + srvs = ngx_resolver_calloc(r, rn->nsrvs * sizeof(ngx_resolver_srv_name_t)); + if (srvs == NULL) { + goto failed; + } + + ctx->srvs = srvs; + ctx->nsrvs = rn->nsrvs; + + for (i = 0; i < rn->nsrvs; i++) { + srvs[i].name.data = ngx_resolver_alloc(r, rn->u.srvs[i].name.len); + if (srvs[i].name.data == NULL) { + goto failed; + } + + srvs[i].name.len = rn->u.srvs[i].name.len; + ngx_memcpy(srvs[i].name.data, rn->u.srvs[i].name.data, + srvs[i].name.len); + + cctx = ngx_resolve_start(r, NULL); + if (cctx == NULL) { + goto failed; + } + + cctx->name = srvs[i].name; + cctx->handler = ngx_resolver_srv_names_handler; + cctx->data = ctx; + cctx->srvs = &srvs[i]; + cctx->timeout = 0; + + srvs[i].priority = rn->u.srvs[i].priority; + srvs[i].weight = rn->u.srvs[i].weight; + srvs[i].port = rn->u.srvs[i].port; + srvs[i].ctx = cctx; + + if (ngx_resolve_name(cctx) == NGX_ERROR) { + srvs[i].ctx = NULL; + goto failed; + } + } + + return; + +failed: + + ctx->state = NGX_ERROR; + ctx->valid = ngx_time() + (r->valid ? r->valid : 10); + + ctx->handler(ctx); +} + + +static void +ngx_resolver_srv_names_handler(ngx_resolver_ctx_t *cctx) +{ + ngx_uint_t i; + u_char (*sockaddr)[NGX_SOCKADDRLEN]; + ngx_addr_t *addrs; + ngx_resolver_t *r; + struct sockaddr_in *sin; + ngx_resolver_ctx_t *ctx; + ngx_resolver_srv_name_t *srv; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; +#endif + + r = cctx->resolver; + ctx = cctx->data; + srv = cctx->srvs; + + ctx->count--; + + srv->ctx = NULL; + + if (cctx->naddrs) { + + ctx->valid = ngx_min(ctx->valid, cctx->valid); + + addrs = ngx_resolver_calloc(r, cctx->naddrs * sizeof(ngx_addr_t)); + if (addrs == NULL) { + ngx_resolve_name_done(cctx); + + ctx->state = NGX_ERROR; + ctx->valid = ngx_time() + (r->valid ? r->valid : 10); + + ctx->handler(ctx); + return; + } + + sockaddr = ngx_resolver_alloc(r, cctx->naddrs * NGX_SOCKADDRLEN); + if (sockaddr == NULL) { + ngx_resolver_free(r, addrs); + ngx_resolve_name_done(cctx); + + ctx->state = NGX_ERROR; + ctx->valid = ngx_time() + (r->valid ? r->valid : 10); + + ctx->handler(ctx); + return; + } + + for (i = 0; i < cctx->naddrs; i++) { + addrs[i].sockaddr = (struct sockaddr *) sockaddr[i]; + addrs[i].socklen = cctx->addrs[i].socklen; + + ngx_memcpy(sockaddr[i], cctx->addrs[i].sockaddr, + addrs[i].socklen); + + switch (addrs[i].sockaddr->sa_family) { +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) addrs[i].sockaddr; + sin6->sin6_port = htons(srv->port); + break; +#endif + default: /* AF_INET */ + sin = (struct sockaddr_in *) addrs[i].sockaddr; + sin->sin_port = htons(srv->port); + } + } + + srv->addrs = addrs; + srv->naddrs = cctx->naddrs; + } + + ngx_resolve_name_done(cctx); + + if (ctx->count == 0) { + ngx_resolver_report_srv(r, ctx); + } +} + + +static void +ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n, + ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan) +{ + char *err; + size_t len; + in_addr_t addr; + int32_t ttl; + ngx_int_t octet; + ngx_str_t name; + ngx_uint_t mask, type, class, qident, a, i, start; + ngx_queue_t *expire_queue; + ngx_rbtree_t *tree; + ngx_resolver_an_t *an; + ngx_resolver_ctx_t *ctx, *next; + ngx_resolver_node_t *rn; +#if (NGX_HAVE_INET6) + uint32_t hash; + ngx_int_t digit; + struct in6_addr addr6; +#endif + + if (ngx_resolver_copy(r, &name, buf, + buf + sizeof(ngx_resolver_hdr_t), buf + n) + != NGX_OK) + { + return; + } + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver qs:%V", &name); + + /* AF_INET */ + + addr = 0; + i = sizeof(ngx_resolver_hdr_t); + + for (mask = 0; mask < 32; mask += 8) { + len = buf[i++]; + + octet = ngx_atoi(&buf[i], len); + if (octet == NGX_ERROR || octet > 255) { + goto invalid_in_addr_arpa; + } + + addr += octet << mask; + i += len; + } + + if (ngx_strcasecmp(&buf[i], (u_char *) "\7in-addr\4arpa") == 0) { + i += sizeof("\7in-addr\4arpa"); + + /* lock addr mutex */ + + rn = ngx_resolver_lookup_addr(r, addr); + + tree = &r->addr_rbtree; + expire_queue = &r->addr_expire_queue; + + goto valid; + } + +invalid_in_addr_arpa: + +#if (NGX_HAVE_INET6) + + i = sizeof(ngx_resolver_hdr_t); + + for (octet = 15; octet >= 0; octet--) { + if (buf[i++] != '\1') { + goto invalid_ip6_arpa; + } + + digit = ngx_hextoi(&buf[i++], 1); + if (digit == NGX_ERROR) { + goto invalid_ip6_arpa; + } + + addr6.s6_addr[octet] = (u_char) digit; + + if (buf[i++] != '\1') { + goto invalid_ip6_arpa; + } + + digit = ngx_hextoi(&buf[i++], 1); + if (digit == NGX_ERROR) { + goto invalid_ip6_arpa; + } + + addr6.s6_addr[octet] += (u_char) (digit * 16); + } + + if (ngx_strcasecmp(&buf[i], (u_char *) "\3ip6\4arpa") == 0) { + i += sizeof("\3ip6\4arpa"); + + /* lock addr mutex */ + + hash = ngx_crc32_short(addr6.s6_addr, 16); + rn = ngx_resolver_lookup_addr6(r, &addr6, hash); + + tree = &r->addr6_rbtree; + expire_queue = &r->addr6_expire_queue; + + goto valid; + } + +invalid_ip6_arpa: +#endif + + ngx_log_error(r->log_level, r->log, 0, + "invalid in-addr.arpa or ip6.arpa name in DNS response"); + ngx_resolver_free(r, name.data); + return; + +valid: + + if (rn == NULL || rn->query == NULL) { + ngx_log_error(r->log_level, r->log, 0, + "unexpected response for %V", &name); + ngx_resolver_free(r, name.data); + goto failed; + } + + qident = (rn->query[0] << 8) + rn->query[1]; + + if (ident != qident) { + ngx_log_error(r->log_level, r->log, 0, + "wrong ident %ui response for %V, expect %ui", + ident, &name, qident); + ngx_resolver_free(r, name.data); + goto failed; + } + + ngx_resolver_free(r, name.data); + + if (code == 0 && nan == 0) { + code = NGX_RESOLVE_NXDOMAIN; + } + + if (code) { + next = rn->waiting; + rn->waiting = NULL; + + ngx_queue_remove(&rn->queue); + + ngx_rbtree_delete(tree, &rn->node); + + /* unlock addr mutex */ + + while (next) { + ctx = next; + ctx->state = code; + ctx->valid = ngx_time() + (r->valid ? r->valid : 10); + next = ctx->next; + + ctx->handler(ctx); + } + + ngx_resolver_free_node(r, rn); + + return; + } + + i += sizeof(ngx_resolver_qs_t); + + for (a = 0; a < nan; a++) { + + start = i; + + while (i < n) { + + if (buf[i] & 0xc0) { + i += 2; + goto found; + } + + if (buf[i] == 0) { + i++; + goto test_length; + } + + i += 1 + buf[i]; + } + + goto short_response; + + test_length: + + if (i - start < 2) { + err = "invalid name in DNS response"; + goto invalid; + } + + found: + + if (i + sizeof(ngx_resolver_an_t) >= n) { + goto short_response; + } + + an = (ngx_resolver_an_t *) &buf[i]; + + type = (an->type_hi << 8) + an->type_lo; + class = (an->class_hi << 8) + an->class_lo; + len = (an->len_hi << 8) + an->len_lo; + ttl = (an->ttl[0] << 24) + (an->ttl[1] << 16) + + (an->ttl[2] << 8) + (an->ttl[3]); + + if (class != 1) { + ngx_log_error(r->log_level, r->log, 0, + "unexpected RR class %ui", class); + goto failed; + } + + if (ttl < 0) { + ttl = 0; + } + + ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0, + "resolver qt:%ui cl:%ui len:%uz", type, class, len); i += sizeof(ngx_resolver_an_t); @@ -2675,6 +3356,7 @@ while (next) { ctx = next; ctx->state = NGX_OK; + ctx->valid = rn->valid; ctx->name = name; next = ctx->next; @@ -2747,6 +3429,47 @@ static ngx_resolver_node_t * +ngx_resolver_lookup_srv(ngx_resolver_t *r, ngx_str_t *name, uint32_t hash) +{ + ngx_int_t rc; + ngx_rbtree_node_t *node, *sentinel; + ngx_resolver_node_t *rn; + + node = r->srv_rbtree.root; + sentinel = r->srv_rbtree.sentinel; + + while (node != sentinel) { + + if (hash < node->key) { + node = node->left; + continue; + } + + if (hash > node->key) { + node = node->right; + continue; + } + + /* hash == node->key */ + + rn = ngx_resolver_node(node); + + rc = ngx_memn2cmp(name->data, rn->name, name->len, rn->nlen); + + if (rc == 0) { + return rn; + } + + node = (rc < 0) ? node->left : node->right; + } + + /* not found */ + + return NULL; +} + + +static ngx_resolver_node_t * ngx_resolver_lookup_addr(ngx_resolver_t *r, in_addr_t addr) { ngx_rbtree_node_t *node, *sentinel; @@ -3034,8 +3757,96 @@ static ngx_int_t +ngx_resolver_create_srv_query(ngx_resolver_t *r, ngx_resolver_node_t *rn, + ngx_str_t *name) +{ + u_char *p, *s; + size_t len, nlen; + ngx_uint_t ident; + ngx_resolver_qs_t *qs; + ngx_resolver_hdr_t *query; + + nlen = name->len ? (1 + name->len + 1) : 1; + + len = sizeof(ngx_resolver_hdr_t) + nlen + sizeof(ngx_resolver_qs_t); + + p = ngx_resolver_alloc(r, len); + if (p == NULL) { + return NGX_ERROR; + } + + rn->qlen = (u_short) len; + rn->query = p; + + query = (ngx_resolver_hdr_t *) p; + + ident = ngx_random(); + + ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0, + "resolve: \"%V\" SRV %i", name, ident & 0xffff); + + query->ident_hi = (u_char) ((ident >> 8) & 0xff); + query->ident_lo = (u_char) (ident & 0xff); + + /* recursion query */ + query->flags_hi = 1; query->flags_lo = 0; + + /* one question */ + query->nqs_hi = 0; query->nqs_lo = 1; + query->nan_hi = 0; query->nan_lo = 0; + query->nns_hi = 0; query->nns_lo = 0; + query->nar_hi = 0; query->nar_lo = 0; + + p += sizeof(ngx_resolver_hdr_t) + nlen; + + qs = (ngx_resolver_qs_t *) p; + + /* query type */ + qs->type_hi = 0; qs->type_lo = NGX_RESOLVE_SRV; + + /* IN query class */ + qs->class_hi = 0; qs->class_lo = 1; + + /* converts "www.example.com" to "\3www\7example\3com\0" */ + + len = 0; + p--; + *p-- = '\0'; + + if (name->len == 0) { + return NGX_DECLINED; + } + + for (s = name->data + name->len - 1; s >= name->data; s--) { + if (*s != '.') { + *p = *s; + len++; + + } else { + if (len == 0 || len > 255) { + return NGX_DECLINED; + } + + *p = (u_char) len; + len = 0; + } + + p--; + } + + if (len == 0 || len > 255) { + return NGX_DECLINED; + } + + *p = (u_char) len; + + return NGX_OK; +} + + +static ngx_int_t ngx_resolver_create_addr_query(ngx_resolver_t *r, ngx_resolver_node_t *rn, - ngx_addr_t *addr) + ngx_resolver_addr_t *addr) { u_char *p, *d; size_t len; @@ -3239,6 +4050,8 @@ static void ngx_resolver_free_node(ngx_resolver_t *r, ngx_resolver_node_t *rn) { + ngx_uint_t i; + /* lock alloc mutex */ if (rn->query) { @@ -3263,6 +4076,16 @@ } #endif + if (rn->nsrvs) { + for (i = 0; i < rn->nsrvs; i++) { + if (rn->u.srvs[i].name.data) { + ngx_resolver_free_locked(r, rn->u.srvs[i].name.data); + } + } + + ngx_resolver_free_locked(r, rn->u.srvs); + } + ngx_resolver_free_locked(r, rn); /* unlock alloc mutex */ @@ -3334,15 +4157,15 @@ } -static ngx_addr_t * +static ngx_resolver_addr_t * ngx_resolver_export(ngx_resolver_t *r, ngx_resolver_node_t *rn, ngx_uint_t rotate) { - ngx_addr_t *dst; ngx_uint_t d, i, j, n; u_char (*sockaddr)[NGX_SOCKADDRLEN]; in_addr_t *addr; struct sockaddr_in *sin; + ngx_resolver_addr_t *dst; #if (NGX_HAVE_INET6) struct in6_addr *addr6; struct sockaddr_in6 *sin6; @@ -3353,7 +4176,7 @@ n += rn->naddrs6; #endif - dst = ngx_resolver_calloc(r, n * sizeof(ngx_addr_t)); + dst = ngx_resolver_calloc(r, n * sizeof(ngx_resolver_addr_t)); if (dst == NULL) { return NULL; } @@ -3417,6 +4240,99 @@ } +static void +ngx_resolver_report_srv(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) +{ + ngx_uint_t naddrs, nsrvs, nw, i, j, k, l, m, n, w; + ngx_resolver_addr_t *addrs; + ngx_resolver_srv_name_t *srvs; + + naddrs = 0; + + for (i = 0; i < ctx->nsrvs; i++) { + naddrs += ctx->srvs[i].naddrs; + } + + if (naddrs == 0) { + ctx->state = NGX_RESOLVE_NXDOMAIN; + ctx->valid = ngx_time() + (r->valid ? r->valid : 10); + + ctx->handler(ctx); + return; + } + + addrs = ngx_resolver_calloc(r, naddrs * sizeof(ngx_resolver_addr_t)); + if (addrs == NULL) { + ctx->state = NGX_ERROR; + ctx->valid = ngx_time() + (r->valid ? r->valid : 10); + + ctx->handler(ctx); + return; + } + + srvs = ctx->srvs; + nsrvs = ctx->nsrvs; + + i = 0; + n = 0; + + do { + nw = 0; + + for (j = i; j < nsrvs; j++) { + if (srvs[j].priority != srvs[i].priority) { + break; + } + + nw += srvs[j].naddrs * srvs[j].weight; + } + + if (nw == 0) { + goto next_srv; + } + + w = ngx_random() % nw; + + for (k = i; k < j; k++) { + if (w < srvs[k].naddrs * srvs[k].weight) { + break; + } + + w -= srvs[k].naddrs * srvs[k].weight; + } + + for (l = i; l < j; l++) { + + for (m = 0; m < srvs[k].naddrs; m++) { + addrs[n].socklen = srvs[k].addrs[m].socklen; + addrs[n].sockaddr = srvs[k].addrs[m].sockaddr; + addrs[n].name = srvs[k].name; + addrs[n].priority = srvs[k].priority; + addrs[n].weight = srvs[k].weight; + n++; + } + + if (++k == j) { + k = i; + } + } + +next_srv: + + i = j; + + } while (i < ctx->nsrvs); + + ctx->state = NGX_OK; + ctx->addrs = addrs; + ctx->naddrs = naddrs; + + ctx->handler(ctx); + + ngx_resolver_free(r, addrs); +} + + char * ngx_resolver_strerror(ngx_int_t err) { @@ -3728,3 +4644,19 @@ return NGX_ERROR; } + + +static ngx_int_t +ngx_resolver_cmp_srvs(const void *one, const void *two) +{ + ngx_int_t p1, p2; + ngx_resolver_srv_t *first, *second; + + first = (ngx_resolver_srv_t *) one; + second = (ngx_resolver_srv_t *) two; + + p1 = first->priority; + p2 = second->priority; + + return p1 - p2; +} | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/core/ngx_resolver.h ^ |
@@ -21,6 +21,7 @@ #if (NGX_HAVE_INET6) #define NGX_RESOLVE_AAAA 28 #endif +#define NGX_RESOLVE_SRV 33 #define NGX_RESOLVE_DNAME 39 #define NGX_RESOLVE_FORMERR 1 @@ -58,6 +59,36 @@ typedef struct { + struct sockaddr *sockaddr; + socklen_t socklen; + ngx_str_t name; + u_short priority; + u_short weight; +} ngx_resolver_addr_t; + + +typedef struct { + ngx_str_t name; + u_short priority; + u_short weight; + u_short port; +} ngx_resolver_srv_t; + + +typedef struct { + ngx_str_t name; + u_short priority; + u_short weight; + u_short port; + + ngx_resolver_ctx_t *ctx; + + ngx_uint_t naddrs; + ngx_addr_t *addrs; +} ngx_resolver_srv_name_t; + + +typedef struct { ngx_rbtree_node_t node; ngx_queue_t queue; @@ -81,10 +112,12 @@ in_addr_t addr; in_addr_t *addrs; u_char *cname; + ngx_resolver_srv_t *srvs; } u; u_char code; u_short naddrs; + u_short nsrvs; u_short cnlen; #if (NGX_HAVE_INET6) @@ -127,13 +160,18 @@ ngx_rbtree_t name_rbtree; ngx_rbtree_node_t name_sentinel; + ngx_rbtree_t srv_rbtree; + ngx_rbtree_node_t srv_sentinel; + ngx_rbtree_t addr_rbtree; ngx_rbtree_node_t addr_sentinel; ngx_queue_t name_resend_queue; + ngx_queue_t srv_resend_queue; ngx_queue_t addr_resend_queue; ngx_queue_t name_expire_queue; + ngx_queue_t srv_expire_queue; ngx_queue_t addr_expire_queue; #if (NGX_HAVE_INET6) @@ -163,12 +201,18 @@ ngx_int_t state; ngx_str_t name; + ngx_str_t service; + time_t valid; ngx_uint_t naddrs; - ngx_addr_t *addrs; - ngx_addr_t addr; + ngx_resolver_addr_t *addrs; + ngx_resolver_addr_t addr; struct sockaddr_in sin; + ngx_uint_t count; + ngx_uint_t nsrvs; + ngx_resolver_srv_name_t *srvs; + ngx_resolver_handler_pt handler; void *data; ngx_msec_t timeout; | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/event/modules/ngx_devpoll_module.c ^ |
@@ -14,7 +14,9 @@ /* Solaris declarations */ +#ifndef POLLREMOVE #define POLLREMOVE 0x0800 +#endif #define DP_POLL 0xD001 #define DP_ISPOLLED 0xD002 @@ -436,7 +438,7 @@ default: ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, - "unexpected event %04Xd for closed and removed socket %d, ", + "unexpected event %04Xd for closed and removed socket %d, " "ioctl(DP_ISPOLLED) returned rc:%d, fd:%d, event %04Xd", revents, fd, rc, pfd.fd, pfd.revents); | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/event/modules/ngx_epoll_module.c ^ |
@@ -840,6 +840,9 @@ } wev->ready = 1; +#if (NGX_THREADS) + wev->complete = 1; +#endif if (flags & NGX_POST_EVENTS) { ngx_post_event(wev, &ngx_posted_events); | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/event/modules/ngx_eventport_module.c ^ |
@@ -49,7 +49,7 @@ void *portnfy_user; /* user defined */ } port_notify_t; -#if (__FreeBSD_version < 700005) +#if (__FreeBSD__) && (__FreeBSD_version < 700005) typedef struct itimerspec { /* definition per POSIX.4 */ struct timespec it_interval;/* timer period */ | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/event/ngx_event.c ^ |
@@ -746,6 +746,7 @@ return NGX_ERROR; } + c->type = ls[i].type; c->log = &ls[i].log; c->listening = &ls[i]; @@ -818,7 +819,8 @@ #else - rev->handler = ngx_event_accept; + rev->handler = (c->type == SOCK_STREAM) ? ngx_event_accept + : ngx_event_recvmsg; if (ngx_use_accept_mutex #if (NGX_HAVE_REUSEPORT) @@ -1206,7 +1208,7 @@ #endif -#if (NGX_HAVE_DEVPOLL) +#if (NGX_HAVE_DEVPOLL) && !(NGX_TEST_BUILD_DEVPOLL) module = &ngx_devpoll_module; | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/event/ngx_event.h ^ |
@@ -343,7 +343,8 @@ #define NGX_DISABLE_EVENT EV_DISABLE -#elif (NGX_HAVE_DEVPOLL || NGX_HAVE_EVENTPORT) +#elif (NGX_HAVE_DEVPOLL && !(NGX_TEST_BUILD_DEVPOLL)) \ + || (NGX_HAVE_EVENTPORT && !(NGX_TEST_BUILD_EVENTPORT)) #define NGX_READ_EVENT POLLIN #define NGX_WRITE_EVENT POLLOUT @@ -352,7 +353,7 @@ #define NGX_ONESHOT_EVENT 1 -#elif (NGX_HAVE_EPOLL) +#elif (NGX_HAVE_EPOLL) && !(NGX_TEST_BUILD_EPOLL) #define NGX_READ_EVENT (EPOLLIN|EPOLLRDHUP) #define NGX_WRITE_EVENT EPOLLOUT @@ -418,6 +419,7 @@ #define ngx_udp_recv ngx_io.udp_recv #define ngx_send ngx_io.send #define ngx_send_chain ngx_io.send_chain +#define ngx_udp_send ngx_io.udp_send #define NGX_EVENT_MODULE 0x544E5645 /* "EVNT" */ @@ -491,6 +493,9 @@ void ngx_event_accept(ngx_event_t *ev); +#if !(NGX_WIN32) +void ngx_event_recvmsg(ngx_event_t *ev); +#endif ngx_int_t ngx_trylock_accept_mutex(ngx_cycle_t *cycle); u_char *ngx_accept_log_error(ngx_log_t *log, u_char *buf, size_t len); | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/event/ngx_event_accept.c ^ |
@@ -13,6 +13,10 @@ static ngx_int_t ngx_enable_accept_events(ngx_cycle_t *cycle); static ngx_int_t ngx_disable_accept_events(ngx_cycle_t *cycle, ngx_uint_t all); static void ngx_close_accepted_connection(ngx_connection_t *c); +#if (NGX_DEBUG) +static void ngx_debug_accepted_connection(ngx_event_conf_t *ecf, + ngx_connection_t *c); +#endif void @@ -149,6 +153,8 @@ return; } + c->type = SOCK_STREAM; + #if (NGX_STAT_STUB) (void) ngx_atomic_fetch_add(ngx_stat_active, 1); #endif @@ -276,79 +282,345 @@ #if (NGX_DEBUG) { + ngx_str_t addr; + u_char text[NGX_SOCKADDR_STRLEN]; - ngx_str_t addr; - struct sockaddr_in *sin; - ngx_cidr_t *cidr; - ngx_uint_t i; - u_char text[NGX_SOCKADDR_STRLEN]; -#if (NGX_HAVE_INET6) - struct sockaddr_in6 *sin6; - ngx_uint_t n; + ngx_debug_accepted_connection(ecf, c); + + if (log->log_level & NGX_LOG_DEBUG_EVENT) { + addr.data = text; + addr.len = ngx_sock_ntop(c->sockaddr, c->socklen, text, + NGX_SOCKADDR_STRLEN, 1); + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, log, 0, + "*%uA accept: %V fd:%d", c->number, &addr, s); + } + + } #endif - cidr = ecf->debug_connection.elts; - for (i = 0; i < ecf->debug_connection.nelts; i++) { - if (cidr[i].family != (ngx_uint_t) c->sockaddr->sa_family) { - goto next; + if (ngx_add_conn && (ngx_event_flags & NGX_USE_EPOLL_EVENT) == 0) { + if (ngx_add_conn(c) == NGX_ERROR) { + ngx_close_accepted_connection(c); + return; } + } - switch (cidr[i].family) { + log->data = NULL; + log->handler = NULL; -#if (NGX_HAVE_INET6) - case AF_INET6: - sin6 = (struct sockaddr_in6 *) c->sockaddr; - for (n = 0; n < 16; n++) { - if ((sin6->sin6_addr.s6_addr[n] - & cidr[i].u.in6.mask.s6_addr[n]) - != cidr[i].u.in6.addr.s6_addr[n]) - { - goto next; - } - } - break; + ls->handler(c); + + if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { + ev->available--; + } + + } while (ev->available); +} + + +#if !(NGX_WIN32) + +void +ngx_event_recvmsg(ngx_event_t *ev) +{ + ssize_t n; + ngx_log_t *log; + ngx_err_t err; + ngx_event_t *rev, *wev; + struct iovec iov[1]; + struct msghdr msg; + ngx_listening_t *ls; + ngx_event_conf_t *ecf; + ngx_connection_t *c, *lc; + u_char sa[NGX_SOCKADDRLEN]; + static u_char buffer[65535]; + +#if (NGX_HAVE_MSGHDR_MSG_CONTROL) + +#if (NGX_HAVE_IP_RECVDSTADDR) + u_char msg_control[CMSG_SPACE(sizeof(struct in_addr))]; +#elif (NGX_HAVE_IP_PKTINFO) + u_char msg_control[CMSG_SPACE(sizeof(struct in_pktinfo))]; #endif -#if (NGX_HAVE_UNIX_DOMAIN) - case AF_UNIX: - break; +#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO) + u_char msg_control6[CMSG_SPACE(sizeof(struct in6_pktinfo))]; #endif - default: /* AF_INET */ - sin = (struct sockaddr_in *) c->sockaddr; - if ((sin->sin_addr.s_addr & cidr[i].u.in.mask) - != cidr[i].u.in.addr) - { - goto next; - } - break; +#endif + + if (ev->timedout) { + if (ngx_enable_accept_events((ngx_cycle_t *) ngx_cycle) != NGX_OK) { + return; + } + + ev->timedout = 0; + } + + ecf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_event_core_module); + + if (!(ngx_event_flags & NGX_USE_KQUEUE_EVENT)) { + ev->available = ecf->multi_accept; + } + + lc = ev->data; + ls = lc->listening; + ev->ready = 0; + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, + "recvmsg on %V, ready: %d", &ls->addr_text, ev->available); + + do { + ngx_memzero(&msg, sizeof(struct msghdr)); + + iov[0].iov_base = (void *) buffer; + iov[0].iov_len = sizeof(buffer); + + msg.msg_name = &sa; + msg.msg_namelen = sizeof(sa); + msg.msg_iov = iov; + msg.msg_iovlen = 1; + +#if (NGX_HAVE_MSGHDR_MSG_CONTROL) + + if (ls->wildcard) { + +#if (NGX_HAVE_IP_RECVDSTADDR || NGX_HAVE_IP_PKTINFO) + if (ls->sockaddr->sa_family == AF_INET) { + msg.msg_control = &msg_control; + msg.msg_controllen = sizeof(msg_control); } +#endif - log->log_level = NGX_LOG_DEBUG_CONNECTION|NGX_LOG_DEBUG_ALL; - break; +#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO) + if (ls->sockaddr->sa_family == AF_INET6) { + msg.msg_control = &msg_control6; + msg.msg_controllen = sizeof(msg_control6); + } +#endif + } - next: +#endif + + n = recvmsg(lc->fd, &msg, 0); + + if (n == -1) { + err = ngx_socket_errno; + + if (err == NGX_EAGAIN) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, err, + "recvmsg() not ready"); + return; + } + + ngx_log_error(NGX_LOG_ALERT, ev->log, err, "recvmsg() failed"); + + return; + } + +#if (NGX_STAT_STUB) + (void) ngx_atomic_fetch_add(ngx_stat_accepted, 1); +#endif + +#if (NGX_HAVE_MSGHDR_MSG_CONTROL) + if (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) { + ngx_log_error(NGX_LOG_ALERT, ev->log, 0, + "recvmsg() truncated data"); continue; } +#endif - if (log->log_level & NGX_LOG_DEBUG_EVENT) { - addr.data = text; - addr.len = ngx_sock_ntop(c->sockaddr, c->socklen, text, - NGX_SOCKADDR_STRLEN, 1); + ngx_accept_disabled = ngx_cycle->connection_n / 8 + - ngx_cycle->free_connection_n; - ngx_log_debug3(NGX_LOG_DEBUG_EVENT, log, 0, - "*%uA accept: %V fd:%d", c->number, &addr, s); + c = ngx_get_connection(lc->fd, ev->log); + if (c == NULL) { + return; } + c->shared = 1; + c->type = SOCK_DGRAM; + c->socklen = msg.msg_namelen; + +#if (NGX_STAT_STUB) + (void) ngx_atomic_fetch_add(ngx_stat_active, 1); +#endif + + c->pool = ngx_create_pool(ls->pool_size, ev->log); + if (c->pool == NULL) { + ngx_close_accepted_connection(c); + return; + } + + c->sockaddr = ngx_palloc(c->pool, c->socklen); + if (c->sockaddr == NULL) { + ngx_close_accepted_connection(c); + return; + } + + ngx_memcpy(c->sockaddr, msg.msg_name, c->socklen); + + log = ngx_palloc(c->pool, sizeof(ngx_log_t)); + if (log == NULL) { + ngx_close_accepted_connection(c); + return; } + + *log = ls->log; + + c->send = ngx_udp_send; + + c->log = log; + c->pool->log = log; + + c->listening = ls; + c->local_sockaddr = ls->sockaddr; + c->local_socklen = ls->socklen; + +#if (NGX_HAVE_MSGHDR_MSG_CONTROL) + + if (ls->wildcard) { + struct cmsghdr *cmsg; + struct sockaddr *sockaddr; + + sockaddr = ngx_palloc(c->pool, c->local_socklen); + if (sockaddr == NULL) { + ngx_close_accepted_connection(c); + return; + } + + ngx_memcpy(sockaddr, c->local_sockaddr, c->local_socklen); + c->local_sockaddr = sockaddr; + + for (cmsg = CMSG_FIRSTHDR(&msg); + cmsg != NULL; + cmsg = CMSG_NXTHDR(&msg, cmsg)) + { + +#if (NGX_HAVE_IP_RECVDSTADDR) + + if (cmsg->cmsg_level == IPPROTO_IP + && cmsg->cmsg_type == IP_RECVDSTADDR + && sockaddr->sa_family == AF_INET) + { + struct in_addr *addr; + struct sockaddr_in *sin; + + addr = (struct in_addr *) CMSG_DATA(cmsg); + sin = (struct sockaddr_in *) sockaddr; + sin->sin_addr = *addr; + + break; + } + +#elif (NGX_HAVE_IP_PKTINFO) + + if (cmsg->cmsg_level == IPPROTO_IP + && cmsg->cmsg_type == IP_PKTINFO + && sockaddr->sa_family == AF_INET) + { + struct in_pktinfo *pkt; + struct sockaddr_in *sin; + + pkt = (struct in_pktinfo *) CMSG_DATA(cmsg); + sin = (struct sockaddr_in *) sockaddr; + sin->sin_addr = pkt->ipi_addr; + + break; + } + #endif - if (ngx_add_conn && (ngx_event_flags & NGX_USE_EPOLL_EVENT) == 0) { - if (ngx_add_conn(c) == NGX_ERROR) { +#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO) + + if (cmsg->cmsg_level == IPPROTO_IPV6 + && cmsg->cmsg_type == IPV6_PKTINFO + && sockaddr->sa_family == AF_INET6) + { + struct in6_pktinfo *pkt6; + struct sockaddr_in6 *sin6; + + pkt6 = (struct in6_pktinfo *) CMSG_DATA(cmsg); + sin6 = (struct sockaddr_in6 *) sockaddr; + sin6->sin6_addr = pkt6->ipi6_addr; + + break; + } + +#endif + + } + } + +#endif + + c->buffer = ngx_create_temp_buf(c->pool, n); + if (c->buffer == NULL) { + ngx_close_accepted_connection(c); + return; + } + + c->buffer->last = ngx_cpymem(c->buffer->last, buffer, n); + + rev = c->read; + wev = c->write; + + wev->ready = 1; + + rev->log = log; + wev->log = log; + + /* + * TODO: MT: - ngx_atomic_fetch_add() + * or protection by critical section or light mutex + * + * TODO: MP: - allocated in a shared memory + * - ngx_atomic_fetch_add() + * or protection by critical section or light mutex + */ + + c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1); + +#if (NGX_STAT_STUB) + (void) ngx_atomic_fetch_add(ngx_stat_handled, 1); +#endif + + if (ls->addr_ntop) { + c->addr_text.data = ngx_pnalloc(c->pool, ls->addr_text_max_len); + if (c->addr_text.data == NULL) { ngx_close_accepted_connection(c); return; } + + c->addr_text.len = ngx_sock_ntop(c->sockaddr, c->socklen, + c->addr_text.data, + ls->addr_text_max_len, 0); + if (c->addr_text.len == 0) { + ngx_close_accepted_connection(c); + return; + } + } + +#if (NGX_DEBUG) + { + ngx_str_t addr; + u_char text[NGX_SOCKADDR_STRLEN]; + + ngx_debug_accepted_connection(ecf, c); + + if (log->log_level & NGX_LOG_DEBUG_EVENT) { + addr.data = text; + addr.len = ngx_sock_ntop(c->sockaddr, c->socklen, text, + NGX_SOCKADDR_STRLEN, 1); + + ngx_log_debug4(NGX_LOG_DEBUG_EVENT, log, 0, + "*%uA recvmsg: %V fd:%d n:%z", + c->number, &addr, c->fd, n); + } + } +#endif log->data = NULL; log->handler = NULL; @@ -356,12 +628,14 @@ ls->handler(c); if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { - ev->available--; + ev->available -= n; } } while (ev->available); } +#endif + ngx_int_t ngx_trylock_accept_mutex(ngx_cycle_t *cycle) @@ -476,7 +750,7 @@ fd = c->fd; c->fd = (ngx_socket_t) -1; - if (ngx_close_socket(fd) == -1) { + if (!c->shared && ngx_close_socket(fd) == -1) { ngx_log_error(NGX_LOG_ALERT, c->log, ngx_socket_errno, ngx_close_socket_n " failed"); } @@ -497,3 +771,64 @@ return ngx_snprintf(buf, len, " while accepting new connection on %V", log->data); } + + +#if (NGX_DEBUG) + +static void +ngx_debug_accepted_connection(ngx_event_conf_t *ecf, ngx_connection_t *c) +{ + struct sockaddr_in *sin; + ngx_cidr_t *cidr; + ngx_uint_t i; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; + ngx_uint_t n; +#endif + + cidr = ecf->debug_connection.elts; + for (i = 0; i < ecf->debug_connection.nelts; i++) { + if (cidr[i].family != (ngx_uint_t) c->sockaddr->sa_family) { + goto next; + } + + switch (cidr[i].family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) c->sockaddr; + for (n = 0; n < 16; n++) { + if ((sin6->sin6_addr.s6_addr[n] + & cidr[i].u.in6.mask.s6_addr[n]) + != cidr[i].u.in6.addr.s6_addr[n]) + { + goto next; + } + } + break; +#endif + +#if (NGX_HAVE_UNIX_DOMAIN) + case AF_UNIX: + break; +#endif + + default: /* AF_INET */ + sin = (struct sockaddr_in *) c->sockaddr; + if ((sin->sin_addr.s_addr & cidr[i].u.in.mask) + != cidr[i].u.in.addr) + { + goto next; + } + break; + } + + c->log->log_level = NGX_LOG_DEBUG_CONNECTION|NGX_LOG_DEBUG_ALL; + break; + + next: + continue; + } +} + +#endif | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/event/ngx_event_connect.c ^ |
@@ -14,7 +14,7 @@ ngx_int_t ngx_event_connect_peer(ngx_peer_connection_t *pc) { - int rc; + int rc, type; ngx_int_t event; ngx_err_t err; ngx_uint_t level; @@ -27,9 +27,12 @@ return rc; } - s = ngx_socket(pc->sockaddr->sa_family, SOCK_STREAM, 0); + type = (pc->type ? pc->type : SOCK_STREAM); - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pc->log, 0, "socket %d", s); + s = ngx_socket(pc->sockaddr->sa_family, type, 0); + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pc->log, 0, "%s socket %d", + (type == SOCK_STREAM) ? "stream" : "dgram", s); if (s == (ngx_socket_t) -1) { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, @@ -49,6 +52,8 @@ return NGX_ERROR; } + c->type = type; + if (pc->rcvbuf) { if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, (const void *) &pc->rcvbuf, sizeof(int)) == -1) @@ -75,25 +80,31 @@ } } - c->recv = ngx_recv; - c->send = ngx_send; - c->recv_chain = ngx_recv_chain; - c->send_chain = ngx_send_chain; - - c->sendfile = 1; - - c->log_error = pc->log_error; - - if (pc->sockaddr->sa_family == AF_UNIX) { - c->tcp_nopush = NGX_TCP_NOPUSH_DISABLED; - c->tcp_nodelay = NGX_TCP_NODELAY_DISABLED; + if (type == SOCK_STREAM) { + c->recv = ngx_recv; + c->send = ngx_send; + c->recv_chain = ngx_recv_chain; + c->send_chain = ngx_send_chain; + + c->sendfile = 1; + + if (pc->sockaddr->sa_family == AF_UNIX) { + c->tcp_nopush = NGX_TCP_NOPUSH_DISABLED; + c->tcp_nodelay = NGX_TCP_NODELAY_DISABLED; #if (NGX_SOLARIS) - /* Solaris's sendfilev() supports AF_NCA, AF_INET, and AF_INET6 */ - c->sendfile = 0; + /* Solaris's sendfilev() supports AF_NCA, AF_INET, and AF_INET6 */ + c->sendfile = 0; #endif + } + + } else { /* type == SOCK_DGRAM */ + c->recv = ngx_udp_recv; + c->send = ngx_send; } + c->log_error = pc->log_error; + rev = c->read; wev = c->write; | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/event/ngx_event_connect.h ^ |
@@ -55,6 +55,7 @@ ngx_addr_t *local; + int type; int rcvbuf; ngx_log_t *log; | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/event/ngx_event_pipe.c ^ |
@@ -112,6 +112,14 @@ return NGX_OK; } +#if (NGX_THREADS) + if (p->aio) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, p->log, 0, + "pipe read upstream: aio"); + return NGX_AGAIN; + } +#endif + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "pipe read upstream: %d", p->upstream->read->ready); @@ -258,19 +266,6 @@ break; } - if (rc == NGX_AGAIN) { - if (ngx_event_flags & NGX_USE_LEVEL_EVENT - && p->upstream->read->active - && p->upstream->read->ready) - { - if (ngx_del_event(p->upstream->read, NGX_READ_EVENT, 0) - == NGX_ERROR) - { - return NGX_ABORT; - } - } - } - if (rc != NGX_OK) { return rc; } @@ -475,8 +470,10 @@ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, p->log, 0, "pipe write chain"); - if (ngx_event_pipe_write_chain_to_temp_file(p) == NGX_ABORT) { - return NGX_ABORT; + rc = ngx_event_pipe_write_chain_to_temp_file(p); + + if (rc != NGX_OK) { + return rc; } } @@ -499,6 +496,18 @@ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "pipe write downstream: %d", downstream->write->ready); +#if (NGX_THREADS) + + if (p->writing) { + rc = ngx_event_pipe_write_chain_to_temp_file(p); + + if (rc == NGX_ABORT) { + return NGX_ABORT; + } + } + +#endif + flushed = 0; for ( ;; ) { @@ -532,6 +541,10 @@ p->out = NULL; } + if (p->writing) { + break; + } + if (p->in) { ngx_log_debug0(NGX_LOG_DEBUG_EVENT, p->log, 0, "pipe write downstream flush in"); @@ -608,7 +621,7 @@ p->out = p->out->next; - } else if (!p->cacheable && p->in) { + } else if (!p->cacheable && !p->writing && p->in) { cl = p->in; ngx_log_debug3(NGX_LOG_DEBUG_EVENT, p->log, 0, @@ -710,12 +723,38 @@ ssize_t size, bsize, n; ngx_buf_t *b; ngx_uint_t prev_last_shadow; - ngx_chain_t *cl, *tl, *next, *out, **ll, **last_out, **last_free, fl; + ngx_chain_t *cl, *tl, *next, *out, **ll, **last_out, **last_free; + +#if (NGX_THREADS) + + if (p->writing) { + + if (p->aio) { + return NGX_AGAIN; + } + + out = p->writing; + p->writing = NULL; + + n = ngx_write_chain_to_temp_file(p->temp_file, NULL); + + if (n == NGX_ERROR) { + return NGX_ABORT; + } + + goto done; + } + +#endif if (p->buf_to_file) { - fl.buf = p->buf_to_file; - fl.next = p->in; - out = &fl; + out = ngx_alloc_chain_link(p->pool); + if (out == NULL) { + return NGX_ABORT; + } + + out->buf = p->buf_to_file; + out->next = p->in; } else { out = p->in; @@ -775,12 +814,31 @@ p->last_in = &p->in; } +#if (NGX_THREADS) + p->temp_file->thread_write = p->thread_handler ? 1 : 0; + p->temp_file->file.thread_task = p->thread_task; + p->temp_file->file.thread_handler = p->thread_handler; + p->temp_file->file.thread_ctx = p->thread_ctx; +#endif + n = ngx_write_chain_to_temp_file(p->temp_file, out); if (n == NGX_ERROR) { return NGX_ABORT; } +#if (NGX_THREADS) + + if (n == NGX_AGAIN) { + p->writing = out; + p->thread_task = p->temp_file->file.thread_task; + return NGX_AGAIN; + } + +done: + +#endif + if (p->buf_to_file) { p->temp_file->offset = p->buf_to_file->last - p->buf_to_file->pos; n -= p->buf_to_file->last - p->buf_to_file->pos; | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/event/ngx_event_pipe.h ^ |
@@ -30,6 +30,8 @@ ngx_chain_t *in; ngx_chain_t **last_in; + ngx_chain_t *writing; + ngx_chain_t *out; ngx_chain_t *free; ngx_chain_t *busy; @@ -45,6 +47,13 @@ ngx_event_pipe_output_filter_pt output_filter; void *output_ctx; +#if (NGX_THREADS) + ngx_int_t (*thread_handler)(ngx_thread_task_t *task, + ngx_file_t *file); + void *thread_ctx; + ngx_thread_task_t *thread_task; +#endif + unsigned read:1; unsigned cacheable:1; unsigned single_buf:1; @@ -56,6 +65,7 @@ unsigned downstream_done:1; unsigned downstream_error:1; unsigned cyclic_temp_file:1; + unsigned aio:1; ngx_int_t allocated; ngx_bufs_t bufs; | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/http/modules/ngx_http_fastcgi_module.c ^ |
@@ -206,6 +206,7 @@ { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR }, { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT }, { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER }, + { ngx_string("non_idempotent"), NGX_HTTP_UPSTREAM_FT_NON_IDEMPOTENT }, { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 }, { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 }, { ngx_string("http_403"), NGX_HTTP_UPSTREAM_FT_HTTP_403 }, | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/http/modules/ngx_http_proxy_module.c ^ |
@@ -213,6 +213,7 @@ { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR }, { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT }, { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER }, + { ngx_string("non_idempotent"), NGX_HTTP_UPSTREAM_FT_NON_IDEMPOTENT }, { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 }, { ngx_string("http_502"), NGX_HTTP_UPSTREAM_FT_HTTP_502 }, { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 }, | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/http/modules/ngx_http_scgi_module.c ^ |
@@ -77,6 +77,7 @@ { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR }, { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT }, { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER }, + { ngx_string("non_idempotent"), NGX_HTTP_UPSTREAM_FT_NON_IDEMPOTENT }, { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 }, { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 }, { ngx_string("http_403"), NGX_HTTP_UPSTREAM_FT_HTTP_403 }, | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/http/modules/ngx_http_sub_filter_module.c ^ |
@@ -229,7 +229,7 @@ return ngx_http_next_header_filter(r); } - ctx->matches = ngx_pnalloc(r->pool, sizeof(ngx_array_t)); + ctx->matches = ngx_palloc(r->pool, sizeof(ngx_array_t)); if (ctx->matches == NULL) { return NGX_ERROR; } @@ -237,7 +237,7 @@ ctx->matches->elts = matches; ctx->matches->nelts = j; - ctx->tables = ngx_pnalloc(r->pool, sizeof(ngx_http_sub_tables_t)); + ctx->tables = ngx_palloc(r->pool, sizeof(ngx_http_sub_tables_t)); if (ctx->tables == NULL) { return NGX_ERROR; } @@ -859,7 +859,7 @@ pairs = conf->pairs->elts; n = conf->pairs->nelts; - matches = ngx_pnalloc(cf->pool, sizeof(ngx_http_sub_match_t) * n); + matches = ngx_palloc(cf->pool, sizeof(ngx_http_sub_match_t) * n); if (matches == NULL) { return NGX_CONF_ERROR; } @@ -869,7 +869,7 @@ matches[i].value = &pairs[i].value; } - conf->matches = ngx_pnalloc(cf->pool, sizeof(ngx_array_t)); + conf->matches = ngx_palloc(cf->pool, sizeof(ngx_array_t)); if (conf->matches == NULL) { return NGX_CONF_ERROR; } | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/http/modules/ngx_http_uwsgi_module.c ^ |
@@ -109,6 +109,7 @@ { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR }, { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT }, { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER }, + { ngx_string("non_idempotent"), NGX_HTTP_UPSTREAM_FT_NON_IDEMPOTENT }, { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 }, { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 }, { ngx_string("http_403"), NGX_HTTP_UPSTREAM_FT_HTTP_403 }, | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/http/ngx_http_cache.h ^ |
@@ -138,6 +138,8 @@ ngx_atomic_t cold; ngx_atomic_t loading; off_t size; + ngx_uint_t count; + ngx_uint_t watermark; } ngx_http_file_cache_sh_t; @@ -153,6 +155,8 @@ time_t inactive; + time_t fail_time; + ngx_uint_t files; ngx_uint_t loader_files; ngx_msec_t last; | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/http/ngx_http_copy_filter_module.c ^ |
@@ -204,10 +204,11 @@ static ssize_t ngx_http_copy_aio_sendfile_preload(ngx_buf_t *file) { - ssize_t n; - static u_char buf[1]; - ngx_event_aio_t *aio; - ngx_http_request_t *r; + ssize_t n; + static u_char buf[1]; + ngx_event_aio_t *aio; + ngx_http_request_t *r; + ngx_output_chain_ctx_t *ctx; n = ngx_file_aio_read(file->file, buf, 1, file->file_pos, NULL); @@ -218,6 +219,9 @@ r = aio->data; r->main->blocked++; r->aio = 1; + + ctx = ngx_http_get_module_ctx(r, ngx_http_copy_filter_module); + ctx->aio = 1; } return n; @@ -252,6 +256,7 @@ ngx_str_t name; ngx_thread_pool_t *tp; ngx_http_request_t *r; + ngx_output_chain_ctx_t *ctx; ngx_http_core_loc_conf_t *clcf; r = file->thread_ctx; @@ -285,6 +290,9 @@ r->main->blocked++; r->aio = 1; + ctx = ngx_http_get_module_ctx(r, ngx_http_copy_filter_module); + ctx->aio = 1; + return NGX_OK; } | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/http/ngx_http_core_module.c ^ |
@@ -400,6 +400,13 @@ 0, NULL }, + { ngx_string("aio_write"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_core_loc_conf_t, aio_write), + NULL }, + { ngx_string("read_ahead"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_size_slot, @@ -3606,6 +3613,7 @@ clcf->sendfile = NGX_CONF_UNSET; clcf->sendfile_max_chunk = NGX_CONF_UNSET_SIZE; clcf->aio = NGX_CONF_UNSET; + clcf->aio_write = NGX_CONF_UNSET; #if (NGX_THREADS) clcf->thread_pool = NGX_CONF_UNSET_PTR; clcf->thread_pool_value = NGX_CONF_UNSET_PTR; @@ -3827,6 +3835,7 @@ prev->sendfile_max_chunk, 0); #if (NGX_HAVE_FILE_AIO || NGX_THREADS) ngx_conf_merge_value(conf->aio, prev->aio, NGX_HTTP_AIO_OFF); + ngx_conf_merge_value(conf->aio_write, prev->aio_write, 0); #endif #if (NGX_THREADS) ngx_conf_merge_ptr_value(conf->thread_pool, prev->thread_pool, NULL); | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/http/ngx_http_core_module.h ^ |
@@ -404,6 +404,7 @@ ngx_flag_t internal; /* internal */ ngx_flag_t sendfile; /* sendfile */ ngx_flag_t aio; /* aio */ + ngx_flag_t aio_write; /* aio_write */ ngx_flag_t tcp_nopush; /* tcp_nopush */ ngx_flag_t tcp_nodelay; /* tcp_nodelay */ ngx_flag_t reset_timedout_connection; /* reset_timedout_connection */ | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/http/ngx_http_file_cache.c ^ |
@@ -62,6 +62,7 @@ ngx_http_cache_t *c); static ngx_int_t ngx_http_file_cache_delete_file(ngx_tree_ctx_t *ctx, ngx_str_t *path); +static void ngx_http_file_cache_set_watermark(ngx_http_file_cache_t *cache); ngx_str_t ngx_http_cache_status[] = { @@ -147,6 +148,8 @@ cache->sh->cold = 1; cache->sh->loading = 0; cache->sh->size = 0; + cache->sh->count = 0; + cache->sh->watermark = (ngx_uint_t) -1; cache->bsize = ngx_fs_bsize(cache->path->name.data); @@ -691,12 +694,13 @@ #if (NGX_THREADS) if (clcf->aio == NGX_HTTP_AIO_THREADS) { + c->file.thread_task = c->thread_task; c->file.thread_handler = ngx_http_cache_thread_handler; c->file.thread_ctx = r; - n = ngx_thread_read(&c->thread_task, &c->file, c->buf->pos, - c->body_start, 0, r->pool); + n = ngx_thread_read(&c->file, c->buf->pos, c->body_start, 0, r->pool); + c->thread_task = c->file.thread_task; c->reading = (n == NGX_AGAIN); return n; @@ -860,6 +864,8 @@ fcn = ngx_slab_calloc_locked(cache->shpool, sizeof(ngx_http_file_cache_node_t)); if (fcn == NULL) { + ngx_http_file_cache_set_watermark(cache); + ngx_shmtx_unlock(&cache->shpool->mutex); (void) ngx_http_file_cache_forced_expire(cache); @@ -876,6 +882,8 @@ } } + cache->sh->count++; + ngx_memcpy((u_char *) &fcn->node.key, c->key, sizeof(ngx_rbtree_key_t)); ngx_memcpy(fcn->key, &c->key[sizeof(ngx_rbtree_key_t)], @@ -1630,6 +1638,7 @@ ngx_queue_remove(&fcn->queue); ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node); ngx_slab_free_locked(cache->shpool, fcn); + cache->sh->count--; c->node = NULL; } @@ -1882,6 +1891,7 @@ ngx_queue_remove(q); ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node); ngx_slab_free_locked(cache->shpool, fcn); + cache->sh->count--; } } @@ -1891,8 +1901,9 @@ { ngx_http_file_cache_t *cache = data; - off_t size; - time_t next, wait; + off_t size; + time_t next, wait; + ngx_uint_t count, watermark; next = ngx_http_file_cache_expire(cache); @@ -1903,13 +1914,16 @@ ngx_shmtx_lock(&cache->shpool->mutex); size = cache->sh->size; + count = cache->sh->count; + watermark = cache->sh->watermark; ngx_shmtx_unlock(&cache->shpool->mutex); - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "http file cache size: %O", size); + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "http file cache size: %O c:%ui w:%i", + size, count, (ngx_int_t) watermark); - if (size < cache->max_size) { + if (size < cache->max_size && count < watermark) { return next; } @@ -2093,10 +2107,20 @@ fcn = ngx_slab_calloc_locked(cache->shpool, sizeof(ngx_http_file_cache_node_t)); if (fcn == NULL) { + ngx_http_file_cache_set_watermark(cache); + + if (cache->fail_time != ngx_time()) { + cache->fail_time = ngx_time(); + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "could not allocate node%s", cache->shpool->log_ctx); + } + ngx_shmtx_unlock(&cache->shpool->mutex); return NGX_ERROR; } + cache->sh->count++; + ngx_memcpy((u_char *) &fcn->node.key, c->key, sizeof(ngx_rbtree_key_t)); ngx_memcpy(fcn->key, &c->key[sizeof(ngx_rbtree_key_t)], @@ -2139,6 +2163,16 @@ } +static void +ngx_http_file_cache_set_watermark(ngx_http_file_cache_t *cache) +{ + cache->sh->watermark = cache->sh->count - cache->sh->count / 8; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "http file cache watermark: %ui", cache->sh->watermark); +} + + time_t ngx_http_file_cache_valid(ngx_array_t *cache_valid, ngx_uint_t status) { | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/http/ngx_http_request_body.c ^ |
@@ -34,7 +34,7 @@ ssize_t size; ngx_int_t rc; ngx_buf_t *b; - ngx_chain_t out, *cl; + ngx_chain_t out; ngx_http_request_body_t *rb; ngx_http_core_loc_conf_t *clcf; @@ -59,10 +59,6 @@ goto done; } - if (r->request_body_no_buffering) { - r->request_body_in_file_only = 0; - } - rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); if (rb == NULL) { rc = NGX_HTTP_INTERNAL_SERVER_ERROR; @@ -148,37 +144,8 @@ if (rb->rest == 0) { /* the whole request body was pre-read */ - - if (r->request_body_in_file_only) { - if (ngx_http_write_request_body(r) != NGX_OK) { - rc = NGX_HTTP_INTERNAL_SERVER_ERROR; - goto done; - } - - if (rb->temp_file->file.offset != 0) { - - cl = ngx_chain_get_free_buf(r->pool, &rb->free); - if (cl == NULL) { - rc = NGX_HTTP_INTERNAL_SERVER_ERROR; - goto done; - } - - b = cl->buf; - - ngx_memzero(b, sizeof(ngx_buf_t)); - - b->in_file = 1; - b->file_last = rb->temp_file->file.offset; - b->file = &rb->temp_file->file; - - rb->bufs = cl; - } - } - r->request_body_no_buffering = 0; - post_handler(r); - return NGX_OK; } @@ -289,8 +256,7 @@ size_t size; ssize_t n; ngx_int_t rc; - ngx_buf_t *b; - ngx_chain_t *cl, out; + ngx_chain_t out; ngx_connection_t *c; ngx_http_request_body_t *rb; ngx_http_core_loc_conf_t *clcf; @@ -439,33 +405,6 @@ ngx_del_timer(c->read); } - if (rb->temp_file || r->request_body_in_file_only) { - - /* save the last part */ - - if (ngx_http_write_request_body(r) != NGX_OK) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - if (rb->temp_file->file.offset != 0) { - - cl = ngx_chain_get_free_buf(r->pool, &rb->free); - if (cl == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - b = cl->buf; - - ngx_memzero(b, sizeof(ngx_buf_t)); - - b->in_file = 1; - b->file_last = rb->temp_file->file.offset; - b->file = &rb->temp_file->file; - - rb->bufs = cl; - } - } - if (!r->request_body_no_buffering) { r->read_event_handler = ngx_http_block_reading; rb->post_handler(r); @@ -1127,9 +1066,8 @@ ngx_int_t ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in) { -#if (NGX_DEBUG) + ngx_buf_t *b; ngx_chain_t *cl; -#endif ngx_http_request_body_t *rb; rb = r->request_body; @@ -1166,13 +1104,46 @@ return NGX_HTTP_INTERNAL_SERVER_ERROR; } - if (rb->rest > 0 - && rb->buf && rb->buf->last == rb->buf->end - && !r->request_body_no_buffering) - { + if (r->request_body_no_buffering) { + return NGX_OK; + } + + if (rb->rest > 0) { + + if (rb->buf && rb->buf->last == rb->buf->end + && ngx_http_write_request_body(r) != NGX_OK) + { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + return NGX_OK; + } + + /* rb->rest == 0 */ + + if (rb->temp_file || r->request_body_in_file_only) { + if (ngx_http_write_request_body(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } + + if (rb->temp_file->file.offset != 0) { + + cl = ngx_chain_get_free_buf(r->pool, &rb->free); + if (cl == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + b = cl->buf; + + ngx_memzero(b, sizeof(ngx_buf_t)); + + b->in_file = 1; + b->file_last = rb->temp_file->file.offset; + b->file = &rb->temp_file->file; + + rb->bufs = cl; + } } return NGX_OK; | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/http/ngx_http_upstream.c ^ |
@@ -76,6 +76,13 @@ static ngx_int_t ngx_http_upstream_non_buffered_filter_init(void *data); static ngx_int_t ngx_http_upstream_non_buffered_filter(void *data, ssize_t bytes); +#if (NGX_THREADS) +static ngx_int_t ngx_http_upstream_thread_handler(ngx_thread_task_t *task, + ngx_file_t *file); +static void ngx_http_upstream_thread_event_handler(ngx_event_t *ev); +#endif +static ngx_int_t ngx_http_upstream_output_filter(void *data, + ngx_chain_t *chain); static void ngx_http_upstream_process_downstream(ngx_http_request_t *r); static void ngx_http_upstream_process_upstream(ngx_http_request_t *r, ngx_http_upstream_t *u); @@ -416,10 +423,10 @@ ngx_conf_bitmask_t ngx_http_upstream_cache_method_mask[] = { - { ngx_string("GET"), NGX_HTTP_GET}, - { ngx_string("HEAD"), NGX_HTTP_HEAD }, - { ngx_string("POST"), NGX_HTTP_POST }, - { ngx_null_string, 0 } + { ngx_string("GET"), NGX_HTTP_GET }, + { ngx_string("HEAD"), NGX_HTTP_HEAD }, + { ngx_string("POST"), NGX_HTTP_POST }, + { ngx_null_string, 0 } }; @@ -2861,11 +2868,16 @@ ngx_http_file_cache_free(r->cache, u->pipe->temp_file); } + if (r->header_only && !u->cacheable && !u->store) { + ngx_http_upstream_finalize_request(r, u, 0); + return; + } + #endif p = u->pipe; - p->output_filter = (ngx_event_pipe_output_filter_pt) ngx_http_output_filter; + p->output_filter = ngx_http_upstream_output_filter; p->output_ctx = r; p->tag = u->output.tag; p->bufs = u->conf->bufs; @@ -2908,6 +2920,13 @@ p->max_temp_file_size = u->conf->max_temp_file_size; p->temp_file_write_size = u->conf->temp_file_write_size; +#if (NGX_THREADS) + if (clcf->aio == NGX_HTTP_AIO_THREADS && clcf->aio_write) { + p->thread_handler = ngx_http_upstream_thread_handler; + p->thread_ctx = r; + } +#endif + p->preread_bufs = ngx_alloc_chain_link(r->pool); if (p->preread_bufs == NULL) { ngx_http_upstream_finalize_request(r, u, NGX_ERROR); @@ -3482,6 +3501,97 @@ } +#if (NGX_THREADS) + +static ngx_int_t +ngx_http_upstream_thread_handler(ngx_thread_task_t *task, ngx_file_t *file) +{ + ngx_str_t name; + ngx_event_pipe_t *p; + ngx_thread_pool_t *tp; + ngx_http_request_t *r; + ngx_http_core_loc_conf_t *clcf; + + r = file->thread_ctx; + p = r->upstream->pipe; + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + tp = clcf->thread_pool; + + if (tp == NULL) { + if (ngx_http_complex_value(r, clcf->thread_pool_value, &name) + != NGX_OK) + { + return NGX_ERROR; + } + + tp = ngx_thread_pool_get((ngx_cycle_t *) ngx_cycle, &name); + + if (tp == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "thread pool \"%V\" not found", &name); + return NGX_ERROR; + } + } + + task->event.data = r; + task->event.handler = ngx_http_upstream_thread_event_handler; + + if (ngx_thread_task_post(tp, task) != NGX_OK) { + return NGX_ERROR; + } + + r->main->blocked++; + r->aio = 1; + p->aio = 1; + + return NGX_OK; +} + + +static void +ngx_http_upstream_thread_event_handler(ngx_event_t *ev) +{ + ngx_connection_t *c; + ngx_http_request_t *r; + + r = ev->data; + c = r->connection; + + ngx_http_set_log_request(c->log, r); + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http upstream thread: \"%V?%V\"", &r->uri, &r->args); + + r->main->blocked--; + r->aio = 0; + + r->write_event_handler(r); + + ngx_http_run_posted_requests(c); +} + +#endif + + +static ngx_int_t +ngx_http_upstream_output_filter(void *data, ngx_chain_t *chain) +{ + ngx_int_t rc; + ngx_event_pipe_t *p; + ngx_http_request_t *r; + + r = data; + p = r->upstream->pipe; + + rc = ngx_http_output_filter(r, chain); + + p->aio = r->aio; + + return rc; +} + + static void ngx_http_upstream_process_downstream(ngx_http_request_t *r) { @@ -3500,6 +3610,10 @@ c->log->action = "sending to client"; +#if (NGX_THREADS) + p->aio = r->aio; +#endif + if (wev->timedout) { if (wev->delayed) { @@ -3629,6 +3743,12 @@ p = u->pipe; +#if (NGX_THREADS) + if (p->writing) { + return; + } +#endif + if (u->peer.connection) { if (u->store) { @@ -3827,42 +3947,36 @@ "upstream timed out"); } - if (u->peer.cached && ft_type == NGX_HTTP_UPSTREAM_FT_ERROR - && (!u->request_sent || !r->request_body_no_buffering)) - { - status = 0; - + if (u->peer.cached && ft_type == NGX_HTTP_UPSTREAM_FT_ERROR) { /* TODO: inform balancer instead */ - u->peer.tries++; + } - } else { - switch (ft_type) { + switch (ft_type) { - case NGX_HTTP_UPSTREAM_FT_TIMEOUT: - status = NGX_HTTP_GATEWAY_TIME_OUT; - break; + case NGX_HTTP_UPSTREAM_FT_TIMEOUT: + status = NGX_HTTP_GATEWAY_TIME_OUT; + break; - case NGX_HTTP_UPSTREAM_FT_HTTP_500: - status = NGX_HTTP_INTERNAL_SERVER_ERROR; - break; + case NGX_HTTP_UPSTREAM_FT_HTTP_500: + status = NGX_HTTP_INTERNAL_SERVER_ERROR; + break; - case NGX_HTTP_UPSTREAM_FT_HTTP_403: - status = NGX_HTTP_FORBIDDEN; - break; + case NGX_HTTP_UPSTREAM_FT_HTTP_403: + status = NGX_HTTP_FORBIDDEN; + break; - case NGX_HTTP_UPSTREAM_FT_HTTP_404: - status = NGX_HTTP_NOT_FOUND; - break; + case NGX_HTTP_UPSTREAM_FT_HTTP_404: + status = NGX_HTTP_NOT_FOUND; + break; - /* - * NGX_HTTP_UPSTREAM_FT_BUSY_LOCK and NGX_HTTP_UPSTREAM_FT_MAX_WAITING - * never reach here - */ + /* + * NGX_HTTP_UPSTREAM_FT_BUSY_LOCK and NGX_HTTP_UPSTREAM_FT_MAX_WAITING + * never reach here + */ - default: - status = NGX_HTTP_BAD_GATEWAY; - } + default: + status = NGX_HTTP_BAD_GATEWAY; } if (r->connection->error) { @@ -3871,37 +3985,42 @@ return; } - if (status) { - u->state->status = status; - timeout = u->conf->next_upstream_timeout; - - if (u->peer.tries == 0 - || !(u->conf->next_upstream & ft_type) - || (u->request_sent && r->request_body_no_buffering) - || (timeout && ngx_current_msec - u->peer.start_time >= timeout)) - { -#if (NGX_HTTP_CACHE) + u->state->status = status; - if (u->cache_status == NGX_HTTP_CACHE_EXPIRED - && (u->conf->cache_use_stale & ft_type)) - { - ngx_int_t rc; + timeout = u->conf->next_upstream_timeout; - rc = u->reinit_request(r); + if (u->request_sent + && (r->method & (NGX_HTTP_POST|NGX_HTTP_LOCK|NGX_HTTP_PATCH))) + { + ft_type |= NGX_HTTP_UPSTREAM_FT_NON_IDEMPOTENT; + } - if (rc == NGX_OK) { - u->cache_status = NGX_HTTP_CACHE_STALE; - rc = ngx_http_upstream_cache_send(r, u); - } + if (u->peer.tries == 0 + || ((u->conf->next_upstream & ft_type) != ft_type) + || (u->request_sent && r->request_body_no_buffering) + || (timeout && ngx_current_msec - u->peer.start_time >= timeout)) + { +#if (NGX_HTTP_CACHE) - ngx_http_upstream_finalize_request(r, u, rc); - return; + if (u->cache_status == NGX_HTTP_CACHE_EXPIRED + && (u->conf->cache_use_stale & ft_type)) + { + ngx_int_t rc; + + rc = u->reinit_request(r); + + if (rc == NGX_OK) { + u->cache_status = NGX_HTTP_CACHE_STALE; + rc = ngx_http_upstream_cache_send(r, u); } -#endif - ngx_http_upstream_finalize_request(r, u, status); + ngx_http_upstream_finalize_request(r, u, rc); return; } +#endif + + ngx_http_upstream_finalize_request(r, u, status); + return; } if (u->peer.connection) { @@ -4068,7 +4187,8 @@ if (!u->header_sent || rc == NGX_HTTP_REQUEST_TIME_OUT - || rc == NGX_HTTP_CLIENT_CLOSED_REQUEST) + || rc == NGX_HTTP_CLIENT_CLOSED_REQUEST + || (u->pipe && u->pipe->downstream_error)) { ngx_http_finalize_request(r, rc); return; | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/http/ngx_http_upstream.h ^ |
@@ -29,6 +29,7 @@ #define NGX_HTTP_UPSTREAM_FT_UPDATING 0x00000400 #define NGX_HTTP_UPSTREAM_FT_BUSY_LOCK 0x00000800 #define NGX_HTTP_UPSTREAM_FT_MAX_WAITING 0x00001000 +#define NGX_HTTP_UPSTREAM_FT_NON_IDEMPOTENT 0x00002000 #define NGX_HTTP_UPSTREAM_FT_NOLIVE 0x40000000 #define NGX_HTTP_UPSTREAM_FT_OFF 0x80000000 @@ -281,7 +282,7 @@ ngx_uint_t no_port; /* unsigned no_port:1 */ ngx_uint_t naddrs; - ngx_addr_t *addrs; + ngx_resolver_addr_t *addrs; struct sockaddr *sockaddr; socklen_t socklen; | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/http/v2/ngx_http_v2.c ^ |
@@ -2503,8 +2503,8 @@ ngx_http_v2_srv_conf_t *h2scf; ngx_http_v2_out_frame_t *frame; - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, - "http2 send SETTINGS frame"); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "http2 send SETTINGS frame ack:%ui", ack); frame = ngx_palloc(h2c->pool, sizeof(ngx_http_v2_out_frame_t)); if (frame == NULL) { @@ -2595,6 +2595,10 @@ ngx_buf_t *buf; ngx_http_v2_out_frame_t *frame; + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "http2 send WINDOW_UPDATE frame sid:%ui, window:%uz", + sid, window); + frame = ngx_http_v2_get_frame(h2c, NGX_HTTP_V2_WINDOW_UPDATE_SIZE, NGX_HTTP_V2_WINDOW_UPDATE_FRAME, NGX_HTTP_V2_NO_FLAG, sid); @@ -2619,6 +2623,10 @@ ngx_buf_t *buf; ngx_http_v2_out_frame_t *frame; + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "http2 send RST_STREAM frame sid:%ui, status:%uz", + sid, status); + frame = ngx_http_v2_get_frame(h2c, NGX_HTTP_V2_RST_STREAM_SIZE, NGX_HTTP_V2_RST_STREAM_FRAME, NGX_HTTP_V2_NO_FLAG, sid); @@ -2642,6 +2650,9 @@ ngx_buf_t *buf; ngx_http_v2_out_frame_t *frame; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "http2 send GOAWAY frame, status:%uz", status); + frame = ngx_http_v2_get_frame(h2c, NGX_HTTP_V2_GOAWAY_SIZE, NGX_HTTP_V2_GOAWAY_FRAME, NGX_HTTP_V2_NO_FLAG, 0); | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/os/unix/ngx_darwin_init.c ^ |
@@ -23,6 +23,7 @@ ngx_readv_chain, ngx_udp_unix_recv, ngx_unix_send, + ngx_udp_unix_send, #if (NGX_HAVE_SENDFILE) ngx_darwin_sendfile_chain, NGX_IO_SENDFILE | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/os/unix/ngx_errno.h ^ |
@@ -25,6 +25,7 @@ #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 | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/os/unix/ngx_files.c ^ |
@@ -12,9 +12,11 @@ #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 ssize_t ngx_writev_file(ngx_file_t *file, ngx_array_t *vec, size_t size, +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); @@ -76,38 +78,39 @@ #if (NGX_THREADS) typedef struct { - ngx_fd_t fd; - u_char *buf; - size_t size; - off_t offset; - - size_t read; - ngx_err_t err; -} ngx_thread_read_ctx_t; + 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_thread_task_t **taskp, ngx_file_t *file, u_char *buf, - size_t size, off_t offset, ngx_pool_t *pool) +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_read_ctx_t *ctx; + 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 = *taskp; + task = file->thread_task; if (task == NULL) { - task = ngx_thread_task_alloc(pool, sizeof(ngx_thread_read_ctx_t)); + task = ngx_thread_task_alloc(pool, sizeof(ngx_thread_file_ctx_t)); if (task == NULL) { return NGX_ERROR; } - task->handler = ngx_thread_read_handler; - - *taskp = task; + file->thread_task = task; } ctx = task->ctx; @@ -115,15 +118,25 @@ 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->read; + return ctx->nbytes; } + task->handler = ngx_thread_read_handler; + + ctx->write = 0; + ctx->fd = file->fd; ctx->buf = buf; ctx->size = size; @@ -142,7 +155,7 @@ static void ngx_thread_read_handler(void *data, ngx_log_t *log) { - ngx_thread_read_ctx_t *ctx = data; + ngx_thread_file_ctx_t *ctx = data; ssize_t n; @@ -154,7 +167,7 @@ ctx->err = ngx_errno; } else { - ctx->read = n; + ctx->nbytes = n; ctx->err = 0; } @@ -276,17 +289,13 @@ } -#define NGX_IOVS 8 - ssize_t ngx_write_chain_to_file(ngx_file_t *file, ngx_chain_t *cl, off_t offset, ngx_pool_t *pool) { - u_char *prev; - size_t size; ssize_t total, n; - ngx_array_t vec; - struct iovec *iov, iovs[NGX_IOVS]; + ngx_iovec_t vec; + struct iovec iovs[NGX_IOVS_PREALLOCATE]; /* use pwrite() if there is the only buf in a chain */ @@ -298,46 +307,18 @@ total = 0; - vec.elts = iovs; - vec.size = sizeof(struct iovec); - vec.nalloc = NGX_IOVS; - vec.pool = pool; + vec.iovs = iovs; + vec.nalloc = NGX_IOVS_PREALLOCATE; do { - prev = NULL; - iov = NULL; - size = 0; - - vec.nelts = 0; - /* create the iovec and coalesce the neighbouring bufs */ - - while (cl && vec.nelts < IOV_MAX) { - if (prev == cl->buf->pos) { - iov->iov_len += cl->buf->last - cl->buf->pos; - - } else { - iov = ngx_array_push(&vec); - if (iov == NULL) { - return NGX_ERROR; - } - - iov->iov_base = (void *) cl->buf->pos; - iov->iov_len = cl->buf->last - cl->buf->pos; - } - - size += cl->buf->last - cl->buf->pos; - prev = cl->buf->last; - cl = cl->next; - } + cl = ngx_chain_to_iovec(&vec, cl); /* use pwrite() if there is the only iovec buffer */ - if (vec.nelts == 1) { - iov = vec.elts; - - n = ngx_write_file(file, (u_char *) iov[0].iov_base, - iov[0].iov_len, offset); + 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; @@ -346,7 +327,7 @@ return total + n; } - n = ngx_writev_file(file, &vec, size, offset); + n = ngx_writev_file(file, &vec, offset); if (n == NGX_ERROR) { return n; @@ -361,20 +342,61 @@ } +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) { + 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_array_t *vec, size_t size, off_t offset) +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, size, offset); + "writev: %d, %uz, %O", file->fd, vec->size, offset); #if (NGX_HAVE_PWRITEV) eintr: - n = pwritev(file->fd, vec->elts, vec->nelts, offset); + n = pwritev(file->fd, vec->iovs, vec->count, offset); if (n == -1) { err = ngx_errno; @@ -390,10 +412,10 @@ return NGX_ERROR; } - if ((size_t) n != size) { + 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, size); + file->name.data, n, vec->size); return NGX_ERROR; } @@ -411,7 +433,7 @@ eintr: - n = writev(file->fd, vec->elts, vec->nelts); + n = writev(file->fd, vec->iovs, vec->count); if (n == -1) { err = ngx_errno; @@ -427,10 +449,10 @@ return NGX_ERROR; } - if ((size_t) n != size) { + 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, size); + file->name.data, n, vec->size); return NGX_ERROR; } @@ -444,6 +466,132 @@ } +#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) { | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/os/unix/ngx_files.h ^ |
@@ -385,8 +385,10 @@ #endif #if (NGX_THREADS) -ssize_t ngx_thread_read(ngx_thread_task_t **taskp, ngx_file_t *file, - u_char *buf, size_t size, off_t offset, ngx_pool_t *pool); +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 | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/os/unix/ngx_freebsd_init.c ^ |
@@ -32,6 +32,7 @@ ngx_readv_chain, ngx_udp_unix_recv, ngx_unix_send, + ngx_udp_unix_send, #if (NGX_HAVE_SENDFILE) ngx_freebsd_sendfile_chain, NGX_IO_SENDFILE | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/os/unix/ngx_freebsd_sendfile_chain.c ^ |
@@ -247,6 +247,19 @@ #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++; | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/os/unix/ngx_linux_init.c ^ |
@@ -18,6 +18,7 @@ ngx_readv_chain, ngx_udp_unix_recv, ngx_unix_send, + ngx_udp_unix_send, #if (NGX_HAVE_SENDFILE) ngx_linux_sendfile_chain, NGX_IO_SENDFILE | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/os/unix/ngx_linux_sendfile_chain.c ^ |
@@ -292,6 +292,19 @@ } } + 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); @@ -315,7 +328,6 @@ ngx_linux_sendfile_thread(ngx_connection_t *c, ngx_buf_t *file, size_t size, size_t *sent) { - ngx_uint_t flags; ngx_event_t *wev; ngx_thread_task_t *task; ngx_linux_sendfile_ctx_t *ctx; @@ -343,29 +355,60 @@ if (task->event.complete) { task->event.complete = 0; - if (ctx->err && ctx->err != NGX_EAGAIN) { + if (ctx->err == NGX_EAGAIN) { + *sent = 0; + + if (wev->complete) { + return NGX_DONE; + } + + 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; + } + *sent = ctx->sent; - return (ctx->sent == ctx->size) ? NGX_DONE : NGX_AGAIN; + if (ctx->sent == ctx->size || wev->complete) { + return NGX_DONE; + } + + return NGX_AGAIN; + } + + 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 + */ + + *sent = 0; + + return NGX_OK; } ctx->file = file; ctx->socket = c->fd; ctx->size = size; - if (wev->active) { - flags = (ngx_event_flags & NGX_USE_CLEAR_EVENT) ? NGX_CLEAR_EVENT - : NGX_LEVEL_EVENT; - - if (ngx_del_event(wev, NGX_WRITE_EVENT, flags) == NGX_ERROR) { - return NGX_ERROR; - } - } + wev->complete = 0; if (file->file->thread_handler(task, file->file) != NGX_OK) { return NGX_ERROR; | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/os/unix/ngx_os.h ^ |
@@ -28,6 +28,7 @@ ngx_recv_chain_pt recv_chain; ngx_recv_pt udp_recv; ngx_send_pt send; + ngx_send_pt udp_send; ngx_send_chain_pt send_chain; ngx_uint_t flags; } ngx_os_io_t; @@ -47,6 +48,7 @@ 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); #if (IOV_MAX > 64) | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/os/unix/ngx_posix_config.h ^ |
@@ -128,7 +128,7 @@ #endif -#if (NGX_HAVE_DEVPOLL) +#if (NGX_HAVE_DEVPOLL) && !(NGX_TEST_BUILD_DEVPOLL) #include <sys/ioctl.h> #include <sys/devpoll.h> #endif | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/os/unix/ngx_posix_init.c ^ |
@@ -24,6 +24,7 @@ ngx_readv_chain, ngx_udp_unix_recv, ngx_unix_send, + ngx_udp_unix_send, ngx_writev_chain, 0 }; | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/os/unix/ngx_solaris_init.c ^ |
@@ -19,6 +19,7 @@ ngx_readv_chain, ngx_udp_unix_recv, ngx_unix_send, + ngx_udp_unix_send, #if (NGX_HAVE_SENDFILE) ngx_solaris_sendfilev_chain, NGX_IO_SENDFILE | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/os/unix/ngx_solaris_sendfilev_chain.c ^ |
@@ -48,6 +48,7 @@ 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; @@ -77,6 +78,7 @@ fd = SFV_FD_SELF; prev = NULL; fprev = 0; + file = NULL; sfv = NULL; eintr = 0; sent = 0; @@ -153,6 +155,7 @@ sfv->sfv_len = (size_t) size; } + file = cl->buf; fprev = cl->buf->file_pos + size; send += size; } @@ -179,6 +182,26 @@ 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, | ||
[+] | Added | nginx-1.9.13.tar.gz/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; + } + } +} | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/stream/ngx_stream.c ^ |
@@ -275,8 +275,11 @@ port = ports->elts; for (i = 0; i < ports->nelts; i++) { - if (p == port[i].port && sa->sa_family == port[i].family) { + if (p == port[i].port + && listen->type == port[i].type + && sa->sa_family == port[i].family) + { /* a port is already in the port list */ port = &port[i]; @@ -292,6 +295,7 @@ } port->family = sa->sa_family; + port->type = listen->type; port->port = p; if (ngx_array_init(&port->addrs, cf->temp_pool, 2, @@ -364,6 +368,7 @@ ls->addr_ntop = 1; ls->handler = ngx_stream_init_connection; ls->pool_size = 256; + ls->type = addr[i].opt.type; cscf = addr->opt.ctx->srv_conf[ngx_stream_core_module.ctx_index]; @@ -373,6 +378,8 @@ ls->backlog = addr[i].opt.backlog; + ls->wildcard = addr[i].opt.wildcard; + ls->keepalive = addr[i].opt.so_keepalive; #if (NGX_HAVE_KEEPALIVE_TUNABLE) ls->keepidle = addr[i].opt.tcp_keepidle; | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/stream/ngx_stream.h ^ |
@@ -66,6 +66,7 @@ int tcp_keepcnt; #endif int backlog; + int type; } ngx_stream_listen_t; @@ -102,6 +103,7 @@ typedef struct { int family; + int type; in_port_t port; ngx_array_t addrs; /* array of ngx_stream_conf_addr_t */ } ngx_stream_conf_port_t; | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/stream/ngx_stream_core_module.c ^ |
@@ -252,7 +252,7 @@ in_port_t port; ngx_str_t *value; ngx_url_t u; - ngx_uint_t i; + ngx_uint_t i, backlog; struct sockaddr *sa; struct sockaddr_in *sin; ngx_stream_listen_t *ls; @@ -343,6 +343,7 @@ ls->socklen = u.socklen; ls->backlog = NGX_LISTEN_BACKLOG; + ls->type = SOCK_STREAM; ls->wildcard = u.wildcard; ls->ctx = cf->ctx; @@ -350,8 +351,17 @@ ls->ipv6only = 1; #endif + backlog = 0; + for (i = 2; i < cf->args->nelts; i++) { +#if !(NGX_WIN32) + if (ngx_strcmp(value[i].data, "udp") == 0) { + ls->type = SOCK_DGRAM; + continue; + } +#endif + if (ngx_strcmp(value[i].data, "bind") == 0) { ls->bind = 1; continue; @@ -367,6 +377,8 @@ return NGX_CONF_ERROR; } + backlog = 1; + continue; } @@ -530,5 +542,21 @@ return NGX_CONF_ERROR; } + if (ls->type == SOCK_DGRAM) { + if (backlog) { + return "\"backlog\" parameter is incompatible with \"udp\""; + } + +#if (NGX_STREAM_SSL) + if (ls->ssl) { + return "\"ssl\" parameter is incompatible with \"udp\""; + } +#endif + + if (ls->so_keepalive) { + return "\"so_keepalive\" parameter is incompatible with \"udp\""; + } + } + return NGX_CONF_OK; } | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/stream/ngx_stream_handler.c ^ |
@@ -52,7 +52,7 @@ * is the "*:port" wildcard so getsockname() is needed to determine * the server address. * - * AcceptEx() already gave this address. + * AcceptEx() and recvmsg() already gave this address. */ if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) { @@ -137,8 +137,9 @@ len = ngx_sock_ntop(c->sockaddr, c->socklen, text, NGX_SOCKADDR_STRLEN, 1); - ngx_log_error(NGX_LOG_INFO, c->log, 0, "*%uA client %*s connected to %V", - c->number, len, text, &addr_conf->addr_text); + ngx_log_error(NGX_LOG_INFO, c->log, 0, "*%uA %sclient %*s connected to %V", + c->number, c->type == SOCK_DGRAM ? "udp " : "", + len, text, &addr_conf->addr_text); c->log->connection = c->number; c->log->handler = ngx_stream_log_error; @@ -166,7 +167,10 @@ } } - if (cscf->tcp_nodelay && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) { + if (c->type == SOCK_STREAM + && cscf->tcp_nodelay + && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) + { ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, "tcp_nodelay"); tcp_nodelay = 1; @@ -325,7 +329,8 @@ s = log->data; - p = ngx_snprintf(buf, len, ", client: %V, server: %V", + p = ngx_snprintf(buf, len, ", %sclient: %V, server: %V", + s->connection->type == SOCK_DGRAM ? "udp " : "", &s->connection->addr_text, &s->connection->listening->addr_text); len -= p - buf; | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/stream/ngx_stream_proxy_module.c ^ |
@@ -17,6 +17,7 @@ size_t buffer_size; size_t upload_rate; size_t download_rate; + ngx_uint_t responses; ngx_uint_t next_upstream_tries; ngx_flag_t next_upstream; ngx_flag_t proxy_protocol; @@ -54,7 +55,7 @@ ngx_uint_t from_upstream); static void ngx_stream_proxy_connect_handler(ngx_event_t *ev); static ngx_int_t ngx_stream_proxy_test_connect(ngx_connection_t *c); -static ngx_int_t ngx_stream_proxy_process(ngx_stream_session_t *s, +static void ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, ngx_uint_t do_write); static void ngx_stream_proxy_next_upstream(ngx_stream_session_t *s); static void ngx_stream_proxy_finalize(ngx_stream_session_t *s, ngx_int_t rc); @@ -167,6 +168,13 @@ offsetof(ngx_stream_proxy_srv_conf_t, download_rate), NULL }, + { ngx_string("proxy_responses"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_proxy_srv_conf_t, responses), + NULL }, + { ngx_string("proxy_next_upstream"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, @@ -351,6 +359,7 @@ u->peer.log_error = NGX_ERROR_ERR; u->peer.local = pscf->local; + u->peer.type = c->type; uscf = pscf->upstream; @@ -370,6 +379,14 @@ u->proxy_protocol = pscf->proxy_protocol; u->start_sec = ngx_time(); + c->write->handler = ngx_stream_proxy_downstream_handler; + c->read->handler = ngx_stream_proxy_downstream_handler; + + if (c->type == SOCK_DGRAM) { + ngx_stream_proxy_connect(s); + return; + } + p = ngx_pnalloc(c->pool, pscf->buffer_size); if (p == NULL) { ngx_stream_proxy_finalize(s, NGX_ERROR); @@ -381,9 +398,6 @@ u->downstream_buf.pos = p; u->downstream_buf.last = p; - c->write->handler = ngx_stream_proxy_downstream_handler; - c->read->handler = ngx_stream_proxy_downstream_handler; - if (u->proxy_protocol #if (NGX_STREAM_SSL) && pscf->ssl == NULL @@ -406,8 +420,8 @@ u->proxy_protocol = 0; } - if (ngx_stream_proxy_process(s, 0, 0) != NGX_OK) { - return; + if (c->read->ready) { + ngx_post_event(c->read, &ngx_posted_events); } ngx_stream_proxy_connect(s); @@ -488,7 +502,10 @@ cscf = ngx_stream_get_module_srv_conf(s, ngx_stream_core_module); - if (cscf->tcp_nodelay && pc->tcp_nodelay == NGX_TCP_NODELAY_UNSET) { + if (pc->type == SOCK_STREAM + && cscf->tcp_nodelay + && pc->tcp_nodelay == NGX_TCP_NODELAY_UNSET) + { ngx_log_debug0(NGX_LOG_DEBUG_STREAM, pc->log, 0, "tcp_nodelay"); tcp_nodelay = 1; @@ -516,7 +533,7 @@ pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); #if (NGX_STREAM_SSL) - if (pscf->ssl && pc->ssl == NULL) { + if (pc->type == SOCK_STREAM && pscf->ssl && pc->ssl == NULL) { ngx_stream_proxy_ssl_init_connection(s); return; } @@ -535,7 +552,9 @@ handler = c->log->handler; c->log->handler = NULL; - ngx_log_error(NGX_LOG_INFO, c->log, 0, "proxy %V connected to %V", + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "%sproxy %V connected to %V", + pc->type == SOCK_DGRAM ? "udp " : "", &str, u->peer.name); c->log->handler = handler; @@ -544,24 +563,36 @@ c->log->action = "proxying connection"; - p = ngx_pnalloc(c->pool, pscf->buffer_size); - if (p == NULL) { - ngx_stream_proxy_finalize(s, NGX_ERROR); - return; + if (u->upstream_buf.start == NULL) { + p = ngx_pnalloc(c->pool, pscf->buffer_size); + if (p == NULL) { + ngx_stream_proxy_finalize(s, NGX_ERROR); + return; + } + + u->upstream_buf.start = p; + u->upstream_buf.end = p + pscf->buffer_size; + u->upstream_buf.pos = p; + u->upstream_buf.last = p; } - u->upstream_buf.start = p; - u->upstream_buf.end = p + pscf->buffer_size; - u->upstream_buf.pos = p; - u->upstream_buf.last = p; + if (c->type == SOCK_DGRAM) { + s->received = c->buffer->last - c->buffer->pos; + u->downstream_buf = *c->buffer; + + if (pscf->responses == 0) { + pc->read->ready = 0; + pc->read->eof = 1; + } + } u->connected = 1; pc->read->handler = ngx_stream_proxy_upstream_handler; pc->write->handler = ngx_stream_proxy_upstream_handler; - if (ngx_stream_proxy_process(s, 1, 0) != NGX_OK) { - return; + if (pc->read->ready || pc->read->eof) { + ngx_post_event(pc->read, &ngx_posted_events); } ngx_stream_proxy_process(s, 0, 1); @@ -894,11 +925,15 @@ s = c->data; u = s->upstream; + c = s->connection; + pc = u->peer.connection; + + pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); + if (ev->timedout) { + ev->timedout = 0; if (ev->delayed) { - - ev->timedout = 0; ev->delayed = 0; if (!ev->ready) { @@ -907,20 +942,35 @@ return; } - if (u->connected) { - pc = u->peer.connection; - - if (!c->read->delayed && !pc->read->delayed) { - pscf = ngx_stream_get_module_srv_conf(s, - ngx_stream_proxy_module); - ngx_add_timer(c->write, pscf->timeout); - } + if (u->connected && !c->read->delayed && !pc->read->delayed) { + ngx_add_timer(c->write, pscf->timeout); } return; } } else { + if (s->connection->type == SOCK_DGRAM) { + if (pscf->responses == NGX_MAX_INT32_VALUE) { + + /* + * successfully terminate timed out UDP session + * with unspecified number of responses + */ + + pc->read->ready = 0; + pc->read->eof = 1; + + ngx_stream_proxy_process(s, 1, 0); + return; + } + + if (u->received == 0) { + ngx_stream_proxy_next_upstream(s); + return; + } + } + ngx_connection_error(c, NGX_ETIMEDOUT, "connection timed out"); ngx_stream_proxy_finalize(s, NGX_DECLINED); return; @@ -1019,7 +1069,7 @@ } -static ngx_int_t +static void ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, ngx_uint_t do_write) { @@ -1039,6 +1089,21 @@ c = s->connection; pc = u->connected ? u->peer.connection : NULL; + if (c->type == SOCK_DGRAM && (ngx_terminate || ngx_exiting)) { + + /* socket is already closed on worker shutdown */ + + handler = c->log->handler; + c->log->handler = NULL; + + ngx_log_error(NGX_LOG_INFO, c->log, 0, "disconnected on shutdown"); + + c->log->handler = handler; + + ngx_stream_proxy_finalize(s, NGX_OK); + return; + } + pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); if (from_upstream) { @@ -1066,9 +1131,19 @@ n = dst->send(dst, b->pos, size); + if (n == NGX_AGAIN && dst->shared) { + /* cannot wait on a shared socket */ + n = NGX_ERROR; + } + if (n == NGX_ERROR) { + if (c->type == SOCK_DGRAM && !from_upstream) { + ngx_stream_proxy_next_upstream(s); + return; + } + ngx_stream_proxy_finalize(s, NGX_DECLINED); - return NGX_ERROR; + return; } if (n > 0) { @@ -1118,6 +1193,12 @@ } } + if (c->type == SOCK_DGRAM && ++u->responses == pscf->responses) + { + src->read->ready = 0; + src->read->eof = 1; + } + *received += n; b->last += n; do_write = 1; @@ -1126,6 +1207,11 @@ } if (n == NGX_ERROR) { + if (c->type == SOCK_DGRAM && u->received == 0) { + ngx_stream_proxy_next_upstream(s); + return; + } + src->read->eof = 1; } } @@ -1138,29 +1224,30 @@ c->log->handler = NULL; ngx_log_error(NGX_LOG_INFO, c->log, 0, - "%s disconnected" + "%s%s disconnected" ", bytes from/to client:%O/%O" ", bytes from/to upstream:%O/%O", + src->type == SOCK_DGRAM ? "udp " : "", from_upstream ? "upstream" : "client", s->received, c->sent, u->received, pc ? pc->sent : 0); c->log->handler = handler; ngx_stream_proxy_finalize(s, NGX_OK); - return NGX_DONE; + return; } flags = src->read->eof ? NGX_CLOSE_EVENT : 0; - if (ngx_handle_read_event(src->read, flags) != NGX_OK) { + if (!src->shared && ngx_handle_read_event(src->read, flags) != NGX_OK) { ngx_stream_proxy_finalize(s, NGX_ERROR); - return NGX_ERROR; + return; } if (dst) { - if (ngx_handle_write_event(dst->write, 0) != NGX_OK) { + if (!dst->shared && ngx_handle_write_event(dst->write, 0) != NGX_OK) { ngx_stream_proxy_finalize(s, NGX_ERROR); - return NGX_ERROR; + return; } if (!c->read->delayed && !pc->read->delayed) { @@ -1170,8 +1257,6 @@ ngx_del_timer(c->write); } } - - return NGX_OK; } @@ -1333,6 +1418,7 @@ conf->buffer_size = NGX_CONF_UNSET_SIZE; conf->upload_rate = NGX_CONF_UNSET_SIZE; conf->download_rate = NGX_CONF_UNSET_SIZE; + conf->responses = NGX_CONF_UNSET_UINT; conf->next_upstream_tries = NGX_CONF_UNSET_UINT; conf->next_upstream = NGX_CONF_UNSET; conf->proxy_protocol = NGX_CONF_UNSET; @@ -1375,6 +1461,9 @@ ngx_conf_merge_size_value(conf->download_rate, prev->download_rate, 0); + ngx_conf_merge_uint_value(conf->responses, + prev->responses, NGX_MAX_INT32_VALUE); + ngx_conf_merge_uint_value(conf->next_upstream_tries, prev->next_upstream_tries, 0); | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/stream/ngx_stream_upstream.c ^ |
@@ -388,7 +388,7 @@ uscf->port = u->port; uscf->no_port = u->no_port; - if (u->naddrs == 1) { + if (u->naddrs == 1 && (u->port || u->family == AF_UNIX)) { uscf->servers = ngx_array_create(cf->pool, 1, sizeof(ngx_stream_upstream_server_t)); if (uscf->servers == NULL) { | ||
[+] | Changed | nginx-1.9.13.tar.gz/src/stream/ngx_stream_upstream.h ^ |
@@ -84,6 +84,7 @@ ngx_buf_t upstream_buf; off_t received; time_t start_sec; + ngx_uint_t responses; #if (NGX_STREAM_SSL) ngx_str_t ssl_name; #endif |