Nginx Intro - ngx_process_events_and_timers


1. ngx_process_events_and_timers


void
ngx_process_events_and_timers(ngx_cycle_t *cycle)
{
    ngx_uint_t  flags;
    ngx_msec_t  timer, delta;


    if (ngx_timer_resolution) {
        timer = NGX_TIMER_INFINITE;
        flags = 0;


    } else {
        timer = ngx_event_find_timer();
        flags = NGX_UPDATE_TIME;


#if (NGX_WIN32)


        /* handle signals from master in case of network inactivity */


        if (timer == NGX_TIMER_INFINITE || timer > 500) {
            timer = 500;
        }


#endif
    }


    if (ngx_use_accept_mutex) {
        if (ngx_accept_disabled > 0) {
            ngx_accept_disabled--;


        } else {
            if (ngx_trylock_accept_mutex(cycle) == NGX_ERROR) {
                return;
            }


            if (ngx_accept_mutex_held) {
                flags |= NGX_POST_EVENTS;


            } else {
                if (timer == NGX_TIMER_INFINITE
                    || timer > ngx_accept_mutex_delay)
                {
                    timer = ngx_accept_mutex_delay;
                }
            }
        }
    }


    delta = ngx_current_msec;


    (void) ngx_process_events(cycle, timer, flags);  // call ngx_epoll_process_events process network events


    delta = ngx_current_msec - delta;


    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                   "timer delta: %M", delta);


    ngx_event_process_posted(cycle, &ngx_posted_accept_events);    // process posted accept events


    if (ngx_accept_mutex_held) {
        ngx_shmtx_unlock(&ngx_accept_mutex);
    }


    if (delta) {
        ngx_event_expire_timers();          // process expired timer events
    }


    ngx_event_process_posted(cycle, &ngx_posted_events);     // process general posted events
}



2. epoll process network events


static ngx_int_t
ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags)
{
    int                events;
    uint32_t           revents;
    ngx_int_t          instance, i;
    ngx_uint_t         level;
    ngx_err_t          err;
    ngx_event_t       *rev, *wev;
    ngx_queue_t       *queue;
    ngx_connection_t  *c;


    /* NGX_TIMER_INFINITE == INFTIM */


    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                   "epoll timer: %M", timer);


    events = epoll_wait(ep, event_list, (int) nevents, timer);


    err = (events == -1) ? ngx_errno : 0;


    if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
        ngx_time_update();
    }


    if (err) {
        if (err == NGX_EINTR) {


            if (ngx_event_timer_alarm) {
                ngx_event_timer_alarm = 0;
                return NGX_OK;
            }


            level = NGX_LOG_INFO;


        } else {
            level = NGX_LOG_ALERT;
        }


        ngx_log_error(level, cycle->log, err, "epoll_wait() failed");
        return NGX_ERROR;
    }


    if (events == 0) {
        if (timer != NGX_TIMER_INFINITE) {
            return NGX_OK;
        }


        ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                      "epoll_wait() returned no events without timeout");
        return NGX_ERROR;
    }


    for (i = 0; i < events; i++) {
        c = event_list[i].data.ptr;


        instance = (uintptr_t) c & 1;
        c = (ngx_connection_t *) ((uintptr_t) c & (uintptr_t) ~1);


        rev = c->read;


        if (c->fd == -1 || rev->instance != instance) {  // 过期读事件处理


            /*
             * the stale event from a file descriptor
             * that was just closed in this iteration
             */


            ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                           "epoll: stale event %p", c);
            continue;
        }


        revents = event_list[i].events;


        ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                       "epoll: fd:%d ev:%04XD d:%p",
                       c->fd, revents, event_list[i].data.ptr);


        if (revents & (EPOLLERR|EPOLLHUP)) {
            ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                           "epoll_wait() error on fd:%d ev:%04XD",
                           c->fd, revents);
        }


