comparison src/event/modules/ngx_epoll_module.c @ 6806:75dbab4ea930

Events: improved error event handling for UDP sockets. Normally, the epoll module calls the read and write handlers depending on whether EPOLLIN and EPOLLOUT are reported by epoll_wait(). No error processing is done in the module, the handlers are expected to get an error when doing I/O. If an error event is reported without EPOLLIN and EPOLLOUT, the module set both EPOLLIN and EPOLLOUT to ensure the error event is handled at least in one active handler. This works well unless the error is delivered along with only one of EPOLLIN or EPOLLOUT, and the corresponding handler does not do any I/O. For example, it happened when getting EPOLLERR|EPOLLOUT from epoll_wait() upon receiving "ICMP port unreachable" while proxying UDP. As the write handler had nothing to send it was not able to detect and log an error, and did not switch to the next upstream. The fix is to unconditionally set EPOLLIN and EPOLLOUT in case of an error event. In the aforementioned case, this causes the read handler to be called which does recv() and detects an error. In addition to the epoll module, analogous changes were made in devpoll/eventport/poll.
author Dmitry Volyntsev <xeioex@nginx.com>
date Mon, 21 Nov 2016 16:03:42 +0300
parents 6acaa638fa07
children a72886067bbb
comparison
equal deleted inserted replaced
6805:52bd8cc17f34 6806:75dbab4ea930
861 861
862 if (revents & (EPOLLERR|EPOLLHUP)) { 862 if (revents & (EPOLLERR|EPOLLHUP)) {
863 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0, 863 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
864 "epoll_wait() error on fd:%d ev:%04XD", 864 "epoll_wait() error on fd:%d ev:%04XD",
865 c->fd, revents); 865 c->fd, revents);
866
867 /*
868 * if the error events were returned, add EPOLLIN and EPOLLOUT
869 * to handle the events at least in one active handler
870 */
871
872 revents |= EPOLLIN|EPOLLOUT;
866 } 873 }
867 874
868 #if 0 875 #if 0
869 if (revents & ~(EPOLLIN|EPOLLOUT|EPOLLERR|EPOLLHUP)) { 876 if (revents & ~(EPOLLIN|EPOLLOUT|EPOLLERR|EPOLLHUP)) {
870 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, 877 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
871 "strange epoll_wait() events fd:%d ev:%04XD", 878 "strange epoll_wait() events fd:%d ev:%04XD",
872 c->fd, revents); 879 c->fd, revents);
873 } 880 }
874 #endif 881 #endif
875
876 if ((revents & (EPOLLERR|EPOLLHUP))
877 && (revents & (EPOLLIN|EPOLLOUT)) == 0)
878 {
879 /*
880 * if the error events were returned without EPOLLIN or EPOLLOUT,
881 * then add these flags to handle the events at least in one
882 * active handler
883 */
884
885 revents |= EPOLLIN|EPOLLOUT;
886 }
887 882
888 if ((revents & EPOLLIN) && rev->active) { 883 if ((revents & EPOLLIN) && rev->active) {
889 884
890 #if (NGX_HAVE_EPOLLRDHUP) 885 #if (NGX_HAVE_EPOLLRDHUP)
891 if (revents & EPOLLRDHUP) { 886 if (revents & EPOLLRDHUP) {