static void ngx_rtmp_ssl_handshake_handler(ngx_connection_t *c) { ngx_rtmp_session_t *s; ngx_event_t *rev; ngx_int_t rc; s = c->data; if (c->ssl->handshaked) { ngx_rtmp_handshake(s); return; } if (c->read->timedout) { ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "SSL handshake timed out"); ngx_rtmp_finalize_session(s); return; } if (c->read->error || c->write->error || c->error) { ngx_log_error(NGX_LOG_INFO, c->log, 0, "SSL handshake failed: c%d w%d r%d", c->error, c->write->error, c->read->error); ngx_rtmp_finalize_session(s); return; } rc = ngx_ssl_handshake(c); if (rc == NGX_AGAIN) { rev = c->read; if (!rev->timer_set) { ngx_add_timer(rev, s->timeout); } c->ssl->handler = ngx_rtmp_ssl_handshake_handler; return; } if (rc == NGX_OK) { ngx_rtmp_handshake(s); return; } ngx_rtmp_finalize_session(s); return; }
static void ngx_rtmp_proxy_protocol_recv(ngx_event_t *rev) { u_char buf[107], *p, *pp, *text; size_t len; ssize_t n; ngx_err_t err; ngx_int_t i; ngx_addr_t addr; ngx_connection_t *c; ngx_rtmp_session_t *s; c = rev->data; s = c->data; if (c->destroyed) { return; } if (rev->timedout) { ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "proxy_protocol: recv: client timed out"); c->timedout = 1; ngx_rtmp_finalize_session(s); return; } if (rev->timer_set) { ngx_del_timer(rev); } n = recv(c->fd, (char *) buf, sizeof(buf), MSG_PEEK); err = ngx_socket_errno; ngx_log_debug1(NGX_LOG_DEBUG_RTMP, c->log, 0, "recv(): %d", n); if (n == -1) { if (err == NGX_EAGAIN) { ngx_add_timer(rev, s->timeout); if (ngx_handle_read_event(c->read, 0) != NGX_OK) { ngx_rtmp_finalize_session(s); } return; } ngx_rtmp_finalize_session(s); return; } p = buf; if (n <= 8 && ngx_strncmp(p, "PROXY ", 6) != 0) { goto bad_header; } n -= 6; p += 6; ngx_memzero(&addr, sizeof(ngx_addr_t)); if (n >= 7 && ngx_strncmp(p, "UNKNOWN", 7) == 0) { n -= 7; p += 7; goto skip; } if (n < 5 || ngx_strncmp(p, "TCP", 3) != 0 || (p[3] != '4' && p[3] != '6') || p[4] != ' ') { goto bad_header; } n -= 5; p += 5; pp = ngx_strlchr(p, p + n, ' '); if (pp == NULL) { goto bad_header; } if (ngx_parse_addr(s->connection->pool, &addr, p, pp - p) != NGX_OK) { goto bad_header; } n -= pp - p; p = pp; skip: for (i = 0; i + 1 < n; i++) { if (p[i] == CR && p[i + 1] == LF) { break; } } if (i + 1 >= n) { goto bad_header; } n = p - buf + i + 2; if (c->recv(c, buf, n) != n) { goto failed; } if (addr.socklen) { text = ngx_palloc(s->connection->pool, NGX_SOCKADDR_STRLEN); if (text == NULL) { goto failed; } len = ngx_sock_ntop(addr.sockaddr, #if (nginx_version >= 1005003) addr.socklen, #endif text, NGX_SOCKADDR_STRLEN, 0); if (len == 0) { goto failed; } c->sockaddr = addr.sockaddr; c->socklen = addr.socklen; c->addr_text.data = text; c->addr_text.len = len; ngx_log_debug1(NGX_LOG_DEBUG_RTMP, c->log, 0, "proxy_protocol: remote_addr:'%V'", &c->addr_text); } ngx_rtmp_handshake(s); return; bad_header: ngx_log_error(NGX_LOG_INFO, c->log, 0, "proxy_protocol: bad header"); failed: ngx_rtmp_finalize_session(s); }
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); /* only auto-pushed connections are * done through unix socket */ s->auto_pushed = unix_socket; if (s) { ngx_rtmp_handshake(s); } }