#if 0
        if (revents & ~(EPOLLIN|EPOLLOUT|EPOLLERR|EPOLLHUP)) {
            ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                          "strange epoll_wait() events fd:%d ev:%04XD",
                          c->fd, revents);
        }
#endif


        if ((revents & (EPOLLERR|EPOLLHUP))
             && (revents & (EPOLLIN|EPOLLOUT)) == 0)
        {
            /*
             * if the error events were returned without EPOLLIN or EPOLLOUT,
             * then add these flags to handle the events at least in one
             * active handler
             */


            revents |= EPOLLIN|EPOLLOUT;
        }


        if ((revents & EPOLLIN) && rev->active) {


#if (NGX_HAVE_EPOLLRDHUP)
            if (revents & EPOLLRDHUP) {
                rev->pending_eof = 1;
            }


            rev->available = 1;
#endif


            rev->ready = 1;


            if (flags & NGX_POST_EVENTS) {   // post read event to posted accept events queue or posted general events queue
                queue = rev->accept ? &ngx_posted_accept_events
                                    : &ngx_posted_events;


                ngx_post_event(rev, queue);


            } else {  // immediately process this event
                rev->handler(rev);
            }
        }


        wev = c->write;


        if ((revents & EPOLLOUT) && wev->active) {


            if (c->fd == -1 || wev->instance != instance) {  // 过期的写事件处理


                /*
                 * the stale event from a file descriptor
                 * that was just closed in this iteration
                 */


                ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                               "epoll: stale event %p", c);
                continue;
            }


            wev->ready = 1;
#if (NGX_THREADS)
            wev->complete = 1;
#endif


            if (flags & NGX_POST_EVENTS) {  // post write event to posted general events queue
                ngx_post_event(wev, &ngx_posted_events);


            } else {
                wev->handler(wev);
            }
        }
    }


    return NGX_OK;
}


3. ngx_event_process_posted

void
ngx_event_process_posted(ngx_cycle_t *cycle, ngx_queue_t *posted)
{
    ngx_queue_t  *q;
    ngx_event_t  *ev;


    while (!ngx_queue_empty(posted)) {


        q = ngx_queue_head(posted);
        ev = ngx_queue_data(q, ngx_event_t, queue);


        ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                      "posted event %p", ev);


        ngx_delete_posted_event(ev);


        ev->handler(ev);
    }
}


3.1 ngx_event_process_init

static ngx_int_t
ngx_event_process_init(ngx_cycle_t *cycle)
{
    ngx_uint_t           m, i;
    ngx_event_t         *rev, *wev;
    ngx_listening_t     *ls;
    ngx_connection_t    *c, *next, *old;
    ngx_core_conf_t     *ccf;
    ngx_event_conf_t    *ecf;
    ngx_event_module_t  *module;


    ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
    ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module);


    if (ccf->master && ccf->worker_processes > 1 && ecf->accept_mutex) {
        ngx_use_accept_mutex = 1;
        ngx_accept_mutex_held = 0;
        ngx_accept_mutex_delay = ecf->accept_mutex_delay;


    } else {
        ngx_use_accept_mutex = 0;
    }


#if (NGX_WIN32)


    /*
     * disable accept mutex on win32 as it may cause deadlock if
     * grabbed by a process which can't accept connections
     */


    ngx_use_accept_mutex = 0;


#endif


    ngx_queue_init(&ngx_posted_accept_events);
    ngx_queue_init(&ngx_posted_events);


    if (ngx_event_timer_init(cycle->log) == NGX_ERROR) {
        return NGX_ERROR;
    }


    for (m = 0; cycle->modules[m]; m++) {
        if (cycle->modules[m]->type != NGX_EVENT_MODULE) {
            continue;
        }


        if (cycle->modules[m]->ctx_index != ecf->use) {
            continue;
        }


        module = cycle->modules[m]->ctx;


        if (module->actions.init(cycle, ngx_timer_resolution) != NGX_OK) {
            /* fatal */
            exit(2);
        }


        break;
    }


