📄 rtpproxy_relay.c
字号:
return STS_FAILURE; } if (client_id == NULL) { ERROR("rtp_relay_start_fwd: contact header is NULL!"); return STS_FAILURE; } /* * life insurance: check size of received call_id strings * I don't know what the maximum allowed size within SIP is, * so if this test fails maybe it's just necessary to increase * the constants CALLIDNUM_SIZE and/or CALLIDHOST_SIZE. */ if (callid->number && strlen(callid->number) > CALLIDNUM_SIZE) { ERROR("rtp_relay_start_fwd: received callid number " "has too many characters (%i, max=%i)", strlen(callid->number),CALLIDNUM_SIZE); return STS_FAILURE; } if (callid->host && strlen(callid->host) > CALLIDHOST_SIZE) { ERROR("rtp_relay_start_fwd: received callid host " "has too many characters (%i, max=%i)", strlen(callid->host),CALLIDHOST_SIZE); return STS_FAILURE; } if (client_id && strlen(client_id) > CLIENT_ID_SIZE) { ERROR("rtp_relay_start_fwd: client ID has too many characters " "(%i, max=%i) (maybe you need to increase CLIENT_ID_SIZE", strlen(client_id),CLIENT_ID_SIZE); return STS_FAILURE; } DEBUGC(DBCLASS_RTP,"rtp_relay_start_fwd: starting RTP proxy " "stream for: %s@%s[%s] (%s) #=%i", callid->number, callid->host, client_id, ((rtp_direction == DIR_INCOMING) ? "incoming RTP" : "outgoing RTP"), media_stream_no); /* lock mutex */ #define return is_forbidden_in_this_code_section 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. */ /* * figure out, if this is an request to start an RTP proxy stream * that is already existing (identified by SIP Call-ID, direction, * media_stream_no and some other client unique thing). * This can be due to UDP repetitions of the INVITE request... */ 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) && (rtp_proxytable[i].media_stream_no == media_stream_no) && (strcmp(rtp_proxytable[i].client_id, client_id) == 0)) { /* * The RTP port number reported by the UA MAY change * for a given media stream * (seen with KPhone during HOLD/unHOLD) */ if (rtp_proxytable[i].remote_port != remote_port) { DEBUGC(DBCLASS_RTP,"RTP port number changed %i -> %i", rtp_proxytable[i].remote_port, remote_port); rtp_proxytable[i].remote_port = remote_port; } /* return the already known local port number */ DEBUGC(DBCLASS_RTP,"RTP stream already active (raddr=%s, " "port=%i, id=%s, #=%i)", utils_inet_ntoa(remote_ipaddr), rtp_proxytable[i].local_port, rtp_proxytable[i].callid_number, rtp_proxytable[i].media_stream_no); *local_port=rtp_proxytable[i].local_port; sts = STS_SUCCESS; goto unlock_and_exit; } } /* * find first free slot in rtp_proxytable */ freeidx=-1; for (j=0; j<RTPPROXY_SIZE; j++) { if (rtp_proxytable[j].rtp_rx_sock==0) { freeidx=j; break; } } /* rtp_proxytable port pool full? */ if (freeidx == -1) { ERROR("rtp_relay_start_fwd: rtp_proxytable is full!"); sts = STS_FAILURE; goto unlock_and_exit; } /* TODO: randomize the port allocation - start at a random offset to search in the allowed port range (so some modulo stuff w/ random start offset - for i=x to (p1-p0)+x; p=p0+mod(x,p1-p0) */ /* find a local outbound port number to use and bind to it */ sock=0; port=0; for (i=configuration.rtp_port_low; i<=configuration.rtp_port_high; i+=2) { for (j=0; j<RTPPROXY_SIZE; j++) { /* outbound port already in use */ if ((memcmp(&rtp_proxytable[j].local_ipaddr, &local_ipaddr, sizeof(struct in_addr))== 0) && (rtp_proxytable[j].local_port == i) ) break; } /* port is available, try to allocate */ if (j == RTPPROXY_SIZE) { port=i; sock=sockbind(local_ipaddr, port, 0); /* if success break, else try further on */ if (sock) break; } } /* for i */ DEBUGC(DBCLASS_RTP,"rtp_relay_start_fwd: addr=%s, port=%i, sock=%i " "freeidx=%i", utils_inet_ntoa(local_ipaddr), port, sock, freeidx); /* found an unused port? No -> RTP port pool fully allocated */ if ((port == 0) || (sock == 0)) { ERROR("rtp_relay_start_fwd: no RTP port available or bind() failed"); sts = STS_FAILURE; goto unlock_and_exit; } /* write entry into rtp_proxytable slot (freeidx) */ rtp_proxytable[freeidx].rtp_rx_sock=sock; if (callid->number) { strcpy(rtp_proxytable[freeidx].callid_number, callid->number); } else { rtp_proxytable[freeidx].callid_number[0]='\0'; } if (callid->host) { strcpy(rtp_proxytable[freeidx].callid_host, callid->host); } else { rtp_proxytable[freeidx].callid_host[0]='\0'; } if (client_id) { strcpy(rtp_proxytable[freeidx].client_id, client_id); } else { rtp_proxytable[freeidx].client_id[0]='\0'; } rtp_proxytable[freeidx].direction = rtp_direction; rtp_proxytable[freeidx].media_stream_no = media_stream_no; memcpy(&rtp_proxytable[freeidx].local_ipaddr, &local_ipaddr, sizeof(struct in_addr)); rtp_proxytable[freeidx].local_port=port; memcpy(&rtp_proxytable[freeidx].remote_ipaddr, &remote_ipaddr, sizeof(struct in_addr)); rtp_proxytable[freeidx].remote_port=remote_port; time(&rtp_proxytable[freeidx].timestamp); *local_port=port; /* 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);unlock_and_exit: /* unlock mutex */ pthread_mutex_unlock(&rtp_proxytable_mutex); #undef return return sts;}/* * stop a rtp stream on the proxy * * RETURNS * STS_SUCCESS on success * STS_FAILURE on error */int rtp_relay_stop_fwd (osip_call_id_t *callid, int rtp_direction, 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)", callid->number, callid->host, ((rtp_direction == DIR_INCOMING) ? "incoming" : "outgoing")); /* * 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 strema active for the same callid (audio + video stream) */ 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)) { 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); } 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) { 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; } } } /* for i */ return STS_SUCCESS;}/* * kills the rtp_proxy thread * * RETURNS * - */void rtpproxy_kill( void ) { void *thread_status; 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;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -