void ngx_rtmp_client_handshake(ngx_rtmp_session_t *s, unsigned async) { ngx_connection_t *c; c = s->connection; c->read->handler = ngx_rtmp_handshake_recv; c->write->handler = ngx_rtmp_handshake_send; ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "handshake: start client handshake"); s->hs_buf = ngx_rtmp_alloc_handshake_buffer(s); s->hs_stage = NGX_RTMP_HANDSHAKE_CLIENT_SEND_CHALLENGE; if (ngx_rtmp_handshake_create_challenge(s, ngx_rtmp_client_version, &ngx_rtmp_client_partial_key) != NGX_OK) { ngx_rtmp_finalize_session(s); return; } if (async) { ngx_add_timer(c->write, s->timeout); if (ngx_handle_write_event(c->write, 0) != NGX_OK) { ngx_rtmp_finalize_session(s); } return; } ngx_rtmp_handshake_send(c->write); }
static void ngx_rtmp_handshake_send(ngx_event_t *wev) { ngx_int_t n; ngx_connection_t *c; ngx_rtmp_session_t *s; ngx_buf_t *b; c = wev->data; s = c->hls ? c->hls_data : c->data; if (c->destroyed) { return; } if (wev->timedout) { ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "handshake_send: send: client timed out, finish session."); c->timedout = 1; ngx_rtmp_finalize_session(s); return; } if (wev->timer_set) { ngx_del_timer(wev); } b = s->hs_buf; while(b->pos != b->last) { n = c->send(c, b->pos, b->last - b->pos); if (n == NGX_ERROR) { ngx_rtmp_finalize_session(s); ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "handshake_send: c->send: error"); return; } if (n == NGX_AGAIN || n == 0) { ngx_add_timer(c->write, s->timeout); if (ngx_handle_write_event(c->write, 0) != NGX_OK) { ngx_rtmp_finalize_session(s); ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "handshake_send: NGX_AGAIN "); } return; } b->pos += n; } if (wev->active) { ngx_del_event(wev, NGX_WRITE_EVENT, 0); } ++s->hs_stage; ngx_log_debug1(NGX_LOG_DEBUG_RTMP, c->log, 0, "ngx_rtmp_handshake_send:handshake: stage %ui", s->hs_stage); switch (s->hs_stage) { case NGX_RTMP_HANDSHAKE_SERVER_SEND_RESPONSE: if (s->hs_old) { ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "handshake_send: old-style response"); s->hs_buf->pos = s->hs_buf->start + 1; s->hs_buf->last = s->hs_buf->end; } else if (ngx_rtmp_handshake_create_response(s) != NGX_OK) { ngx_log_error(NGX_LOG_INFO, c->log, 0, "handshake_send: response error"); ngx_rtmp_finalize_session(s); return; } ngx_rtmp_handshake_send(wev); break; case NGX_RTMP_HANDSHAKE_SERVER_RECV_RESPONSE: s->hs_buf->pos = s->hs_buf->last = s->hs_buf->start + 1; ngx_rtmp_handshake_recv(c->read); break; case NGX_RTMP_HANDSHAKE_CLIENT_RECV_CHALLENGE: s->hs_buf->pos = s->hs_buf->last = s->hs_buf->start; ngx_rtmp_handshake_recv(c->read); break; case NGX_RTMP_HANDSHAKE_CLIENT_DONE: ngx_rtmp_handshake_done(s); break; } }
static void ngx_rtmp_handshake_recv(ngx_event_t *rev) { ssize_t n; ngx_connection_t *c; ngx_rtmp_session_t *s; ngx_buf_t *b; c = rev->data; s = c->hls ? c->hls_data : c->data; if (c->destroyed) { return; } if (rev->timedout) { ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "handshake_recv: recv: client timed out"); c->timedout = 1; ngx_rtmp_finalize_session(s); return; } if (rev->timer_set) { ngx_del_timer(rev); } b = s->hs_buf; while (b->last != b->end) { n = c->recv(c, b->last, b->end - b->last); if (n == NGX_ERROR || n == 0) { ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "handshake_recv: c->recv error"); ngx_rtmp_finalize_session(s); return; } if (n == NGX_AGAIN) { ngx_add_timer(rev, s->timeout); if (ngx_handle_read_event(c->read, 0) != NGX_OK) { ngx_rtmp_finalize_session(s); ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "handshake_recv: NGX_AGAIN, ngx_rtmp_finalize_session"); } ngx_log_debug0(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "handshake_recv: NGX_AGAIN, return"); return; } b->last += n; } if (rev->active) { ngx_del_event(rev, NGX_READ_EVENT, 0); } ++s->hs_stage; ngx_log_debug1(NGX_LOG_DEBUG_RTMP, c->log, 0, "ngx_rtmp_handshake_recv:handshake: stage %ui", s->hs_stage); switch (s->hs_stage) { case NGX_RTMP_HANDSHAKE_SERVER_SEND_CHALLENGE: if (ngx_rtmp_handshake_parse_challenge(s, &ngx_rtmp_client_partial_key, &ngx_rtmp_server_full_key) != NGX_OK) { ngx_log_error(NGX_LOG_INFO, c->log, 0, "handshake: error parsing challenge"); ngx_rtmp_finalize_session(s); return; } if (s->hs_old) { ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "handshake: old-style challenge"); s->hs_buf->pos = s->hs_buf->start; s->hs_buf->last = s->hs_buf->end; } else if (ngx_rtmp_handshake_create_challenge(s, ngx_rtmp_server_version, &ngx_rtmp_server_partial_key) != NGX_OK) { ngx_log_error(NGX_LOG_INFO, c->log, 0, "handshake: error creating challenge"); ngx_rtmp_finalize_session(s); return; } ngx_rtmp_handshake_send(c->write); break; case NGX_RTMP_HANDSHAKE_SERVER_DONE: ngx_rtmp_handshake_done(s); break; case NGX_RTMP_HANDSHAKE_CLIENT_RECV_RESPONSE: if (ngx_rtmp_handshake_parse_challenge(s, &ngx_rtmp_server_partial_key, &ngx_rtmp_client_full_key) != NGX_OK) { ngx_log_error(NGX_LOG_INFO, c->log, 0, "handshake: error parsing challenge"); ngx_rtmp_finalize_session(s); return; } s->hs_buf->pos = s->hs_buf->last = s->hs_buf->start + 1; ngx_rtmp_handshake_recv(c->read); break; case NGX_RTMP_HANDSHAKE_CLIENT_SEND_RESPONSE: if (ngx_rtmp_handshake_create_response(s) != NGX_OK) { ngx_log_error(NGX_LOG_INFO, c->log, 0, "handshake: response error"); ngx_rtmp_finalize_session(s); return; } ngx_rtmp_handshake_send(c->write); break; } }