#if !(NGX_WIN32)


    if (ngx_timer_resolution && !(ngx_event_flags & NGX_USE_TIMER_EVENT)) {
        struct sigaction  sa;
        struct itimerval  itv;


        ngx_memzero(&sa, sizeof(struct sigaction));
        sa.sa_handler = ngx_timer_signal_handler;
        sigemptyset(&sa.sa_mask);


        if (sigaction(SIGALRM, &sa, NULL) == -1) {
            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                          "sigaction(SIGALRM) failed");
            return NGX_ERROR;
        }


        itv.it_interval.tv_sec = ngx_timer_resolution / 1000;
        itv.it_interval.tv_usec = (ngx_timer_resolution % 1000) * 1000;
        itv.it_value.tv_sec = ngx_timer_resolution / 1000;
        itv.it_value.tv_usec = (ngx_timer_resolution % 1000 ) * 1000;


        if (setitimer(ITIMER_REAL, &itv, NULL) == -1) {
            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                          "setitimer() failed");
        }
    }


    if (ngx_event_flags & NGX_USE_FD_EVENT) {
        struct rlimit  rlmt;


        if (getrlimit(RLIMIT_NOFILE, &rlmt) == -1) {
            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                          "getrlimit(RLIMIT_NOFILE) failed");
            return NGX_ERROR;
        }


        cycle->files_n = (ngx_uint_t) rlmt.rlim_cur;


        cycle->files = ngx_calloc(sizeof(ngx_connection_t *) * cycle->files_n,
                                  cycle->log);
        if (cycle->files == NULL) {
            return NGX_ERROR;
        }
    }


#else


    if (ngx_timer_resolution && !(ngx_event_flags & NGX_USE_TIMER_EVENT)) {
        ngx_log_error(NGX_LOG_WARN, cycle->log, 0,
                      "the \"timer_resolution\" directive is not supported "
                      "with the configured event method, ignored");
        ngx_timer_resolution = 0;
    }


#endif


    cycle->connections =
        ngx_alloc(sizeof(ngx_connection_t) * cycle->connection_n, cycle->log);
    if (cycle->connections == NULL) {
        return NGX_ERROR;
    }


    c = cycle->connections;


    cycle->read_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n,
                                   cycle->log);
    if (cycle->read_events == NULL) {
        return NGX_ERROR;
    }


    rev = cycle->read_events;
    for (i = 0; i < cycle->connection_n; i++) {
        rev[i].closed = 1;
        rev[i].instance = 1;
    }


    cycle->write_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n,
                                    cycle->log);
    if (cycle->write_events == NULL) {
        return NGX_ERROR;
    }


    wev = cycle->write_events;
    for (i = 0; i < cycle->connection_n; i++) {
        wev[i].closed = 1;
    }


    i = cycle->connection_n;
    next = NULL;


    do {
        i--;


        c[i].data = next;
        c[i].read = &cycle->read_events[i];
        c[i].write = &cycle->write_events[i];
        c[i].fd = (ngx_socket_t) -1;


        next = &c[i];
    } while (i);


    cycle->free_connections = next;
    cycle->free_connection_n = cycle->connection_n;


    /* for each listening socket */


    ls = cycle->listening.elts;
    for (i = 0; i < cycle->listening.nelts; i++) {


#if (NGX_HAVE_REUSEPORT)
        if (ls[i].reuseport && ls[i].worker != ngx_worker) {
            continue;
        }
#endif


        c = ngx_get_connection(ls[i].fd, cycle->log);


        if (c == NULL) {
            return NGX_ERROR;
        }


        c->type = ls[i].type;
        c->log = &ls[i].log;


        c->listening = &ls[i];
        ls[i].connection = c;


        rev = c->read;


        rev->log = c->log;
        rev->accept = 1;


#if (NGX_HAVE_DEFERRED_ACCEPT)
        rev->deferred_accept = ls[i].deferred_accept;
#endif


        if (!(ngx_event_flags & NGX_USE_IOCP_EVENT)) {
            if (ls[i].previous) {


                /*
                 * delete the old accept events that were bound to
                 * the old cycle read events array
                 */


                old = ls[i].previous->connection;


                if (ngx_del_event(old->read, NGX_READ_EVENT, NGX_CLOSE_EVENT)
                    == NGX_ERROR)
                {
                    return NGX_ERROR;
                }


                old->fd = (ngx_socket_t) -1;
            }
        }


#if (NGX_WIN32)


        if (ngx_event_flags & NGX_USE_IOCP_EVENT) {
            ngx_iocp_conf_t  *iocpcf;


            rev->handler = ngx_event_acceptex;


            if (ngx_use_accept_mutex) {
                continue;
            }


            if (ngx_add_event(rev, 0, NGX_IOCP_ACCEPT) == NGX_ERROR) {
                return NGX_ERROR;
            }


            ls[i].log.handler = ngx_acceptex_log_error;


            iocpcf = ngx_event_get_conf(cycle->conf_ctx, ngx_iocp_module);
            if (ngx_event_post_acceptex(&ls[i], iocpcf->post_acceptex)
                == NGX_ERROR)
            {
                return NGX_ERROR;
            }


        } else {
            rev->handler = ngx_event_accept;


            if (ngx_use_accept_mutex) {
                continue;
            }


            if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) {
                return NGX_ERROR;
            }
        }


