Add -lncurses to LDD flags
[lcr.git] / sip.cpp
diff --git a/sip.cpp b/sip.cpp
index 7d16328..075447c 100644 (file)
--- a/sip.cpp
+++ b/sip.cpp
 #include <sofia-sip/sdp.h>
 #include <sofia-sip/sip_header.h>
 
+#ifndef SOFIA_SIP_GCC_4_8_PATCH_APLLIED
+#warning ********************************************************
+#warning Please apply the sofia-sip-gcc-4.8.patch !
+#warning If this issue is already fixed, just remove this check.
+#warning ********************************************************
+#error
+#endif
+
 #undef NUTAG_AUTO100
 
 unsigned char flip[256];
 
+int any_sip_interface = 0;
+
 //pthread_mutex_t mutex_msg;
 su_home_t      sip_home[1];
 
@@ -31,6 +41,7 @@ struct sip_inst {
 };
 
 static int delete_event(struct lcr_work *work, void *instance, int index);
+static int load_timer(struct lcr_timer *timer, void *instance, int index);
 
 /*
  * initialize SIP port
@@ -61,6 +72,11 @@ Psip::Psip(int type, char *portname, struct port_settings *settings, struct inte
        p_s_rxpos = 0;
        p_s_rtp_tx_action = 0;
 
+       /* audio */
+       memset(&p_s_loadtimer, 0, sizeof(p_s_loadtimer));
+       add_timer(&p_s_loadtimer, load_timer, this, 0);
+       p_s_next_tv_sec = 0;
+
        PDEBUG(DEBUG_SIP, "Created new Psip(%s).\n", portname);
        if (!p_s_sip_inst)
                FATAL("No SIP instance for interface\n");
@@ -74,6 +90,7 @@ Psip::~Psip()
 {
        PDEBUG(DEBUG_SIP, "Destroyed SIP process(%s).\n", p_name);
 
+       del_timer(&p_s_loadtimer);
        del_work(&p_s_delete);
 
        rtp_close();
@@ -255,6 +272,12 @@ we only support alaw and ulaw!
                return 0;
        }
 
+       /* record audio */
+       if (psip->p_record)
+               psip->record(payload, payload_len, 0); // from down
+       if (psip->p_tap)
+               psip->tap(payload, payload_len, 0); // from down
+
        n = payload_len;
        from = payload;
        to = payload;
@@ -265,6 +288,8 @@ we only support alaw and ulaw!
        }
        while(n--)
                *to++ = flip[*from++];
+       if (psip->p_dov_rx)
+               psip->dov_rx(payload, payload_len);
        psip->bridge_tx(payload, payload_len);
 
        return 0;
@@ -313,7 +338,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 +379,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 +394,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,22 +404,41 @@ 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) {
+                       p_s_rtp_port_local = next_udp_port;
+                       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);
 
-               rc = rtp_sub_socket_bind(p_s_rtcp_fd.fd, &p_s_rtcp_sin_local, ip, next_udp_port+1);
-               if (rc == 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");
                rtp_close();
                return rc;
        }
-       p_s_rtp_port_local = next_udp_port;
        p_s_rtp_ip_local = ntohl(p_s_rtp_sin_local.sin_addr.s_addr);
        PDEBUG(DEBUG_SIP, "local ip %08x port %d\n", p_s_rtp_ip_local, p_s_rtp_port_local);
        PDEBUG(DEBUG_SIP, "remote ip %08x port %d\n", p_s_rtp_ip_remote, p_s_rtp_port_remote);
