📄 rtpproxy_relay.c
字号:
osip_call_id_t cid;
if (callid == NULL) {
printf("rtp_relay_start_fwd: callid is NULL!");
return STS_FAILURE;
}
if (client_id == NULL) {
printf("rtp_relay_start_fwd: did not get a client ID!");
return STS_FAILURE;
}
pthread_mutex_lock(&rtp_proxytable_mutex);
/*
* 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
* Also the destination IP may change during a re-Invite
*/
/* Port number */
if (rtp_proxytable[i].remote_port != remote_port)
rtp_proxytable[i].remote_port = remote_port;
/* IP address */
if (memcmp(&rtp_proxytable[i].remote_ipaddr, &remote_ipaddr,
sizeof(remote_ipaddr))) {
memcpy (&rtp_proxytable[i].remote_ipaddr, &remote_ipaddr,
sizeof(remote_ipaddr));
}
*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) {
printf("rtp_relay_start_fwd: rtp_proxytable is full!");
sts = STS_FAILURE;
goto unlock_and_exit;
}
/*randomize the port allocation - start at a random offset to
search in the allowed port range
random start offset
- for i=x to (p1-p0)+x; p=p0+mod(x,p1-p0) */
/* find a local port number to use and bind to it */
sock=0;
port=0;
if ((prev_used_port < args_info.rtp_port_low_arg) ||
(prev_used_port > args_info.rtp_port_high_arg)) {
prev_used_port = args_info.rtp_port_high_arg;
}
num_ports = args_info.rtp_port_high_arg - args_info.rtp_port_low_arg + 1;
for (i2 = (prev_used_port - args_info.rtp_port_low_arg + 1);
i2 < (num_ports + prev_used_port - args_info.rtp_port_low_arg + 1);
i2++) {
i = (i2%num_ports) + args_info.rtp_port_low_arg;
/* only allow even port numbers */
if ((i % 2) != 0) continue;
for (j=0; j<RTPPROXY_SIZE; j++) {
/* check if 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);
/* if success break, else try further on */
if (sock) break;
}
}
prev_used_port = port;
/* found an unused port? No -> RTP port pool fully allocated */
if ((port == 0) || (sock == 0)) {
printf("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();
int k;
for (k=0; k<RTPPROXY_SIZE; k++) {
if (rtp_proxytable[k].rtp_rx_sock != 0) {
printf("rtp_proxytable[%d]:%d,%s@%s,%s,%d,%d\n",k,rtp_proxytable[k].rtp_rx_sock,
rtp_proxytable[k].callid_number,rtp_proxytable[k].callid_host,
rtp_proxytable[k].client_id,rtp_proxytable[k].direction,rtp_proxytable[k].media_stream_no);
}
}
/* 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);
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) {
printf("rtp_relay_stop_fwd: callid is NULL!\n");
return STS_FAILURE;
}
if (nolock == 0) {
pthread_mutex_lock(&rtp_proxytable_mutex);
}
/*
* 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))) {
sts = close(rtp_proxytable[i].rtp_rx_sock);
memset(&rtp_proxytable[i], 0, sizeof(rtp_proxytable[0]));
got_match=1;
}
}
/* did not find an active stream... */
if (!got_match) {
printf("rtp_relay_stop_fwd: can't find active stream for %s@%s (%s)",
callid->number, callid->host,
((rtp_direction == DIR_INCOMING) ? "incoming RTP\n" : "outgoing RTP\n"));
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);
}
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;
}
}
}
return STS_SUCCESS;
}
/*
* kills the rtp_proxy thread
*
* RETURNS
* -
*/
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, 0);
}
}
/* kill the thread */
if (rtpproxy_tid) {
pthread_cancel(rtpproxy_tid);
pthread_kill(rtpproxy_tid, SIGALRM);
pthread_join(rtpproxy_tid, &thread_status);
}
return;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -