void rtp_transport_close(RTP_transport *transport) { port_pair pair; switch (transport->trans_mode) { case RTP_OVER_TCP: g_event_remove((GEvent*)transport->passby); g_event_unref((GEvent*)transport->passby); /* fall through */ case RTP_OVER_UDP: pair.RTP = get_local_port(transport->rtp_sock); pair.RTCP = get_local_port(transport->rtcp_sock); put_port_pair(NULL, &pair); Sock_close(transport->rtp_sock); Sock_close(transport->rtcp_sock); break; case RTP_OVER_RTSP: g_event_unref((GEvent*)transport->passby); break; default: break; } }
/** * @brief Free a RTSP_interleaved instance * * @param element Instance to destroy and free * @param user_data The loop to stop libev I/O * * @internal This function should only be called through * g_slist_foreach() by @ref interleaved_free_list. * * @see interleaved_setup_transport */ static void interleaved_free(gpointer element, gpointer user_data) { struct ev_loop *loop = (struct ev_loop *)user_data; RTSP_interleaved *intlvd = (RTSP_interleaved *)element; Sock_close(intlvd->rtp.local); ev_io_stop(loop, &intlvd->rtp.ev_io_listen); Sock_close(intlvd->rtcp.local); ev_io_stop(loop, &intlvd->rtcp.ev_io_listen); g_slice_free(RTSP_interleaved, element); }
gboolean interleaved_setup_transport(RTSP_Client *rtsp, RTP_transport *transport, int rtp_ch, int rtcp_ch) { RTSP_interleaved *intlvd = NULL; Sock *sock_pair[2][2]; //unsigned buffer_size = 0; // RTP local sockpair if ( Sock_socketpair(sock_pair[0]) < 0) { fnc_log(FNC_LOG_ERR, "Cannot create AF_LOCAL socketpair for rtp\n"); return false; } // RTCP local sockpair if ( Sock_socketpair(sock_pair[1]) < 0) { fnc_log(FNC_LOG_ERR, "Cannot create AF_LOCAL socketpair for rtcp\n"); Sock_close(sock_pair[0][0]); Sock_close(sock_pair[0][1]); return false; } intlvd = g_slice_new0(RTSP_interleaved); transport->rtp_sock = sock_pair[0][0]; intlvd->rtp.local = sock_pair[0][1]; /* Jmkn: Not necessary to increase the buffer for socketpair, * because we send a 1.4 Kbytes packet each time */ /* buffer_size = increase_sock_buffer_to(transport->rtp_sock, SO_SNDBUF, RTP_BUF_SIZE); fnc_log(FNC_LOG_VERBOSE,"[rtsp] Set rtp data socket send buffer size to %u", buffer_size); */ transport->rtcp_sock = sock_pair[1][0]; intlvd->rtcp.local = sock_pair[1][1]; // copy stream number in rtp_transport struct transport->rtp_ch = intlvd->rtp.channel = rtp_ch; transport->rtcp_ch = intlvd->rtcp.channel = rtcp_ch; interleaved_setup_callbacks(rtsp, intlvd); rtsp->interleaved = g_slist_prepend(rtsp->interleaved, intlvd); return true; }
/** * Closes a transport linked to a session * @param session the RTP session for which to close the transport */ static void rtp_transport_close(RTP_session * session) { port_pair pair; pair.RTP = get_local_port(session->transport.rtp_sock); pair.RTCP = get_local_port(session->transport.rtcp_sock); ev_periodic_stop(session->srv->loop, &session->transport.rtp_writer); ev_io_stop(session->srv->loop, &session->transport.rtcp_reader); switch (session->transport.rtp_sock->socktype) { case UDP: RTP_release_port_pair(session->srv, &pair); default: break; } Sock_close(session->transport.rtp_sock); Sock_close(session->transport.rtcp_sock); }
static int close_sock(int fd) { perr.error = 0; int res = Sock_close(fd, &perr); if (res == -1) { REprintf("socket error: %s\n", strerror(perr.error)); return -1; } return 0; }
/** * @brief Handle client disconnection and free resources * * @param loop The event loop where the event was issued * @param w The async event object * @param revents Unused * * This event is triggered when a client disconnects or is forcefully * disconnected. It stops the other events from running, and frees all * the remaining resources for the client itself. */ static void client_ev_disconnect_handler(struct ev_loop *loop, ev_async *w, int revents) { RTSP_Client *rtsp = (RTSP_Client*)w->data; GString *outbuf = NULL; feng *srv = rtsp->srv; ev_io_stop(srv->loop, &rtsp->ev_io_read); ev_io_stop(srv->loop, &rtsp->ev_io_write); ev_async_stop(srv->loop, &rtsp->ev_sig_disconnect); ev_timer_stop(srv->loop, &rtsp->ev_timeout); Sock_close(rtsp->sock); srv->connection_count--; rtsp_session_free(rtsp->session); r_close(rtsp->cached_resource); interleaved_free_list(rtsp); /* Remove the output queue */ while( (outbuf = g_queue_pop_tail(rtsp->out_queue)) ) g_string_free(outbuf, TRUE); g_queue_free(rtsp->out_queue); g_byte_array_free(rtsp->input, true); g_slice_free(RTSP_Client, rtsp); fnc_log(FNC_LOG_INFO, "[client] Client removed"); demuxer_stsw_global_uninit(); sleep(1); exit(0); }
Sock * Sock_connect(char *host, char *port, Sock *binded, sock_type socktype, sock_flags ssl_flag) { Sock *s; char remote_host[128]; /*Unix Domain is largest*/ char local_host[128]; /*Unix Domain is largest*/ int sockfd = -1; struct sockaddr *sa_p = NULL; socklen_t sa_len = 0; int32_t local_port; int32_t remote_port; #if HAVE_SSL SSL *ssl_con; #endif if(binded) { sockfd = binded->fd; } if (sock_connect(host, port, &sockfd, socktype)) { net_log(NET_LOG_ERR, "Sock_connect() failure.\n"); return NULL; } #if HAVE_SSL if(ssl_flag & IS_SSL) { if (sock_SSL_connect(&ssl_con)) net_log (NET_LOG_ERR, "Sock_connect() failure in SSL init.\n"); sock_close(sockfd); return NULL; } else #endif if (binded) { s = binded; free(s->local_host); s->local_host = NULL; free(s->remote_host); s->remote_host = NULL; } else if (!(s = calloc(1, sizeof(Sock)))) { net_log(NET_LOG_FATAL, "Unable to allocate a Sock struct in Sock_connect().\n"); #if HAVE_SSL if(ssl_flag & IS_SSL) sock_SSL_close(ssl_con); #endif sock_close (sockfd); return NULL; } s->fd = sockfd; s->socktype = socktype; #if HAVE_SSL if(ssl_flag & IS_SSL) s->ssl = ssl_con; #endif s->flags = ssl_flag; sa_p = (struct sockaddr *) &(s->local_stg); sa_len = sizeof(struct sockaddr_storage); if(getsockname(s->fd, sa_p, &sa_len)) { net_log(NET_LOG_ERR, "Unable to get remote port in Sock_connect().\n"); Sock_close(s); return NULL; } if(!sock_ntop_host(sa_p, local_host, sizeof(local_host))) memset(local_host, 0, sizeof(local_host)); if (!(s->local_host = strdup(local_host))) { net_log(NET_LOG_FATAL, "Unable to allocate local host in Sock_connect().\n"); Sock_close(s); return NULL; } local_port = sock_get_port(sa_p); if(local_port < 0) { net_log(NET_LOG_ERR, "Unable to get local port in Sock_connect().\n"); Sock_close(s); return NULL; } else s->local_port = ntohs(local_port); sa_p = (struct sockaddr *) &(s->remote_stg); sa_len = sizeof(struct sockaddr_storage); if(getpeername(s->fd, sa_p, &sa_len)) { net_log(NET_LOG_ERR, "Unable to get remote address in Sock_connect().\n"); Sock_close(s); return NULL; } if(!sock_ntop_host(sa_p, remote_host, sizeof(remote_host))) memset(remote_host, 0, sizeof(remote_host)); if (!(s->remote_host = strdup(remote_host))) { net_log(NET_LOG_FATAL, "Unable to allocate remote host in Sock_connect().\n"); Sock_close(s); return NULL; } remote_port = sock_get_port(sa_p); if(remote_port < 0) { net_log(NET_LOG_ERR, "Unable to get remote port in Sock_connect().\n"); Sock_close(s); return NULL; } else s->remote_port = ntohs(remote_port); net_log(NET_LOG_DEBUG, "Socket connected between local=\"%s\":%u and " "remote=\"%s\":%u.\n", s->local_host, s->local_port, s->remote_host, s->remote_port); if(is_multicast_address(sa_p, s->remote_stg.ss_family)) { //fprintf(stderr,"IS MULTICAST\n"); if(mcast_join(s->fd, sa_p, NULL, 0, &(s->addr))!=0) { Sock_close(s); return NULL; } s->flags |= IS_MULTICAST; } return s; }
/** * @brief Handle an incoming RTSP connection * * @param loop The event loop where the incoming connection was triggered * @param w The watcher that triggered the incoming connection * @param revents Unused * * This function takes care of all the handling of an incoming RTSP * client connection: * * @li accept the new socket; * * @li checks that there is space for new connections for the current * fork; * * @li creates and sets up the @ref RTSP_Client object. * * The newly created instance is deleted by @ref * client_ev_disconnect_handler. * * @internal This function should be used as callback for an ev_io * listener. */ void rtsp_client_incoming_cb(struct ev_loop *loop, ev_io *w, int revents) { Sock *sock = w->data; feng *srv = sock->data; Sock *client_sock = NULL; ev_io *io; ev_async *async; ev_timer *timer; RTSP_Client *rtsp; client_port_pair *clients=NULL; pid_t pid; if ( (client_sock = Sock_accept(sock, NULL)) == NULL ) return; if (srv->connection_count >= ONE_FORK_MAX_CONNECTION) { Sock_close(client_sock); return; } if(!( clients = new_child_port(srv, get_remote_host(client_sock), get_remote_port(client_sock)))){ Sock_close(client_sock); return; } pid = fork(); if(pid==0){ /*clean the context of parent*/ clients->pid = getpid(); current_client = clients; //free_child_port(clients); feng_ports_cleanup(srv); feng_stop_child_watcher(srv); demuxer_stsw_global_init(); //void fnc_log_change_child(); if(srv->srvconf.log_type == FNC_LOG_FILE){ //child process can't write to parent log file fnc_log_uninit(); } rtsp = g_slice_new0(RTSP_Client); rtsp->sock = client_sock; rtsp->input = g_byte_array_new(); rtsp->out_queue = g_queue_new(); rtsp->srv = srv; rtsp->cached_resource = NULL; srv->connection_count++; client_sock->data = srv; /*install read handler*/ io = &rtsp->ev_io_read; io->data = rtsp; ev_io_init(io, rtsp_read_cb, Sock_fd(client_sock), EV_READ); ev_io_start(srv->loop, io); /* configure the write handler*/ /* to be started/stopped when necessary */ io = &rtsp->ev_io_write; io->data = rtsp; ev_io_init(io, rtsp_write_cb, Sock_fd(client_sock), EV_WRITE); fnc_log(FNC_LOG_INFO, "Incoming RTSP connection accepted on socket: %d\n", Sock_fd(client_sock)); /* install async event handler for destroy */ async = &rtsp->ev_sig_disconnect; async->data = rtsp; ev_async_init(async, client_ev_disconnect_handler); ev_async_start(srv->loop, async); /* configure a check timer, * After play, this timer would be started */ timer = &rtsp->ev_timeout; timer->data = rtsp; ev_init(timer, client_ev_timeout); timer->repeat = STREAM_TIMEOUT; }else if(pid > 0){ Sock_close(client_sock); srv->connection_count++; clients->pid = pid; fnc_log(FNC_LOG_INFO, "The child process (pid:%d) for rtsp connection (%s:%hu) is created\n", pid, clients->host, clients->port); fnc_log(FNC_LOG_INFO, "Connection reached: %d\n", srv->connection_count); add_client_list(clients); return; }else{ Sock_close(client_sock); free_child_port(clients); fnc_log(FNC_LOG_ERR, "fork faild\n"); return; } }
/** * Create a new socket accepting a new connection from a listening socket. * @param main Listening socket. * @param octx optional ssl global context * @return the newly allocated Sock */ Sock * Sock_accept(Sock *s, void * octx) { int res = -1; char remote_host[128]; /*Unix Domain is largest*/ char local_host[128]; /*Unix Domain is largest*/ int remote_port = -1; int local_port = -1; Sock *new_s = NULL; struct sockaddr *sa_p = NULL; socklen_t sa_len = 0; #if ENABLE_SSL SSL_CTX * ctx = octx; SSL *ssl_con = NULL; #endif if (!s) return NULL; if ((res = sock_accept(s->fd)) < 0) { net_log(NET_LOG_ERR, "System error in sock_accept().\n"); return NULL; } #if ENABLE_SSL if(ctx) { if( !(ssl_con = SSL_sock_accept(res, ctx)) ) { net_log(NET_LOG_ERR, "Unable to accept SSL connection.\n"); sock_close(res); return NULL; } } #endif if (!(new_s = calloc(1, sizeof(Sock)))) { net_log(NET_LOG_FATAL, "Unable to allocate a Sock struct in Sock_accept().\n"); #if ENABLE_SSL if(ctx) SSL_close_connection(ssl_con, res); #endif sock_close(res); return NULL; } new_s->fd = res; new_s->socktype = s->socktype; new_s->flags = s->flags; #if ENABLE_SSL if(ctx) new_s->ssl = ssl_con; #endif sa_p = (struct sockaddr *) &(new_s->remote_stg); sa_len = sizeof(struct sockaddr_storage); if(getpeername(res, sa_p, &sa_len)) { net_log(NET_LOG_ERR, "Unable to get remote address in Sock_accept().\n"); Sock_close(new_s); return NULL; } if(!sock_ntop_host(sa_p, remote_host, sizeof(remote_host))) memset(remote_host, 0, sizeof(remote_host)); if (!(new_s->remote_host = strdup(remote_host))) { net_log(NET_LOG_FATAL, "Unable to allocate remote host in Sock_accept().\n"); Sock_close(new_s); return NULL; } remote_port = sock_get_port(sa_p); if(remote_port < 0) { net_log(NET_LOG_ERR, "Unable to get remote port in Sock_accept().\n"); Sock_close(new_s); return NULL; } else new_s->remote_port = ntohs(remote_port); sa_p = (struct sockaddr *) &(new_s->remote_stg); sa_len = sizeof(struct sockaddr_storage); if(getsockname(res, sa_p, &sa_len)) { net_log(NET_LOG_ERR, "Unable to get remote port in Sock_accept().\n"); Sock_close(new_s); return NULL; } if(!sock_ntop_host(sa_p, local_host, sizeof(local_host))) memset(local_host, 0, sizeof(local_host)); if (!(new_s->local_host = strdup(local_host))) { net_log(NET_LOG_FATAL, "Unable to allocate local host in Sock_accept().\n"); Sock_close(new_s); return NULL; } local_port = sock_get_port(sa_p); if(local_port < 0) { net_log(NET_LOG_ERR, "Unable to get local port in Sock_accept().\n"); Sock_close(new_s); return NULL; } else new_s->local_port = ntohs(local_port); net_log(NET_LOG_DEBUG, "Socket accepted between local=\"%s\":%u and " "remote=\"%s\":%u.\n", new_s->local_host, new_s->local_port, new_s->remote_host, new_s->remote_port); return new_s; }
Sock * Sock_bind(char const *host, char const *port, Sock *sock, sock_type socktype, void * octx) { Sock *s = NULL; int sockfd = -1; struct sockaddr *sa_p; socklen_t sa_len; char local_host[128]; int local_port; #if ENABLE_SSL if ((octx)) { if(socktype != TCP) { net_log(NET_LOG_ERR, "SSL can't work on this protocol.\n"); return NULL; } } #endif if(sock) { sockfd = sock->fd; } if (sock_bind(host, port, &sockfd, socktype)) { net_log(NET_LOG_ERR, "Error in low level sock_bind().\n"); return NULL; } if (!(s = calloc(1, sizeof(Sock)))) { net_log(NET_LOG_FATAL, "Unable to allocate a Sock struct in Sock_bind().\n"); sock_close(sockfd); return NULL; } s->fd = sockfd; s->socktype = socktype; s->flags = 0; sa_p = (struct sockaddr *)&(s->local_stg); sa_len = sizeof(struct sockaddr_storage); if(getsockname(s->fd, sa_p, &sa_len) < 0) { Sock_close(s); return NULL; } if(!sock_ntop_host(sa_p, local_host, sizeof(local_host))) memset(local_host, 0, sizeof(local_host)); if (!(s->local_host = strdup(local_host))) { net_log(NET_LOG_FATAL, "Unable to allocate local host in Sock_bind().\n"); Sock_close(s); return NULL; } local_port = sock_get_port(sa_p); if(local_port < 0) { net_log(NET_LOG_ERR, "Unable to get local port in Sock_bind().\n"); Sock_close(s); return NULL; } else s->local_port = ntohs(local_port); net_log(NET_LOG_DEBUG, "Socket bound with addr=\"%s\" and port=\"%u\".\n", s->local_host, s->local_port); if(is_multicast_address(sa_p, s->local_stg.ss_family)) { if(mcast_join(s->fd, sa_p)) { Sock_close(s); return NULL; } s->flags |= IS_MULTICAST; } return s; }