@@ -464,6 +510,12 @@ int Psip::rtp_send_frame(unsigned char *data, unsigned int len, uint8_t payload_
        int duration; /* in samples */
        unsigned char buffer[256];
 
+       /* record audio */
+       if (p_record)
+               record(data, len, 1); // from up
+       if (p_tap)
+               tap(data, len, 1); // from up
+
        if (!p_s_rtp_is_connected) {
                /* drop silently */
                return 0;
@@ -555,6 +607,18 @@ we only support alaw and ulaw!
 /* receive from remote */
 int Psip::bridge_rx(unsigned char *data, int len)
 {
+       int ret;
+
+       /* don't bridge, if tones are provided */
+       if (p_tone_name[0] || p_dov_tx)
+               return -EBUSY;
+
+       if (p_dov_tx)
+               return -EBUSY;
+
+       if ((ret = Port::bridge_rx(data, len)))
+               return ret;
+
        /* write to rx buffer */
        while(len--) {
                p_s_rxdata[p_s_rxpos++] = flip[*data++];
@@ -795,6 +859,12 @@ int Psip::message_connect(unsigned int epoint_id, int message_id, union paramete
                , inet_ntoa(ia), inet_ntoa(ia), p_s_rtp_port_local, payload_type, payload_type, media_type2name(media_type));
        PDEBUG(DEBUG_SIP, "Using SDP response: %s\n", sdp_str);
 
+       /* NOTE:
+        * If this response causes corrupt messages, like SDP body inside or
+        * before header, check if the sofia-sip-gcc-4.8.patch was applied.
+        * If it is still corrupted, try to disable optimization when compiling
+        * sofia-sip.
+        */
        nua_respond(p_s_handle, SIP_200_OK,
                NUTAG_MEDIA_ENABLE(0),
                SIPTAG_CONTENT_TYPE_STR("application/sdp"),
@@ -1268,7 +1338,8 @@ int Psip::parse_sdp(sip_t const *sip, unsigned int *ip, unsigned short *port, ui
 void Psip::i_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *magic, nua_handle_t *nh, nua_hmagic_t *hmagic, sip_t const *sip, tagi_t tagss[])
 {
        struct sip_inst *inst = (struct sip_inst *) p_s_sip_inst;
-       const char *from = "", *to = "";
+       const char *from = "", *to = "", *name = "";
+       char imsi[16] = "";
        int ret;
        class Endpoint *epoint;
        struct lcr_msg *message;
@@ -1276,6 +1347,7 @@ void Psip::i_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag
        int media_types[32];
        uint8_t payload_types[32];
        int payloads = 0;
+       int media_type;
 
        interface = getinterfacebyname(inst->interface_name);
        if (!interface) {
@@ -1283,10 +1355,22 @@ void Psip::i_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag
                return;
        }
 
-       if (sip->sip_from && sip->sip_from->a_url)
-               from = sip->sip_from->a_url->url_user;
-       if (sip->sip_to && sip->sip_to->a_url)
-               to = sip->sip_to->a_url->url_user;
+       if (sip->sip_from) {
+               if (sip->sip_from->a_url)
+                       from = sip->sip_from->a_url->url_user;
+               if (sip->sip_from->a_display) {
+                       name = sip->sip_from->a_display;
+                       if (!strncmp(name, "\"IMSI", 5)) {
+                               strncpy(imsi, name + 5, 15);
+                               imsi[15] = '\0';
+                               name = "";
+                       }
+               }
+       }
+       if (sip->sip_to) {
+               if (sip->sip_to->a_url)
+                       to = sip->sip_to->a_url->url_user;
+       }
        PDEBUG(DEBUG_SIP, "invite received (%s->%s)\n", from, to);
 
        sip_trace_header(this, "Payload received", DIRECTION_NONE);
@@ -1361,6 +1445,12 @@ void Psip::i_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag
                p_callerinfo.ntype = INFO_NTYPE_UNKNOWN;
                SCPY(p_callerinfo.id, from);
                add_trace("calling", "number", "%s", from);
+               SCPY(p_callerinfo.name, name);
+               if (name[0])
+                       add_trace("calling", "name", "%s", name);
+               SCPY(p_callerinfo.imsi, imsi);
+               if (imsi[0])
+                       add_trace("calling", "imsi", "%s", imsi);
        }
        SCPY(p_callerinfo.interface, inst->interface_name);
        /* dialing information */
@@ -1426,9 +1516,6 @@ void Psip::i_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag
        }
        message_put(message);
 
-#if 0
-issues:
-- send tones that are clocked with timer, unless data is received from bridge
        /* send progress, if tones are available and if we don't bridge */
        if (!p_s_rtp_bridge && interface->is_tones == IS_YES) {
                char sdp_str[256];
@@ -1436,7 +1523,8 @@ issues:
                unsigned char payload_type;
 
                PDEBUG(DEBUG_SIP, "Connecting audio, since we have tones available\n");
-               payload_type = (options.law=='a') ? RTP_PT_ALAW : RTP_PT_ULAW;
+               media_type = (options.law=='a') ? MEDIA_TYPE_ALAW : MEDIA_TYPE_ULAW;
+               payload_type = (options.law=='a') ? PAYLOAD_TYPE_ALAW : PAYLOAD_TYPE_ULAW;
                /* open local RTP peer (if not bridging) */
                if (rtp_connect() < 0) {
                        nua_respond(nh, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
@@ -1467,23 +1555,21 @@ issues:
                        "t=0 0\n"
                        "m=audio %d RTP/AVP %d\n"
                        "a=rtpmap:%d %s/8000\n"
-                       , inet_ntoa(ia), inet_ntoa(ia), p_s_rtp_port_local, payload_type, payload_type, payload_type2name(payload_type));
+                       , inet_ntoa(ia), inet_ntoa(ia), p_s_rtp_port_local, payload_type, payload_type, media_type2name(media_type));
                PDEBUG(DEBUG_SIP, "Using SDP response: %s\n", sdp_str);
 
                nua_respond(p_s_handle, SIP_183_SESSION_PROGRESS,
                        NUTAG_MEDIA_ENABLE(0),
                        SIPTAG_CONTENT_TYPE_STR("application/sdp"),
                        SIPTAG_PAYLOAD_STR(sdp_str), TAG_END());
-               new_state(PORT_STATE_CONNECT);
                sip_trace_header(this, "RESPOND", DIRECTION_OUT);
                add_trace("respond", "value", "183 SESSION PROGRESS");
                add_trace("reason", NULL, "audio available");
                add_trace("rtp", "ip", "%s", inet_ntoa(ia));
                add_trace("rtp", "port", "%d,%d", p_s_rtp_port_local, p_s_rtp_port_local + 1);
-               add_trace("rtp", "payload", "%d", payload_type);
+               add_trace("rtp", "payload", "%s:%d", media_type2name(media_type), payload_type);
                end_trace();
        }
-#endif
 }
 
 void Psip::i_bye(int status, char const *phrase, nua_t *nua, nua_magic_t *magic, nua_handle_t *nh, nua_hmagic_t *hmagic, sip_t const *sip, tagi_t tagss[])
@@ -1869,6 +1955,8 @@ int sip_init_inst(struct interface *interface)
 
        PDEBUG(DEBUG_SIP, "SIP interface created (inst=%p)\n", inst);
 
+       any_sip_interface = 1;
+
        return 0;
 }
 
@@ -1887,6 +1975,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[];
@@ -1947,3 +2045,106 @@ static int delete_event(struct lcr_work *work, void *instance, int index)
        return 0;
 }
 
+
+/*
+ * generate audio, if no data is received from bridge
+ */
+
+void Psip::set_tone(const char *dir, const char *tone)
+{
+       Port::set_tone(dir, tone);
+
+       update_load();
+}
+
+void Psip::update_load(void)
+{
+       /* don't trigger load event if event already active */
+       if (p_s_loadtimer.active)
+               return;
+
+       /* don't start timer if ... */
+       if (!p_tone_name[0] && !p_dov_tx)
+               return;
+
+       p_s_next_tv_sec = 0;
+       schedule_timer(&p_s_loadtimer, 0, 0); /* no delay the first time */
+}
+
+static int load_timer(struct lcr_timer *timer, void *instance, int index)
+{
+       class Psip *psip = (class Psip *)instance;
+
+       /* stop timer if ... */
+       if (!psip->p_tone_name[0] && !psip->p_dov_tx)
+               return 0;
+
+       psip->load_tx();
+
+       return 0;
+}
+
+#define SEND_SIP_LEN 160
+
+void Psip::load_tx(void)
+{
+       int diff;
+       struct timeval current_time;
+       int tosend = SEND_SIP_LEN, i;
+       unsigned char buf[SEND_SIP_LEN], *p = buf;
+
+       /* get elapsed */
+       gettimeofday(&current_time, NULL);
+       if (!p_s_next_tv_sec) {
+               /* if timer expired the first time, set next expected timeout 160 samples in advance */
+               p_s_next_tv_sec = current_time.tv_sec;
+               p_s_next_tv_usec = current_time.tv_usec + SEND_SIP_LEN * 125;
+               if (p_s_next_tv_usec >= 1000000) {
+                       p_s_next_tv_usec -= 1000000;
+                       p_s_next_tv_sec++;
+               }
+               schedule_timer(&p_s_loadtimer, 0, SEND_SIP_LEN * 125);
+       } else {
+               diff = 1000000 * (current_time.tv_sec - p_s_next_tv_sec)
+                       + (current_time.tv_usec - p_s_next_tv_usec);
+               if (diff < -SEND_SIP_LEN * 125 || diff > SEND_SIP_LEN * 125) {
+                       /* if clock drifts too much, set next timeout event to current timer + 160 */
+                       diff = 0;
+                       p_s_next_tv_sec = current_time.tv_sec;
+                       p_s_next_tv_usec = current_time.tv_usec + SEND_SIP_LEN * 125;
+                       if (p_s_next_tv_usec >= 1000000) {
+                               p_s_next_tv_usec -= 1000000;
+                               p_s_next_tv_sec++;
+                       }
+               } else {
+                       /* if diff is positive, it took too long, so next timeout will be earlier */
+                       p_s_next_tv_usec += SEND_SIP_LEN * 125;
+                       if (p_s_next_tv_usec >= 1000000) {
+                               p_s_next_tv_usec -= 1000000;
+                               p_s_next_tv_sec++;
+                       }
+               }
+               schedule_timer(&p_s_loadtimer, 0, SEND_SIP_LEN * 125 - diff);
+       }
+
+       /* copy tones */
+       if (p_tone_name[0]) {
+               tosend -= read_audio(p, tosend);
+       } else
+       if (p_dov_tx) {
+               tosend -= dov_tx(p, tosend);
+       }
+       if (tosend) {
+               PERROR("buffer is not completely filled\n");
+               return;
+       }
+
+       p = buf;
+       for (i = 0; i < SEND_SIP_LEN; i++) {
+               *p = flip[*p];
+               p++;
+       }
+       /* transmit data via rtp */
+       rtp_send_frame(buf, SEND_SIP_LEN, (options.law=='a')?PAYLOAD_TYPE_ALAW:PAYLOAD_TYPE_ULAW);
+}
+