#else

       // read event process handler register
        rev->handler = (c->type == SOCK_STREAM) ? ngx_event_accept
                                                : ngx_event_recvmsg;


#if (NGX_HAVE_REUSEPORT)


        if (ls[i].reuseport) {
            if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) {
                return NGX_ERROR;
            }


            continue;
        }


#endif


        if (ngx_use_accept_mutex) {
            continue;
        }


#if (NGX_HAVE_EPOLLEXCLUSIVE)


        if ((ngx_event_flags & NGX_USE_EPOLL_EVENT)
            && ccf->worker_processes > 1)
        {
            if (ngx_add_event(rev, NGX_READ_EVENT, NGX_EXCLUSIVE_EVENT)
                == NGX_ERROR)
            {
                return NGX_ERROR;
            }


            continue;
        }


#endif


        if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) {
            return NGX_ERROR;
        }


#endif


    }


    return NGX_OK;
}


3.2 ngx_event_accept

void
ngx_event_accept(ngx_event_t *ev)
{
    socklen_t          socklen;
    ngx_err_t          err;
    ngx_log_t         *log;
    ngx_uint_t         level;
    ngx_socket_t       s;
    ngx_event_t       *rev, *wev;
    ngx_sockaddr_t     sa;
    ngx_listening_t   *ls;
    ngx_connection_t  *c, *lc;
    ngx_event_conf_t  *ecf;
#if (NGX_HAVE_ACCEPT4)
    static ngx_uint_t  use_accept4 = 1;
#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,
                   "accept on %V, ready: %d", &ls->addr_text, ev->available);


    do {
        socklen = sizeof(ngx_sockaddr_t);


#if (NGX_HAVE_ACCEPT4)
        if (use_accept4) {
            s = accept4(lc->fd, &sa.sockaddr, &socklen, SOCK_NONBLOCK);
        } else {
            s = accept(lc->fd, &sa.sockaddr, &socklen);
        }
#else
        s = accept(lc->fd, &sa.sockaddr, &socklen);
#endif


        if (s == (ngx_socket_t) -1) {
            err = ngx_socket_errno;


            if (err == NGX_EAGAIN) {
                ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, err,
                               "accept() not ready");
                return;
            }


            level = NGX_LOG_ALERT;


            if (err == NGX_ECONNABORTED) {
                level = NGX_LOG_ERR;


            } else if (err == NGX_EMFILE || err == NGX_ENFILE) {
                level = NGX_LOG_CRIT;
            }


#if (NGX_HAVE_ACCEPT4)
            ngx_log_error(level, ev->log, err,
                          use_accept4 ? "accept4() failed" : "accept() failed");


            if (use_accept4 && err == NGX_ENOSYS) {
                use_accept4 = 0;
                ngx_inherited_nonblocking = 0;
                continue;
            }
#else
            ngx_log_error(level, ev->log, err, "accept() failed");
#endif


            if (err == NGX_ECONNABORTED) {
                if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
                    ev->available--;
                }


                if (ev->available) {
                    continue;
                }
            }


            if (err == NGX_EMFILE || err == NGX_ENFILE) {
                if (ngx_disable_accept_events((ngx_cycle_t *) ngx_cycle, 1)
                    != NGX_OK)
                {
                    return;
                }


                if (ngx_use_accept_mutex) {
                    if (ngx_accept_mutex_held) {
                        ngx_shmtx_unlock(&ngx_accept_mutex);
                        ngx_accept_mutex_held = 0;
                    }


                    ngx_accept_disabled = 1;


                } else {
                    ngx_add_timer(ev, ecf->accept_mutex_delay);
                }
            }


            return;
        }


