fixup register
authorAndreas Eversberg <jolly@eversberg.eu>
Sun, 5 Nov 2017 06:44:42 +0000 (07:44 +0100)
committerAndreas Eversberg <jolly@eversberg.eu>
Sun, 5 Nov 2017 06:44:42 +0000 (07:44 +0100)
default/interface.conf
interface.c
interface.h
sip.cpp

index 76a6da4..ae79ed5 100644 (file)
 #[sip]
 ## define source and destination IP to make a call
 #sip 192.168.0.55 sipgate.de
-## define <user> <host> to register to a SIP gateway
-#register <user> sipgate.de
+## define <user> <host> <interval> to register to a SIP gateway
+#register <user> sipgate.de 300
 ##define RTP port range or use default
 #rtp-ports 30000 39999
 ## use authentication credentials
 #authenticate <user> <password>
 ## define keepalive timer to keep INVITE/REGISTER alive
-#options-timer 15
+## this is also required to keep the NAT router's table alive
+#options-interval 15
 ## define public IP (if behind NAT firewall)
 #public 123.45.67.89
 ## OR define stun server and resolving interval
index 7722529..7d5d7a5 100644 (file)
@@ -1017,7 +1017,7 @@ static int inter_authenticate(struct interface *interface, char *filename, int l
        return(0);
 #endif
 }
