Fix: Polling of file descriptors
[lcr.git] / sip.cpp
diff --git a/sip.cpp b/sip.cpp
index ee455a8..4def0a1 100644 (file)
--- a/sip.cpp
+++ b/sip.cpp
@@ -19,6 +19,8 @@
 
 unsigned char flip[256];
 
+int any_sip_interface = 0;
+
 //pthread_mutex_t mutex_msg;
 su_home_t      sip_home[1];
 
@@ -35,7 +37,7 @@ static int delete_event(struct lcr_work *work, void *instance, int index);
 /*
  * initialize SIP port
  */
-Psip::Psip(int type, char *portname, struct port_settings *settings, struct interface *interface) : Port(type, portname, settings)
+Psip::Psip(int type, char *portname, struct port_settings *settings, struct interface *interface) : Port(type, portname, settings, interface)
 {
        p_s_rtp_bridge = 0;
        if (interface->rtp_bridge)
@@ -79,7 +81,7 @@ Psip::~Psip()
        rtp_close();
 }
 
-const char *media_type2name(uint8_t media_type) {
+static const char *media_type2name(uint8_t media_type) {
        switch (media_type) {
        case MEDIA_TYPE_ULAW:
                return "PCMU";
@@ -313,7 +315,8 @@ static int rtcp_sock_callback(struct lcr_fd *fd, unsigned int what, void *instan
 }
 
 #define RTP_PORT_BASE  30000
-static unsigned int next_udp_port = RTP_PORT_BASE;
+#define RTP_PORT_MAX   39998
+static unsigned short next_udp_port = RTP_PORT_BASE;
 
 static int rtp_sub_socket_bind(int fd, struct sockaddr_in *sin_local, uint32_t ip, uint16_t port)
 {
@@ -353,13 +356,14 @@ static int rtp_sub_socket_connect(int fd, struct sockaddr_in *sin_local, struct
 
 int Psip::rtp_open(void)
 {
-       int rc;
+       int rc, rc2;
        struct in_addr ia;
        unsigned int ip;
+       unsigned short start_port;
 
        /* create socket */
        rc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
-       if (!rc) {
+       if (rc < 0) {
                rtp_close();
                return -EIO;
        }
@@ -367,7 +371,7 @@ int Psip::rtp_open(void)
        register_fd(&p_s_rtp_fd, LCR_FD_READ, rtp_sock_callback, this, 0);
 
        rc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
-       if (!rc) {
+       if (rc < 0) {
                rtp_close();
                return -EIO;
        }
@@ -377,15 +381,34 @@ int Psip::rtp_open(void)
        /* bind socket */
        ip = htonl(INADDR_ANY);
        ia.s_addr = ip;
-       for (next_udp_port = next_udp_port % 0xffff;
-            next_udp_port < 0xffff; next_udp_port += 2) {
+       start_port = next_udp_port;
+       while (1) {
                rc = rtp_sub_socket_bind(p_s_rtp_fd.fd, &p_s_rtp_sin_local, ip, next_udp_port);
                if (rc != 0)
-                       continue;
+                       goto try_next_port;
 
                rc = rtp_sub_socket_bind(p_s_rtcp_fd.fd, &p_s_rtcp_sin_local, ip, next_udp_port+1);
-               if (rc == 0)
+               if (rc == 0) {
+                       next_udp_port = (next_udp_port + 2 > RTP_PORT_MAX) ? RTP_PORT_BASE : next_udp_port + 2;
                        break;
+               }
+               /* reopen rtp socket and try again with next udp port */
+               unregister_fd(&p_s_rtp_fd);
+               close(p_s_rtp_fd.fd);
+               p_s_rtp_fd.fd = 0;
+               rc2 = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+               if (rc2 < 0) {
+                       rtp_close();
+                       return -EIO;
+               }
+               p_s_rtp_fd.fd = rc2;
+               register_fd(&p_s_rtp_fd, LCR_FD_READ, rtp_sock_callback, this, 0);
+
+try_next_port:
+               next_udp_port = (next_udp_port + 2 > RTP_PORT_MAX) ? RTP_PORT_BASE : next_udp_port + 2;
+               if (next_udp_port == start_port)
+                       break;
+               /* we must use rc2, in order to preserve rc */
        }
        if (rc < 0) {
                PDEBUG(DEBUG_SIP, "failed to find port\n");
@@ -1826,6 +1849,7 @@ void Psip::rtp_shutdown(void)
 int sip_init_inst(struct interface *interface)
 {
        struct sip_inst *inst = (struct sip_inst *) MALLOC(sizeof(*inst));
+       char local[64];
 
        interface->sip_inst = inst;
        SCPY(inst->interface_name, interface->name);
@@ -1840,7 +1864,10 @@ int sip_init_inst(struct interface *interface)
                return -EINVAL;
        }
 
-       inst->nua = nua_create(inst->root, sip_callback, inst, TAG_NULL());
+       SPRINT(local, "sip:%s",inst->local_peer);
+       if (!strchr(inst->local_peer, ':'))
+               SCAT(local, ":5060");
+       inst->nua = nua_create(inst->root, sip_callback, inst, NUTAG_URL(local), TAG_END());
        if (!inst->nua) {
                PERROR("Failed to create SIP stack object\n");
                sip_exit_inst(interface);
@@ -1865,6 +1892,8 @@ int sip_init_inst(struct interface *interface)
 
        PDEBUG(DEBUG_SIP, "SIP interface created (inst=%p)\n", inst);
 
+       any_sip_interface = 1;
+
        return 0;
 }
 
@@ -1883,6 +1912,16 @@ void sip_exit_inst(struct interface *interface)
        interface->sip_inst = NULL;
 
        PDEBUG(DEBUG_SIP, "SIP interface removed\n");
+
+       /* check if there is any other SIP interface left */
+       interface = interface_first;
+       while (interface) {
+               if (interface->sip_inst)
+                       break;
+               interface = interface->next;
+       }
+       if (!interface)
+               any_sip_interface = 0;
 }
 
 extern su_log_t su_log_default[];