#if (NGX_STAT_STUB)
        (void) ngx_atomic_fetch_add(ngx_stat_accepted, 1);
#endif


        ngx_accept_disabled = ngx_cycle->connection_n / 8
                              - ngx_cycle->free_connection_n;


        c = ngx_get_connection(s, ev->log);


        if (c == NULL) {
            if (ngx_close_socket(s) == -1) {
                ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
                              ngx_close_socket_n " failed");
            }


            return;
        }


        c->type = SOCK_STREAM;


#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, socklen);
        if (c->sockaddr == NULL) {
            ngx_close_accepted_connection(c);
            return;
        }


        ngx_memcpy(c->sockaddr, &sa, socklen);


        log = ngx_palloc(c->pool, sizeof(ngx_log_t));
        if (log == NULL) {
            ngx_close_accepted_connection(c);
            return;
        }


        /* set a blocking mode for iocp and non-blocking mode for others */


        if (ngx_inherited_nonblocking) {
            if (ngx_event_flags & NGX_USE_IOCP_EVENT) {
                if (ngx_blocking(s) == -1) {
                    ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
                                  ngx_blocking_n " failed");
                    ngx_close_accepted_connection(c);
                    return;
                }
            }


        } else {
            if (!(ngx_event_flags & NGX_USE_IOCP_EVENT)) {
                if (ngx_nonblocking(s) == -1) {
                    ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno,
                                  ngx_nonblocking_n " failed");
                    ngx_close_accepted_connection(c);
                    return;
                }
            }
        }


        *log = ls->log;


        c->recv = ngx_recv;
        c->send = ngx_send;
        c->recv_chain = ngx_recv_chain;
        c->send_chain = ngx_send_chain;


        c->log = log;
        c->pool->log = log;


        c->socklen = socklen;
        c->listening = ls;
        c->local_sockaddr = ls->sockaddr;
        c->local_socklen = ls->socklen;


#if (NGX_HAVE_UNIX_DOMAIN)
        if (c->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;
#endif
        }
#endif


        rev = c->read;
        wev = c->write;


        wev->ready = 1;


        if (ngx_event_flags & NGX_USE_IOCP_EVENT) {
            rev->ready = 1;
        }


        if (ev->deferred_accept) {
            rev->ready = 1;
#if (NGX_HAVE_KQUEUE)
            rev->available = 1;
#endif
        }


        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_debug3(NGX_LOG_DEBUG_EVENT, log, 0,
                           "*%uA accept: %V fd:%d", c->number, &addr, s);
        }


        }
#endif


        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;
            }
        }


        log->data = NULL;
        log->handler = NULL;


        ls->handler(c);   //  call ngx_rtmp_init_connection


        if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
            ev->available--;
        }


    } while (ev->available);
}


3.3 ngx_rtmp_init_connection