-static int options_timer(struct interface *interface, char *filename, int line, char *parameter, char *value)
+static int options_interval(struct interface *interface, char *filename, int line, char *parameter, char *value)
 {
 #ifndef WITH_SIP
        SPRINT(interface_error, "Error in %s (line %d): SIP not compiled in.\n", filename, line);
@@ -1029,10 +1029,10 @@ static int options_timer(struct interface *interface, char *filename, int line,
        }
 
        if (!value || !value[0]) {
-               SPRINT(interface_error, "Error in %s (line %d): Missing timer value.\n", filename, line);
+               SPRINT(interface_error, "Error in %s (line %d): Missing options interval.\n", filename, line);
                return(-1);
        }
-       interface->sip_options_timer = atoi(value);
+       interface->sip_options_interval = atoi(value);
 
        return(0);
 #endif
@@ -1128,7 +1128,7 @@ static int inter_register(struct interface *interface, char *filename, int line,
        SPRINT(interface_error, "Error in %s (line %d): SIP not compiled in.\n", filename, line);
        return(-1);
 #else
-       char *p;
+       char *p, *q;
 
        if (!interface->sip) {
                SPRINT(interface_error, "Error in %s (line %d): This is not a SIP interface.\n", filename, line);
@@ -1145,9 +1145,15 @@ static int inter_register(struct interface *interface, char *filename, int line,
                SPRINT(interface_error, "Error in %s (line %d): Missing SIP host\n", filename, line);
                return(-1);
        }
+       q = get_seperated(p);
+       if (!q[0]) {
+               SPRINT(interface_error, "Error in %s (line %d): Missing register interval\n", filename, line);
+               return(-1);
+       }
        interface->sip_register = 1;
        SCPY(interface->sip_register_user, value);
        SCPY(interface->sip_register_host, p);
+       interface->sip_register_interval = atoi(q);
 
        return(0);
 #endif
@@ -1533,7 +1539,7 @@ struct interface_param interface_param[] = {
        "Registers to given SIP registrar."},
        {"authenticate", &inter_authenticate, "<user> <password>",
        "Defines SIP user and password for authentication."},
-       {"options-timer", &options_timer, "<timer> | 0",
+       {"options-interval", &options_interval, "<interval> | 0",
        "Defines SIP timer to send OPTIONS messages to keepalive SIP sessions."},
        {"public", &options_public, "<server> <interval>",
        "Defines public IP, if this endpoint is behind NAT firewall."},
index 91ccc47..ecee833 100644 (file)
@@ -133,7 +133,8 @@ struct interface {
        int                     sip_register;
        char                    sip_register_user[128];
        char                    sip_register_host[128];
-       int                     sip_options_timer; /* timer to keepalive invite/register transactions */
+       int                     sip_register_interval; /* interval to register */
+       int                     sip_options_interval; /* timer to keepalive invite/register transactions */
        char                    sip_public_ip[128];
        char                    sip_stun_server[128];
        int                     sip_stun_interval; /* timer to check own IP address */
diff --git a/sip.cpp b/sip.cpp
index e136579..21e24d5 100644 (file)
--- a/sip.cpp
+++ b/sip.cpp
@@ -60,7 +60,8 @@ struct sip_inst {
        nua_handle_t            *register_handle;
        struct lcr_timer        register_retry_timer;
        struct lcr_timer        register_option_timer;
-       int                     options_timeout;
+       int                     register_interval;
+       int                     options_interval;
        char                    auth_user[128];
        char                    auth_password[128];
        su_root_t               *root;
@@ -1604,8 +1605,9 @@ void Psip::i_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag
        message_put(message);
 
        PDEBUG(DEBUG_SIP, "Invite received, scheduling option timer\n");
-       if (inst->options_timeout)
-               schedule_timer(&p_s_invite_option_timer, inst->options_timeout, 0);
+       /* start option timer */
+       if (inst->options_interval)
+               schedule_timer(&p_s_invite_option_timer, inst->options_interval, 0);
        p_s_invite_direction = DIRECTION_IN;
 
        /* send progress, if tones are available and if we don't bridge */
@@ -1809,8 +1811,9 @@ void Psip::r_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag
        }
 
        PDEBUG(DEBUG_SIP, "Invite response, scheduling option timer\n");
-       if (inst->options_timeout)
-               schedule_timer(&p_s_invite_option_timer, inst->options_timeout, 0);
+       /* start option timer */
+       if (inst->options_interval)
+               schedule_timer(&p_s_invite_option_timer, inst->options_interval, 0);
 
        switch (status) {
        case 100:
@@ -1899,7 +1902,8 @@ void Psip::r_options(int status, char const *phrase, nua_t *nua, nua_magic_t *ma
 
        if (status >= 200 && status <= 299) {
                PDEBUG(DEBUG_SIP, "options ok, scheduling timer\n");
-               schedule_timer(&p_s_invite_option_timer, inst->options_timeout, 0);
+               /* restart option timer */
+               schedule_timer(&p_s_invite_option_timer, inst->options_interval, 0);
                return;
        }
 
@@ -1924,7 +1928,7 @@ void Psip::r_options(int status, char const *phrase, nua_t *nua, nua_magic_t *ma
        trigger_work(&p_s_delete);
 }
 
-static void challenge(struct sip_inst *inst, class Psip *psip, 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[])
+static int challenge(struct sip_inst *inst, class Psip *psip, 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[])
 {
        sip_www_authenticate_t const *authenticate = NULL;
        char const *realm = NULL;
@@ -1932,9 +1936,16 @@ static void challenge(struct sip_inst *inst, class Psip *psip, int status, char
        int i;
        char *cur;
        char authentication[256] = "";
-
        PDEBUG(DEBUG_SIP, "challenge order received\n");
 
+       if (!inst->auth_user[0]) {
+               PDEBUG(DEBUG_SIP, "No credentials available\n");
+               sip_trace_header(psip, inst->interface_name, "AUTHENTICATE", DIRECTION_OUT);
+               add_trace("error", NULL, "There are no credentials given for interface");
+               end_trace();
+               return -1;
+       }
+
        if (sip->sip_www_authenticate) {
                authenticate = sip->sip_www_authenticate;
        } else if (sip->sip_proxy_authenticate) {
@@ -1944,7 +1955,7 @@ static void challenge(struct sip_inst *inst, class Psip *psip, int status, char
                sip_trace_header(psip, inst->interface_name, "AUTHENTICATE", DIRECTION_OUT);
                add_trace("error", NULL, "Authentication method unknwon");
                end_trace();
-               return;
+               return -1;
        }
 
        scheme = (char const *) authenticate->au_scheme;
@@ -1962,7 +1973,7 @@ static void challenge(struct sip_inst *inst, class Psip *psip, int status, char
                sip_trace_header(psip, inst->interface_name, "AUTHENTICATE", DIRECTION_OUT);
                add_trace("error", NULL, "Authentication header has no realm or scheme");
                end_trace();
-               return;
+               return -1;
        }
 
        SPRINT(authentication, "%s:%s:%s:%s", scheme, realm, inst->auth_user, inst->auth_password);
@@ -1976,6 +1987,8 @@ static void challenge(struct sip_inst *inst, class Psip *psip, int status, char
        end_trace();
 
        nua_authenticate(nh, /*SIPTAG_EXPIRES_STR("3600"),*/ NUTAG_AUTH(authentication), TAG_END());
+
+       return 0;
 }
 
 static void sip_callback(nua_event_t event, 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 tags[])
@@ -1983,6 +1996,7 @@ static void sip_callback(nua_event_t event, int status, char const *phrase, nua_
        struct sip_inst *inst = (struct sip_inst *) magic;
        class Port *port;
        class Psip *psip = NULL;
+       int rc;
 
        PDEBUG(DEBUG_SIP, "Event %d from SIP stack received (handle=%p)\n", event, nh);
        if (!nh)
@@ -1997,24 +2011,35 @@ static void sip_callback(nua_event_t event, int status, char const *phrase, nua_
                switch (status) {
                case 200:
                        status_200:
-                       inst->register_state = REGISTER_STATE_REGISTERED;
-                       if (inst->options_timeout)
-                               schedule_timer(&inst->register_option_timer, inst->options_timeout, 0);
+                       /* if not registered, become registered and start register interval timer */
+                       if (inst->register_state != REGISTER_STATE_REGISTERED) {
+                               if (inst->register_interval)
+                                       schedule_timer(&inst->register_retry_timer, inst->register_interval, 0);
+                               inst->register_state = REGISTER_STATE_REGISTERED;
+                       }
+                       /* start option timer */
+                       if (inst->options_interval)
+                               schedule_timer(&inst->register_option_timer, inst->options_interval, 0);
                        break;
                case 401:
                case 407:
                        PDEBUG(DEBUG_SIP, "Register challenge received\n");
-                       challenge(inst, NULL, status, phrase, nua, magic, nh, hmagic, sip, tags);
+                       rc = challenge(inst, NULL, status, phrase, nua, magic, nh, hmagic, sip, tags);
+                       if (rc < 0)
+                               goto status_400;
                        break;
                default:
                        if (status >= 200 && status <= 299)
                                goto status_200;
                        if (status < 400)
                                break;
+                       status_400:
                        PDEBUG(DEBUG_SIP, "Register failed, starting register timer\n");
                        inst->register_state = REGISTER_STATE_FAILED;
                        nua_handle_destroy(inst->register_handle);
+                       /* stop option timer */
                        unsched_timer(&inst->register_option_timer);
+                       /* if failed, start register interval timer with REGISTER_RETRY_TIMER */
                        schedule_timer(&inst->register_retry_timer, REGISTER_RETRY_TIMER);
                        inst->register_handle = NULL;
                        break;
@@ -2068,8 +2093,9 @@ static void sip_callback(nua_event_t event, int status, char const *phrase, nua_
        switch (status) {
        case 401:
        case 407:
-               challenge(inst, psip, status, phrase, nua, magic, nh, hmagic, sip, tags);
-               return;
+               rc = challenge(inst, psip, status, phrase, nua, magic, nh, hmagic, sip, tags);
+               if (rc >= 0)
+                       return;
        }
 
        switch (event) {
@@ -2138,6 +2164,7 @@ static void stun_bind_cb(stun_discovery_magic_t *magic, stun_handle_t *sh, stun_
                }
                su_inet_ntop(sa.su_family, SU_ADDR(&sa), inst->public_ip, sizeof(inst->public_ip));
                inst->stun_state = STUN_STATE_RESOLVED;
+               /* start timer for next stun request with inst->stun_interval */
                schedule_timer(&inst->stun_retry_timer, inst->stun_interval, 0);
                sip_trace_header(NULL, inst->interface_name, "STUN resolved", DIRECTION_OUT);
                add_trace("ip", "addr", "%s", inst->public_ip);
@@ -2147,6 +2174,7 @@ static void stun_bind_cb(stun_discovery_magic_t *magic, stun_handle_t *sh, stun_
 failed:
                PDEBUG(DEBUG_SIP, "STUN failed, starting timer\n");
                inst->stun_state = STUN_STATE_FAILED;
+               /* start timer for next stun request (after failing) with STUN_RETRY_TIMER */
                schedule_timer(&inst->stun_retry_timer, STUN_RETRY_TIMER);
                sip_trace_header(NULL, inst->interface_name, "STUN failed", DIRECTION_OUT);
                end_trace();
@@ -2191,8 +2219,6 @@ static int invite_option_timer(struct lcr_timer *timer, void *instance, int inde
        nua_options(psip->p_s_handle,
                TAG_END());
 
-//     schedule_timer(&psip->p_s_invite_option_timer, inst->options_timeout, 0);
-
        return 0;
 }
 
@@ -2211,6 +2237,14 @@ static int register_retry_timer(struct lcr_timer *timer, void *instance, int ind
        struct sip_inst *inst = (struct sip_inst *)instance;
 
        PDEBUG(DEBUG_SIP, "timeout, restart register\n");
+       /* if we have a handle, destroy it and becom unregistered, so registration is
+        * triggered next */
+       if (inst->register_handle) {
+               /* stop option timer */
+               unsched_timer(&inst->register_option_timer);
+               nua_handle_destroy(inst->register_handle);
+               inst->register_handle = NULL;
+       }
        inst->register_state = REGISTER_STATE_UNREGISTERED;
 
        return 0;
@@ -2225,8 +2259,6 @@ static int register_option_timer(struct lcr_timer *timer, void *instance, int in
        nua_options(inst->register_handle,
                TAG_END());
 
-//     schedule_timer(&inst->register_option_timer, inst->options_timeout, 0);
-
        return 0;
 }
 
@@ -2246,7 +2278,8 @@ int sip_init_inst(struct interface *interface)
        }
        SCPY(inst->auth_user, interface->sip_auth_user);
        SCPY(inst->auth_password, interface->sip_auth_password);
-       inst->options_timeout = interface->sip_options_timer;
+       inst->register_interval = interface->sip_register_interval;
+       inst->options_interval = interface->sip_options_interval;
 
        inst->rtp_port_from = interface->rtp_port_from;
        inst->rtp_port_to = interface->rtp_port_to;