/* * init_server() * Starts up listening socket */ int init_server() { int on = 1; // Communications sockets if (ENABLE_VB) { // tcp: gs_coms_skt = tcpsock(); if (setsockopt(gs_coms_skt, SOL_SOCKET,SO_REUSEADDR, (char*)&on, sizeof(on)) < 0) { printf("Error Reusing Socket\n"); } sockbind(gs_coms_skt, gs_port_coms); socklisten(gs_coms_skt); printf("TCP Listening on port %d\n.",gs_port_coms); sock_set_nonblocking(gs_coms_skt); // was blocking } // udp: if (firsttime) { gs_udpcoms_skt = udpsock(); sock_set_nonblocking(gs_udpcoms_skt); sockbind(gs_udpcoms_skt, UDP_PORT); printf("UDP Listening on port %d\n.", UDP_PORT); } }
/* * 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, char *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) { static int prev_used_port = 0; int num_ports; int i2, i, j; int sock, port; 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; } if (client_id == NULL) { ERROR("rtp_relay_start_fwd: did not get a client ID!"); 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) * 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)); } /* return the already known local port number */ DEBUGC(DBCLASS_RTP,"RTP stream already active (remaddr=%s, " "remport=%i, lclport=%i, id=%s, #=%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; } } /* * 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; 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 += 2) { i = (i2%num_ports) + configuration.rtp_port_low; 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, 0); /* if success break, else try further on */ if (sock) break; } } /* for i */ prev_used_port = port; 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; } /* 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: ", 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; 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; /* call to firewall API */ fwapi_start_rtp(rtp_proxytable[freeidx].direction, rtp_proxytable[freeidx].local_ipaddr, rtp_proxytable[freeidx].local_port, rtp_proxytable[freeidx].remote_ipaddr, rtp_proxytable[freeidx].remote_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; }
/* * binds to SIP UDP socket for listening to incoming packets * * RETURNS * STS_SUCCESS on success * STS_FAILURE on error */ int sipsock_listen (void) { struct in_addr ipaddr; /* start of AU4D00875 by d00107688 to support bind 2008-10-15*/ struct in_addr wanipaddr; /* end of AU4D00875 by d00107688 to support bind 2008-10-15*/ int i = 0; memset(&ipaddr, 0, sizeof(ipaddr)); /* start of AU4D00875 by d00107688 to support bind 2008-10-15*/ memset(&wanipaddr, 0, sizeof(wanipaddr)); if (STS_FAILURE == get_ip_by_ifname(configuration.outbound_if, &wanipaddr)) { ERROR("%s ip: %s", configuration.inbound_if, utils_inet_ntoa(wanipaddr)); ERROR("can not get the ip , please check it......."); } else { g_lsockFlg = 1; } /* end of AU4D00875 by d00107688 to support bind 2008-10-15*/ /* start of AU4D00875 by d00107688 to support bind 2008-10-15*/ if (1 == g_lsockFlg) { sip_udp_socket = sockbind(ipaddr, configuration.sip_listen_port, 1); sip_udp_wan_socket = sockbind(wanipaddr, wanport, 1); if (0 == sip_udp_wan_socket) { for (i = 0; i < 5; i++) { wanport += (i * 10 + i); sip_udp_wan_socket = sockbind(wanipaddr, wanport, 1); if (0 == sip_udp_wan_socket) { ERROR("bind in port: %d error", wanport); continue; } else { break; } } } if ((0 == sip_udp_socket) || (0 == sip_udp_wan_socket)) { ERROR("socket bind error"); return STS_FAILURE; /* failure */ } } else { sip_udp_socket = sockbind(ipaddr, configuration.sip_listen_port, 1); if (sip_udp_socket == 0) return STS_FAILURE; /* failure*/ } INFO("bound to port %i", configuration.sip_listen_port); DEBUGC(DBCLASS_NET,"bound socket %i",sip_udp_socket); /* end of AU4D00875 by d00107688 to support bind 2008-10-15*/ return STS_SUCCESS; }