void
ngx_rtmp_init_connection(ngx_connection_t *c)
{
    ngx_uint_t             i;
    ngx_rtmp_port_t       *port;
    struct sockaddr       *sa;
    struct sockaddr_in    *sin;
    ngx_rtmp_in_addr_t    *addr;
    ngx_rtmp_session_t    *s;
    ngx_rtmp_addr_conf_t  *addr_conf;
    ngx_int_t              unix_socket;
#if (NGX_HAVE_INET6)
    struct sockaddr_in6   *sin6;
    ngx_rtmp_in6_addr_t   *addr6;
#endif


    ++ngx_rtmp_naccepted;


    /* find the server configuration for the address:port */


    /* AF_INET only */


    port = c->listening->servers;
    unix_socket = 0;


    if (port->naddrs > 1) {


        /*
         * There are several addresses on this port and one of them
         * is the "*:port" wildcard so getsockname() is needed to determine
         * the server address.
         *
         * AcceptEx() already gave this address.
         */


        if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) {
            ngx_rtmp_close_connection(c);
            return;
        }


        sa = c->local_sockaddr;


        switch (sa->sa_family) {


#if (NGX_HAVE_INET6)
        case AF_INET6:
            sin6 = (struct sockaddr_in6 *) sa;


            addr6 = port->addrs;


            /* the last address is "*" */


            for (i = 0; i < port->naddrs - 1; i++) {
                if (ngx_memcmp(&addr6[i].addr6, &sin6->sin6_addr, 16) == 0) {
                    break;
                }
            }


            addr_conf = &addr6[i].conf;


            break;
#endif


        case AF_UNIX:
            unix_socket = 1;


        default: /* AF_INET */
            sin = (struct sockaddr_in *) sa;


            addr = port->addrs;


            /* the last address is "*" */


            for (i = 0; i < port->naddrs - 1; i++) {
                if (addr[i].addr == sin->sin_addr.s_addr) {
                    break;
                }
            }


            addr_conf = &addr[i].conf;


            break;
        }


    } else {
        switch (c->local_sockaddr->sa_family) {


#if (NGX_HAVE_INET6)
        case AF_INET6:
            addr6 = port->addrs;
            addr_conf = &addr6[0].conf;
            break;
#endif


        case AF_UNIX:
            unix_socket = 1;


        default: /* AF_INET */
            addr = port->addrs;
            addr_conf = &addr[0].conf;
            break;
        }
    }


    ngx_log_error(NGX_LOG_INFO, c->log, 0, "*%ui client connected '%V'",
                  c->number, &c->addr_text);


    s = ngx_rtmp_init_session(c, addr_conf);
    if (s == NULL) {
        return;
    }


    /* only auto-pushed connections are
     * done through unix socket */


    s->auto_pushed = unix_socket;


    if (addr_conf->proxy_protocol) {
        ngx_rtmp_proxy_protocol(s);


    } else {
        ngx_rtmp_handshake(s);
    }
}



4. ngx_event_expire_timers

void
ngx_event_expire_timers(void)
{
    ngx_event_t        *ev;
    ngx_rbtree_node_t  *node, *root, *sentinel;


    sentinel = ngx_event_timer_rbtree.sentinel;


    for ( ;; ) {
        root = ngx_event_timer_rbtree.root;


        if (root == sentinel) {
            return;
        }


        node = ngx_rbtree_min(root, sentinel);


        /* node->key > ngx_current_time */


        if ((ngx_msec_int_t) (node->key - ngx_current_msec) > 0) {
            return;
        }


        ev = (ngx_event_t *) ((char *) node - offsetof(ngx_event_t, timer));


        ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
                       "event timer del: %d: %M",
                       ngx_event_ident(ev->data), ev->timer.key);


        ngx_rbtree_delete(&ngx_event_timer_rbtree, &ev->timer);


#if (NGX_DEBUG)
        ev->timer.left = NULL;
        ev->timer.right = NULL;
        ev->timer.parent = NULL;
#endif


        ev->timer_set = 0;


        ev->timedout = 1;


        ev->handler(ev);
    }
}

展开阅读全文

没有更多推荐了,返回首页