int32_t rtmp_server_handshake_done(rtmp_session_t *session) { rtmp_log(RTMP_LOG_INFO,"[%d]handshake done!",session->sid); session->in_chain = rtmp_core_alloc_chain(session,session->c->pool, session->in_chunk_size); if (session->in_chain == NULL) { rtmp_session_destroy(session); return RTMP_FAILED; } return rtmp_core_cycle(session); }
void *SWITCH_THREAD_FUNC rtmp_io_tcp_thread(switch_thread_t *thread, void *obj) { rtmp_io_tcp_t *io = (rtmp_io_tcp_t*)obj; io->base.running = 1; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s: I/O Thread starting\n", io->base.profile->name); while(io->base.running) { const switch_pollfd_t *fds; int32_t numfds; int32_t i; switch_status_t status; switch_mutex_lock(io->mutex); status = switch_pollset_poll(io->pollset, 500000, &numfds, &fds); switch_mutex_unlock(io->mutex); if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_TIMEOUT) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "pollset_poll failed\n"); continue; } else if (status == SWITCH_STATUS_TIMEOUT) { switch_cond_next(); } for (i = 0; i < numfds; i++) { if (!fds[i].client_data) { switch_socket_t *newsocket; if (switch_socket_accept(&newsocket, io->listen_socket, io->base.pool) != SWITCH_STATUS_SUCCESS) { if (io->base.running) { /* Don't spam the logs if we are shutting down */ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Socket Error [%s]\n", strerror(errno)); } else { return NULL; } } else { rtmp_session_t *rsession; if (switch_socket_opt_set(newsocket, SWITCH_SO_NONBLOCK, TRUE)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Couldn't set socket as non-blocking\n"); } if (switch_socket_opt_set(newsocket, SWITCH_SO_TCP_NODELAY, 1)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Couldn't disable Nagle.\n"); } if (rtmp_session_request(io->base.profile, &rsession) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "RTMP session request failed\n"); switch_socket_close(newsocket); } else { switch_sockaddr_t *addr = NULL; char ipbuf[200]; /* Create out private data and attach it to the rtmp session structure */ rtmp_tcp_io_private_t *pvt = switch_core_alloc(rsession->pool, sizeof(*pvt)); rsession->io_private = pvt; pvt->socket = newsocket; switch_socket_create_pollfd(&pvt->pollfd, newsocket, SWITCH_POLLIN | SWITCH_POLLERR, rsession, rsession->pool); switch_pollset_add(io->pollset, pvt->pollfd); switch_buffer_create_dynamic(&pvt->sendq, 512, 1024, 0); /* Get the remote address/port info */ switch_socket_addr_get(&addr, SWITCH_TRUE, newsocket); switch_get_addr(ipbuf, sizeof(ipbuf), addr); rsession->remote_address = switch_core_strdup(rsession->pool, ipbuf); rsession->remote_port = switch_sockaddr_get_port(addr); switch_log_printf(SWITCH_CHANNEL_UUID_LOG(rsession->uuid), SWITCH_LOG_INFO, "Rtmp connection from %s:%i\n", rsession->remote_address, rsession->remote_port); } } } else { rtmp_session_t *rsession = (rtmp_session_t*)fds[i].client_data; rtmp_tcp_io_private_t *io_pvt = (rtmp_tcp_io_private_t*)rsession->io_private; if (fds[i].rtnevents & SWITCH_POLLOUT && switch_buffer_inuse(io_pvt->sendq) > 0) { /* Send as much remaining data as possible */ switch_size_t sendlen; const void *ptr; sendlen = switch_buffer_peek_zerocopy(io_pvt->sendq, &ptr); switch_socket_send_nonblock(io_pvt->socket, ptr, &sendlen); switch_buffer_toss(io_pvt->sendq, sendlen); if (switch_buffer_inuse(io_pvt->sendq) == 0) { /* Remove our fd from OUT polling */ rtmp_tcp_alter_pollfd(rsession, SWITCH_FALSE); } } else if (fds[i].rtnevents & SWITCH_POLLIN && rtmp_handle_data(rsession) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_UUID_LOG(rsession->uuid), SWITCH_LOG_DEBUG, "Closing socket\n"); switch_mutex_lock(io->mutex); switch_pollset_remove(io->pollset, io_pvt->pollfd); switch_mutex_unlock(io->mutex); switch_socket_close(io_pvt->socket); io_pvt->socket = NULL; rtmp_session_destroy(&rsession); } } } } io->base.running = -1; switch_socket_close(io->listen_socket); return NULL; }
void rtmp_chain_send(rtmp_event_t *ev) { rtmp_connection_t *conn; rtmp_session_t *session; mem_buf_t *sbuf,wbuf; int32_t rc; uint32_t out_rear,out_front; mem_buf_chain_t *chain; rtmp_message_t *msg; conn = ev->data; session = conn->data; if (ev->timeout) { rtmp_log(RTMP_LOG_WARNING,"[%d]send timeout!",conn->fd); rtmp_session_destroy(session); return; } if (ev->timer_set) { rtmp_event_del_timer(ev); } if (ev->active) { rtmp_event_delete(ev,EVENT_WRITE); } while (1) { out_rear = session->out_rear; out_front = session->out_front; if (session->out_chunk == NULL) { if (out_rear == out_front) { return ; } msg = & session->out_message[out_rear]; rc = rtmp_send_buf(conn->fd,&msg->head,NULL); if (rc == SOCK_ERROR) { rtmp_log(RTMP_LOG_ERR,"[%d]send error:%p,%d",session->sid,rc); return; } if (rc == SOCK_EAGAIN) { rtmp_log(RTMP_LOG_DEBUG,"[%d]send again:%d",session->sid,rc); if (!ev->active) { rtmp_event_add(ev,EVENT_WRITE); } rtmp_event_add_timer(ev,6000); return ; } session->out_chunk = msg->chain; if (session->out_chunk == NULL) { rtmp_log(RTMP_LOG_WARNING,"[%d]pick null message", session->sid); session->out_rear = (out_rear + 1) % session->out_queue; continue; } session->out_last = session->out_chunk->chunk.last; } while (session->out_chunk) { sbuf = & session->out_chunk->chunk; if ((session->out_last < sbuf->last) || (session->out_last >= sbuf->end)) { rtmp_log(RTMP_LOG_WARNING,"[%d]send error chunk",session->sid); session->out_last = sbuf->last; } wbuf.buf = sbuf->buf; wbuf.last = session->out_last; wbuf.end = sbuf->end; rtmp_log(RTMP_LOG_DEBUG,"[%d]send (%p,%d) bytes",session->sid, session->out_last,wbuf.end - wbuf.last); rc = rtmp_send_buf(conn->fd,&wbuf,NULL); if (rc == SOCK_ERROR) { rtmp_log(RTMP_LOG_ERR,"[%d]send error:%p,%d",session->sid,rc); return; } if (rc == SOCK_EAGAIN) { rtmp_log(RTMP_LOG_DEBUG,"[%d]send again:%d",session->sid,rc); session->out_last = wbuf.last; if (!ev->active) { rtmp_event_add(ev,EVENT_WRITE); } rtmp_event_add_timer(ev,6000); return ; } session->ping_sent = 0; chain = session->out_chunk->next; session->out_chunk = chain; if (chain) { session->out_last = chain->chunk.last; } } chain = session->out_message[out_rear].chain; rtmp_log(RTMP_LOG_INFO,"[%d]send a message",session->sid); rtmp_core_free_chain(session,session->chunk_pool,chain); session->out_message[out_rear].chain = NULL; session->out_last = NULL; session->out_rear = (out_rear + 1) % session->out_queue; } return ; }
void rtmp_core_chunk_recv(rtmp_event_t *ev) { rtmp_connection_t *conn; rtmp_session_t *session; int32_t rc,hr,n; conn = ev->data; session = conn->data; if (ev->timer_set) { rtmp_event_del_timer(ev); } if (ev->timeout) { if (session->ping_sent == 1) { rtmp_log(RTMP_LOG_INFO,"[%d]recv timeout!",session->sid); rtmp_session_destroy(session); return; } session->ping_sent = 1; rtmp_send_ping_request(session); rtmp_event_add_timer(ev,session->ping_timeout); return; } for (;;) { rc = rtmp_recv_buf(conn->fd,&session->in_chain->chunk,&n); if (rc == SOCK_ERROR) { rtmp_log(RTMP_LOG_ERR,"[%d]recv error[%d]!", session->sid,sock_errno); rtmp_session_destroy(session); return ; } session->ping_sent = 0; hr = rtmp_core_update_inbytes(session,NULL,(uint32_t)n); if(hr != RTMP_OK) { rtmp_session_destroy(session); return ; } /*rtmp_core_handle_recv*/ hr = rtmp_core_handle_recv(session); if (hr != RTMP_OK) { rtmp_session_destroy(session); return ; } if(rc == SOCK_EAGAIN) { if (!ev->active) { rtmp_event_add(conn->read,EVENT_READ); } rtmp_event_add_timer(ev,session->ping_timeout); break; } } }