📄 rtpproxy_relay.c
字号:
callid.number=rtp_proxytable[i].callid_number; callid.host=rtp_proxytable[i].callid_host; /* don't lock the mutex, as we own the lock already */ sts = rtp_relay_stop_fwd(&callid, rtp_proxytable[i].direction, -1, NOLOCK_FDSET); if (sts != STS_SUCCESS) { /* force the streams to timeout on next occasion */ rtp_proxytable[i].timestamp=0; } } }#endif } } /* count > 0 */ /* update timestamp of last usage for both (RX and TX) entries. * This allows silence (no data) on one stream without breaking * the connection after the RTP timeout */ rtp_proxytable[i].timestamp=current_tv.tv_sec; if (rtp_proxytable[i].opposite_entry > 0) { rtp_proxytable[rtp_proxytable[i].opposite_entry-1].timestamp= current_tv.tv_sec; } } /* if */ } /* for i */ /* * age and clean rtp_proxytable (check every 10 seconds) */ if (current_tv.tv_sec > last_tv.tv_sec) { last_tv.tv_sec = current_tv.tv_sec + 10 ; for (i=0;i<RTPPROXY_SIZE; i++) { if ( (rtp_proxytable[i].rtp_rx_sock != 0) && ((rtp_proxytable[i].timestamp+configuration.rtp_timeout) < current_tv.tv_sec)) { osip_call_id_t callid; /* this one has expired, clean it up */ callid.number=rtp_proxytable[i].callid_number; callid.host=rtp_proxytable[i].callid_host;#ifdef USE_DEJITTER dejitter_cancel(&rtp_proxytable[i]);#endif INFO("RTP stream %s@%s (media=%i) has expired", callid.number, callid.host, rtp_proxytable[i].media_stream_no); DEBUGC(DBCLASS_RTP,"RTP stream rx_sock=%i tx_sock=%i " "%s@%s (idx=%i) has expired", rtp_proxytable[i].rtp_rx_sock, rtp_proxytable[i].rtp_tx_sock, callid.number, callid.host, i); /* Don't lock the mutex, as we own the lock already here */ /* Only stop the stream we caught is timeout and not everything. * This may be a multiple stream conversation (audio/video) and * just one (unused?) has timed out. Seen with VoIPEX PBX! */ rtp_relay_stop_fwd(&callid, rtp_proxytable[i].direction, rtp_proxytable[i].media_stream_no, NOLOCK_FDSET); } /* if */ } /* for i */ } /* if (t>...) */ /* copy master FD set */ memcpy(&fdset, &master_fdset, sizeof(fdset)); fd_max=master_fd_max; /* * UNLOCK the MUTEX */ pthread_mutex_unlock(&rtp_proxytable_mutex); } /* for(;;) */ return NULL;}/* * start an rtp stream on the proxy * * RETURNS * STS_SUCCESS on success * STS_FAILURE on error */int rtp_relay_start_fwd (osip_call_id_t *callid, client_id_t client_id, int rtp_direction, int media_stream_no, struct in_addr local_ipaddr, int *local_port, struct in_addr remote_ipaddr, int remote_port, int dejitter) { static int prev_used_port = 0; int num_ports; int i2, i, j; int sock, port; int sock_con; int freeidx; int sts=STS_SUCCESS; int tos; osip_call_id_t cid; if (callid == NULL) { ERROR("rtp_relay_start_fwd: callid 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 [%s] " "has too many characters (%ld, max=%i)", callid->number, (long)strlen(callid->number),CALLIDNUM_SIZE); return STS_FAILURE; } if (callid->host && (strlen(callid->host) >= CALLIDHOST_SIZE)) { ERROR("rtp_relay_start_fwd: received callid host [%s] " "has too many characters (%ld, max=%i)", callid->host, (long)strlen(callid->host),CALLIDHOST_SIZE); return STS_FAILURE; } DEBUGC(DBCLASS_RTP,"rtp_relay_start_fwd: starting RTP proxy " "stream for: CallID=%s@%s [Client-ID=%s] (%s) #=%i", callid->number, callid->host, client_id.contact, ((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) && (compare_client_id(rtp_proxytable[i].client_id, client_id) == STS_SUCCESS)) { /* * The RTP port number reported by the UA MAY change * for a given media stream * (seen with KPhone during HOLD/unHOLD) * Also the destination IP may change during a re-Invite * (seen with Sipphone.com, re-Invites when using * the SIP - POTS gateway [SIP Minutes] */ /* Port number */ 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; } /* IP address */ if (memcmp(&rtp_proxytable[i].remote_ipaddr, &remote_ipaddr, sizeof(remote_ipaddr))) { DEBUGC(DBCLASS_RTP,"RTP IP address changed to %s", utils_inet_ntoa(remote_ipaddr)); memcpy (&rtp_proxytable[i].remote_ipaddr, &remote_ipaddr, sizeof(remote_ipaddr)); }#ifdef USE_DEJITTER /* Initialize up timecrontrol for dejitter function */ dejitter_init_time(&rtp_proxytable[i].tc, dejitter);#endif /* return the already known local port number */ DEBUGC(DBCLASS_RTP,"RTP stream already active idx=%i (remaddr=%s, " "remport=%i, lclport=%i, id=%s, #=%i)", i, utils_inet_ntoa(remote_ipaddr), rtp_proxytable[i].remote_port, 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; } /* if already active */ } /* for */ /* * 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 port number to use and bind to it */ sock=0; /* RTP socket */ sock_con=0; /* RTCP socket */ port=0; if ((prev_used_port < configuration.rtp_port_low) || (prev_used_port > configuration.rtp_port_high)) { prev_used_port = configuration.rtp_port_high; } num_ports = configuration.rtp_port_high - configuration.rtp_port_low + 1; for (i2 = (prev_used_port - configuration.rtp_port_low + 1); i2 < (num_ports + prev_used_port - configuration.rtp_port_low + 1); i2++) { i = (i2%num_ports) + configuration.rtp_port_low; /* 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) { if (rtp_proxytable[j].local_port == i) break; if (rtp_proxytable[j].local_port == i + 1) break; if (rtp_proxytable[j].local_port + 1 == i) break; if (rtp_proxytable[j].local_port + 1 == i + 1) break; } } /* port is available, try to allocate */ if (j == RTPPROXY_SIZE) { port=i; sock=sockbind(local_ipaddr, port, 0); /* RTP */ if (sock) { sock_con=sockbind(local_ipaddr, port+1, 0); /* RTCP */ /* if success break, else try further on */ if (sock_con) break; sts = close(sock); DEBUGC(DBCLASS_RTP,"closed socket %i [%i] for RTP stream because " "cant get pair sts=%i", sock, i, sts); } /* if sock */ } /* if j */ } /* for i */ prev_used_port = port+1; DEBUGC(DBCLASS_RTP,"rtp_relay_start_fwd: addr=%s, port=%i, sock=%i, " "freeidx=%i, input data dejitter buffer=%i usec", utils_inet_ntoa(local_ipaddr), port, sock, freeidx, dejitter); /* found an unused port? No -> RTP port pool fully allocated */ if ((port == 0) || (sock == 0) || (sock_con == 0)) { ERROR("rtp_relay_start_fwd: no RTP port available or bind() failed"); sts = STS_FAILURE; goto unlock_and_exit; } /*&&&: do RTP and RTCP both set DSCP value? */ /* set DSCP value, need to be ROOT */ if (configuration.rtp_dscp) { int uid,euid; uid=getuid(); euid=geteuid(); DEBUGC(DBCLASS_RTP,"uid=%i, euid=%i", uid, euid); if (uid != euid) seteuid(0); if (geteuid()==0) { /* now I'm root */ if (!(configuration.rtp_dscp & ~0x3f)) { tos = (configuration.rtp_dscp << 2) & 0xff; if(setsockopt(sock, SOL_IP, IP_TOS, &tos, sizeof(tos))) { ERROR("rtp_relay_start_fwd: setsockopt() failed while " "setting DSCP value: %s", strerror(errno)); } } else { ERROR("rtp_relay_start_fwd: Invalid DSCP value %d", configuration.rtp_dscp); configuration.rtp_dscp = 0; /* inhibit further attempts */ } } else { /* could not get root */ WARN("siproxd not started as root - cannot set DSCP value"); configuration.rtp_dscp = 0; /* inhibit further attempts */ } /* drop privileges */ if (uid != euid) seteuid(euid); } /* write entry into rtp_proxytable slot (freeidx) */ rtp_proxytable[freeidx].rtp_rx_sock=sock; rtp_proxytable[freeidx].rtp_con_rx_sock = sock_con; 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'; } /* store the passed Client-ID data */ memcpy(&rtp_proxytable[freeidx].client_id, &client_id, sizeof(client_id_t)); 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);#ifdef USE_DEJITTER /* Initialize up timecrontrol for dejitter function */ dejitter_init_time(&rtp_proxytable[freeidx].tc, dejitter);#endif *local_port=port; /* call to firewall API: RTP port */ fwapi_start_rtp(rtp_proxytable[freeidx].direction, rtp_proxytable[freeidx].local_ipaddr, rtp_proxytable[freeidx].local_port,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -