📄 rtpproxy_relay.c
字号:
rtp_proxytable[freeidx].remote_ipaddr, rtp_proxytable[freeidx].remote_port); /* call to firewall API: RTCP port */ fwapi_start_rtp(rtp_proxytable[freeidx].direction, rtp_proxytable[freeidx].local_ipaddr, rtp_proxytable[freeidx].local_port + 1, rtp_proxytable[freeidx].remote_ipaddr, rtp_proxytable[freeidx].remote_port + 1); /* prepare FD set for next select operation */ rtp_recreate_fdset(); /* wakeup/signal rtp_proxythread from select() hibernation */ if (!pthread_equal(rtpproxy_tid, pthread_self())) pthread_kill(rtpproxy_tid, SIGALRM);//&&& DEBUGC(DBCLASS_RTP,"rtp_relay_start_fwd: started RTP proxy " "stream for: CallID=%s@%s [Client-ID=%s] %s #=%i idx=%i", rtp_proxytable[freeidx].callid_number, rtp_proxytable[freeidx].callid_host, rtp_proxytable[freeidx].client_id.contact, ((rtp_proxytable[freeidx].direction == DIR_INCOMING) ? "incoming RTP" : "outgoing RTP"), rtp_proxytable[freeidx].media_stream_no, freeidx);unlock_and_exit: /* unlock mutex */ pthread_mutex_unlock(&rtp_proxytable_mutex); #undef return return sts;}/* * stop a rtp stream on the proxy * * if media_stream_no == -1, all media streams will be stopped, * otherwise only the specified one. * * RETURNS * STS_SUCCESS on success * STS_FAILURE on error */int rtp_relay_stop_fwd (osip_call_id_t *callid, int rtp_direction, int media_stream_no, int nolock) { int i, sts; int retsts=STS_SUCCESS; int got_match=0; osip_call_id_t cid; if (callid == NULL) { ERROR("rtp_relay_stop_fwd: callid is NULL!"); return STS_FAILURE; } DEBUGC(DBCLASS_RTP,"rtp_relay_stop_fwd: stopping RTP proxy " "stream for: %s@%s (%s) (nolock=%i)", callid->number, callid->host, ((rtp_direction == DIR_INCOMING) ? "incoming" : "outgoing"), nolock); /* * lock mutex - only if not requested to skip the lock. * this is needed as we are also called from within * the RTP thread itself - and there we already own the lock. */ #define return is_forbidden_in_this_code_section if (nolock == 0) { pthread_mutex_lock(&rtp_proxytable_mutex); /* * !! We now have a locked MUTEX! It is forbidden to return() from * !! here up to the end of this funtion where the MUTEX is * !! unlocked again. * !! Per design, a mutex is locked (for one purpose) at *exactly one* * !! place in the code and unlocked also at *exactly one* place. * !! this minimizes the risk of deadlocks. */ } /* * wakeup/signal rtp_proxythread from select() hibernation. * This must be done here before we close the socket, otherwise * we may get an select() error later from the proxy thread that * is still hibernating in select() now. */ if (!pthread_equal(rtpproxy_tid, pthread_self())) pthread_kill(rtpproxy_tid, SIGALRM); /* * find the proper entry in rtp_proxytable * we need to loop the whole table, as there might be multiple * media streams active for the same callid (audio + video stream) * if media_stream_no == -1, all streams are stoppen, otherwise * if media_stream_no > 0 only the specified stream is stopped. */ for (i=0; i<RTPPROXY_SIZE; i++) { cid.number = rtp_proxytable[i].callid_number; cid.host = rtp_proxytable[i].callid_host; if (rtp_proxytable[i].rtp_rx_sock && (compare_callid(callid, &cid) == STS_SUCCESS) && (rtp_proxytable[i].direction == rtp_direction) && ((media_stream_no < 0) || (media_stream_no == rtp_proxytable[i].media_stream_no))) { /* close RTP sockets */ sts = close(rtp_proxytable[i].rtp_rx_sock); DEBUGC(DBCLASS_RTP,"closed socket %i for RTP stream " "%s:%s == %s:%s (idx=%i) sts=%i", rtp_proxytable[i].rtp_rx_sock, rtp_proxytable[i].callid_number, rtp_proxytable[i].callid_host, callid->number, callid->host, i, sts); if (sts < 0) { ERROR("Error in close(%i): %s nolock=%i %s:%s\n", rtp_proxytable[i].rtp_rx_sock, strerror(errno), nolock, callid->number, callid->host); } /* call to firewall API (RTP port) */ fwapi_stop_rtp(rtp_proxytable[i].direction, rtp_proxytable[i].local_ipaddr, rtp_proxytable[i].local_port, rtp_proxytable[i].remote_ipaddr, rtp_proxytable[i].remote_port); /* close RTCP socket */ sts = close(rtp_proxytable[i].rtp_con_rx_sock); DEBUGC(DBCLASS_RTP,"closed socket %i for RTCP stream sts=%i", rtp_proxytable[i].rtp_con_rx_sock, sts); if (sts < 0) { ERROR("Error in close(%i): %s nolock=%i %s:%s\n", rtp_proxytable[i].rtp_con_rx_sock, strerror(errno), nolock, callid->number, callid->host); } /* call to firewall API (RTCP port) */ fwapi_stop_rtp(rtp_proxytable[i].direction, rtp_proxytable[i].local_ipaddr, rtp_proxytable[i].local_port + 1, rtp_proxytable[i].remote_ipaddr, rtp_proxytable[i].remote_port + 1); /* clean up */ memset(&rtp_proxytable[i], 0, sizeof(rtp_proxytable[0])); got_match=1; } } /* did not find an active stream... */ if (!got_match) { DEBUGC(DBCLASS_RTP, "rtp_relay_stop_fwd: can't find active stream for %s@%s (%s)", callid->number, callid->host, ((rtp_direction == DIR_INCOMING) ? "incoming RTP" : "outgoing RTP")); retsts = STS_FAILURE; goto unlock_and_exit; } /* prepare FD set for next select operation */ rtp_recreate_fdset(); unlock_and_exit: /* * unlock mutex - only if not requested to skip the lock. * this is needed as we are also called from within * the RTP thread itself - and there we already own the lock. */ if (nolock == 0) { pthread_mutex_unlock(&rtp_proxytable_mutex); } #undef return return retsts;}/* * some sockets have been newly created or removed - * recreate the FD set for next select operation * * RETURNS * STS_SUCCESS on success (always) */static int rtp_recreate_fdset(void) { int i; FD_ZERO(&master_fdset); master_fd_max=-1; for (i=0;i<RTPPROXY_SIZE;i++) { if (rtp_proxytable[i].rtp_rx_sock != 0) { /* RTP */ FD_SET(rtp_proxytable[i].rtp_rx_sock, &master_fdset); if (rtp_proxytable[i].rtp_rx_sock > master_fd_max) { master_fd_max=rtp_proxytable[i].rtp_rx_sock; } /* RTPCP */ FD_SET(rtp_proxytable[i].rtp_con_rx_sock, &master_fdset); if (rtp_proxytable[i].rtp_con_rx_sock > master_fd_max) { master_fd_max=rtp_proxytable[i].rtp_con_rx_sock; } } } /* for i */ return STS_SUCCESS;}/* * kills the rtp_proxy thread * * RETURNS * - */static void rtpproxy_kill( void ) { void *thread_status; osip_call_id_t cid; int i, sts; /* stop any active RTP stream */ for (i=0;i<RTPPROXY_SIZE;i++) { if (rtp_proxytable[i].rtp_rx_sock != 0) { cid.number = rtp_proxytable[i].callid_number; cid.host = rtp_proxytable[i].callid_host; sts = rtp_relay_stop_fwd(&cid, rtp_proxytable[i].direction, rtp_proxytable[i].media_stream_no, LOCK_FDSET); } } /* kill the thread */ if (rtpproxy_tid) { pthread_cancel(rtpproxy_tid); pthread_kill(rtpproxy_tid, SIGALRM); pthread_join(rtpproxy_tid, &thread_status); } DEBUGC(DBCLASS_RTP,"killed RTP proxy thread"); return;}/* * match_socket * matches and cross connects two rtp_proxytable entries * (corresponds to the two data directions of one RTP stream) */static void match_socket (int rtp_proxytable_idx) { int j; int rtp_direction = rtp_proxytable[rtp_proxytable_idx].direction; int media_stream_no = rtp_proxytable[rtp_proxytable_idx].media_stream_no;/*chnnel int channel = rtp_proxytable[rtp_proxytable_idx].channel;*/ osip_call_id_t callid; callid.number = rtp_proxytable[rtp_proxytable_idx].callid_number; callid.host = rtp_proxytable[rtp_proxytable_idx].callid_host; for (j=0;(j<RTPPROXY_SIZE);j++) { osip_call_id_t cid; cid.number = rtp_proxytable[j].callid_number; cid.host = rtp_proxytable[j].callid_host; /* match on: * - same call ID * - same media stream * - opposite direction * - different client ID */ if ( (rtp_proxytable[j].rtp_rx_sock != 0) && (compare_callid(&callid, &cid) == STS_SUCCESS) && (media_stream_no == rtp_proxytable[j].media_stream_no) && (rtp_direction != rtp_proxytable[j].direction) /* channel: && (channel == rtp_proxytable[j].channel)*/ ) { rtp_proxytable[rtp_proxytable_idx].rtp_tx_sock = rtp_proxytable[j].rtp_rx_sock; rtp_proxytable[rtp_proxytable_idx].rtp_con_tx_sock = rtp_proxytable[j].rtp_con_rx_sock; DEBUGC(DBCLASS_RTP, "connected entry %i (fd=%i) <-> entry %i (fd=%i)", j, rtp_proxytable[j].rtp_rx_sock, rtp_proxytable_idx, rtp_proxytable[rtp_proxytable_idx].rtp_rx_sock); break; } }}/* * error_handler * * rtp_proxytable_idx: index into the rtp_proxytable array * socket_type: 1 - RTCP, 0 - RTP */static void error_handler (int rtp_proxytable_idx, int socket_type) { /* * It has been seen on linux 2.2.x systems that for some * reason (ICMP issue? -> below) inside the RTP relay, select() * claims that a certain file descriptor has data available to * read, a subsequent call to read() or recv() then does block!! * So lets make the FD's we are going to use non-blocking, so * we will at least survive and not run into a deadlock. * * We catch this here with this workaround (pronounce "HACK") * and hope that next time we pass by it will be ok again. */ if (errno == EAGAIN) { /* I may want to remove this WARNing */ WARN("read() [fd=%i, %s:%i] would block, but select() " "claimed to be readable!", socket_type ? rtp_proxytable[rtp_proxytable_idx].rtp_rx_sock : rtp_proxytable[rtp_proxytable_idx].rtp_con_rx_sock, utils_inet_ntoa(rtp_proxytable[rtp_proxytable_idx].local_ipaddr), rtp_proxytable[rtp_proxytable_idx].local_port + socket_type); } /* * I *MAY* receive ICMP destination unreachable messages when I * try to send RTP traffic to a destination that is in HOLD * (better: is not listening on the UDP port where I send * my RTP data to). * So I should *not* do this - or ignore errors originating * by this -> ECONNREFUSED * * Note: This error is originating from a previous send() on the * same socket and has nothing to do with the read() we have * done above! */ if (errno != ECONNREFUSED) { /* some other error that I probably want to know about */ int j; WARN("read() [fd=%i, %s:%i] returned error [%i:%s]", socket_type ? rtp_proxytable[rtp_proxytable_idx].rtp_rx_sock : rtp_proxytable[rtp_proxytable_idx].rtp_con_rx_sock, utils_inet_ntoa(rtp_proxytable[rtp_proxytable_idx].local_ipaddr), rtp_proxytable[rtp_proxytable_idx].local_port + socket_type, errno, strerror(errno)); for (j=0; j<RTPPROXY_SIZE;j++) { DEBUGC(DBCLASS_RTP, "%i - rx:%i tx:%i %s@%s dir:%i " "lp:%i, rp:%i rip:%s", j, socket_type ? rtp_proxytable[rtp_proxytable_idx].rtp_rx_sock : rtp_proxytable[rtp_proxytable_idx].rtp_con_rx_sock, socket_type ? rtp_proxytable[rtp_proxytable_idx].rtp_tx_sock : rtp_proxytable[rtp_proxytable_idx].rtp_con_tx_sock, rtp_proxytable[j].callid_number, rtp_proxytable[j].callid_host, rtp_proxytable[j].direction, rtp_proxytable[j].local_port, rtp_proxytable[j].remote_port, utils_inet_ntoa(rtp_proxytable[j].remote_ipaddr)); } /* for j */ } /* if errno != ECONNREFUSED */}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -