fixup
[lcr.git] / sip.cpp
diff --git a/sip.cpp b/sip.cpp
index 3537dd0..b5d9635 100644 (file)
--- a/sip.cpp
+++ b/sip.cpp
@@ -54,6 +54,8 @@ struct sip_inst {
        char                    interface_name[64];
        char                    local_peer[128];
        char                    remote_peer[128];
+       char                    asserted_id[128];
+       int                     allow_register;
        int                     register_state;
        char                    register_user[128];
        char                    register_host[128];
@@ -435,6 +437,8 @@ int Psip::rtp_open(void)
        unsigned int ip;
        unsigned short start_port;
 
+       PDEBUG(DEBUG_SIP, "rtp_open\n");
+
        /* create socket */
        rc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
        if (rc < 0) {
@@ -454,7 +458,6 @@ int Psip::rtp_open(void)
 
        /* bind socket */
        ip = htonl(INADDR_ANY);
-//     ia.s_addr = ip;
        start_port = inst->next_rtp_port;
        while (1) {
                rc = rtp_sub_socket_bind(p_s_rtp_fd.fd, &p_s_rtp_sin_local, ip, inst->next_rtp_port);
@@ -503,6 +506,8 @@ int Psip::rtp_connect(void)
        struct in_addr ia;
 
        ia.s_addr = htonl(p_s_rtp_ip_remote);
+       if (p_s_rtp_is_connected)
+               PDEBUG(DEBUG_SIP, "reconnecting existing RTP connection to new/same destination\n");
        PDEBUG(DEBUG_SIP, "rtp_connect(ip=%s, port=%u)\n", inet_ntoa(ia), p_s_rtp_port_remote);
 
        rc = rtp_sub_socket_connect(p_s_rtp_fd.fd, &p_s_rtp_sin_local, &p_s_rtp_sin_remote, p_s_rtp_ip_remote, p_s_rtp_port_remote);
@@ -882,12 +887,18 @@ unsigned int Psip::get_local_ip(unsigned int ip)
 int Psip::message_connect(unsigned int epoint_id, int message_id, union parameter *param)
 {
        struct sip_inst *inst = (struct sip_inst *) p_s_sip_inst;
-       char sdp_str[256];
-       struct in_addr ia;
+       const char *sdp_str = NULL;
        struct lcr_msg *message;
+       struct interface *interface;
        int media_type;
        unsigned char payload_type;
 
+       interface = getinterfacebyname(inst->interface_name);
+       if (!interface) {
+               PERROR("Cannot find interface %s.\n", inst->interface_name);
+               return 0;
+       }
+
        if (param->connectinfo.rtpinfo.port) {
                PDEBUG(DEBUG_SIP, "RTP info given by remote, forward that\n");
                p_s_rtp_bridge = 1;
@@ -903,7 +914,7 @@ int Psip::message_connect(unsigned int epoint_id, int message_id, union paramete
                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 (!p_s_rtp_is_connected && rtp_connect() < 0) {
+               if (rtp_connect() < 0) {
                        nua_cancel(p_s_handle, TAG_END());
                        nua_handle_destroy(p_s_handle);
                        p_s_handle = NULL;
@@ -920,17 +931,7 @@ int Psip::message_connect(unsigned int epoint_id, int message_id, union paramete
                }
        }
 
-       memset(&ia, 0, sizeof(ia));
-       ia.s_addr = htonl(get_local_ip(p_s_rtp_ip_local));
-       SPRINT(sdp_str,
-               "v=0\r\n"
-               "o=LCR-Sofia-SIP 0 0 IN IP4 %s\r\n"
-               "s=SIP Call\r\n"
-               "c=IN IP4 %s\r\n"
-               "t=0 0\r\n"
-               "m=audio %d RTP/AVP %d\r\n"
-               "a=rtpmap:%d %s/8000\r\n"
-               , inet_ntoa(ia), inet_ntoa(ia), p_s_rtp_port_local, payload_type, payload_type, media_type2name(media_type));
+       sdp_str = generate_sdp(p_s_rtp_ip_local, p_s_rtp_port_local, 1, &payload_type, &media_type);
        PDEBUG(DEBUG_SIP, "Using SDP response: %s\n", sdp_str);
 
        /* NOTE:
@@ -948,6 +949,9 @@ int Psip::message_connect(unsigned int epoint_id, int message_id, union paramete
        sip_trace_header(this, inst->interface_name, "RESPOND", DIRECTION_OUT);
        add_trace("respond", "value", "200 OK");
        add_trace("reason", NULL, "call connected");
+       struct in_addr ia;
+       memset(&ia, 0, sizeof(ia));
+       ia.s_addr = htonl(get_local_ip(p_s_rtp_ip_local));
        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", "%s:%d", media_type2name(media_type), payload_type);
@@ -1025,13 +1029,13 @@ int Psip::message_setup(unsigned int epoint_id, int message_id, union parameter
 {
        struct sip_inst *inst = (struct sip_inst *) p_s_sip_inst;
        char from[128] = "";
+       char asserted_id[128] = "", asserted_msg[256] = "";
        char to[128] = "";
        char contact[128] = "";
        const char *local = inst->local_peer;
        char local_ip[16];
        const char *remote = inst->remote_peer;
-       char sdp_str[512], pt_str[32];
-       struct in_addr ia;
+       const char *sdp_str = NULL;
        struct epoint_list *epointlist;
        sip_cseq_t *cseq = NULL;
        struct lcr_msg *message;
@@ -1106,8 +1110,6 @@ int Psip::message_setup(unsigned int epoint_id, int message_id, union parameter
                }
        }
 
-       memset(&ia, 0, sizeof(ia));
-       ia.s_addr = htonl(get_local_ip(p_s_rtp_ip_local));
        p_s_handle = nua_handle(inst->nua, NULL, TAG_END());
        if (!p_s_handle) {
                PERROR("Failed to create handle\n");
@@ -1125,33 +1127,31 @@ int Psip::message_setup(unsigned int epoint_id, int message_id, union parameter
 //     add_trace("handle", "new", "0x%x", p_s_handle);
 //     end_trace();
 
-       SPRINT(sdp_str,
-               "v=0\r\n"
-               "o=LCR-Sofia-SIP 0 0 IN IP4 %s\r\n"
-               "s=SIP Call\r\n"
-               "c=IN IP4 %s\r\n"
-               "t=0 0\r\n"
-               "m=audio %d RTP/AVP"
-               , inet_ntoa(ia), inet_ntoa(ia), p_s_rtp_port_local);
-       for (i = 0; i < payloads; i++) {
-               SPRINT(pt_str, " %d", payload_types[i]);
-               SCAT(sdp_str, pt_str);
-       }
-       SCAT(sdp_str, "\r\n");
-       for (i = 0; i < payloads; i++) {
-               SPRINT(pt_str, "a=rtpmap:%d %s/8000\r\n", payload_types[i], media_type2name(media_types[i]));
-               SCAT(sdp_str, pt_str);
-       }
+       sdp_str = generate_sdp(p_s_rtp_ip_local, p_s_rtp_port_local, payloads, payload_types, media_types);
        PDEBUG(DEBUG_SIP, "Using SDP for invite: %s\n", sdp_str);
 
        SPRINT(from, "sip:%s@%s", p_callerinfo.id, remote);
        SPRINT(to, "sip:%s@%s", p_dialinginfo.id, remote);
-       if (inst->public_ip[0])
+       if (inst->asserted_id[0]) {
+               SPRINT(asserted_id, "sip:%s@%s", inst->asserted_id, remote);
+               SPRINT(asserted_msg, "P-Asserted-Identity: <%s>", asserted_id);
+       }
+       if (inst->public_ip[0]) {
+               char *p;
                SPRINT(contact, "sip:%s@%s", p_callerinfo.id, inst->public_ip);
+               p = strchr(inst->local_peer, ':');
+               if (p)
+                       SCAT(contact, p);
+       }
 
        sip_trace_header(this, inst->interface_name, "INVITE", DIRECTION_OUT);
        add_trace("from", "uri", "%s", from);
        add_trace("to", "uri", "%s", to);
+       if (asserted_id[0])
+               add_trace("assert-id", "uri", "%s", asserted_id);
+       struct in_addr ia;
+       memset(&ia, 0, sizeof(ia));
+       ia.s_addr = htonl(get_local_ip(p_s_rtp_ip_local));
        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);
        for (i = 0; i < payloads; i++)
@@ -1163,6 +1163,7 @@ int Psip::message_setup(unsigned int epoint_id, int message_id, union parameter
        nua_invite(p_s_handle,
                TAG_IF(from[0], SIPTAG_FROM_STR(from)),
                TAG_IF(to[0], SIPTAG_TO_STR(to)),
+               TAG_IF(asserted_msg[0], SIPTAG_HEADER_STR(asserted_msg)),
                TAG_IF(contact[0], SIPTAG_CONTACT_STR(contact)),
                TAG_IF(cseq, SIPTAG_CSEQ(cseq)),
                NUTAG_MEDIA_ENABLE(0),
@@ -1205,6 +1206,7 @@ int Psip::message_notify(unsigned int epoint_id, int message_id, union parameter
        switch (param->notifyinfo.notify) {
        case INFO_NOTIFY_REMOTE_HOLD:
 #if 0
+               sdp_str = generate_sdp(0, 0, 0, NULL, NULL);
                SPRINT(sdp_str,
                        "v=0\r\n"
                        "o=LCR-Sofia-SIP 0 0 IN IP4 0.0.0.0\r\n"
@@ -1224,17 +1226,7 @@ int Psip::message_notify(unsigned int epoint_id, int message_id, union parameter
                break;
        case INFO_NOTIFY_REMOTE_RETRIEVAL:
 #if 0
-               memset(&ia, 0, sizeof(ia));
-               ia.s_addr = htonl(get_local_ip(p_s_rtp_ip_local));
-               SPRINT(sdp_str,
-                       "v=0\r\n"
-                       "o=LCR-Sofia-SIP 0 0 IN IP4 %s\r\n"
-                       "s=SIP Call\r\n"
-                       "c=IN IP4 %s\r\n"
-                       "t=0 0\r\n"
-                       "m=audio %d RTP/AVP %d\r\n"
-                       "a=rtpmap:%d %s/8000\r\n"
-                       , inet_ntoa(ia), inet_ntoa(ia), p_s_rtp_port_local, p_s_rtp_payload_type, p_s_rtp_payload_type, media_type2name(p_s_rtp_media_type));
+               sdp_str = generate_sdp(p_s_rtp_ip_local, p_s_rtp_port_local, 1, &payload_type, &media_type);
                PDEBUG(DEBUG_SIP, "Using SDP for rertieve: %s\n", sdp_str);
                nua_info(p_s_handle,
 //                     TAG_IF(from[0], SIPTAG_FROM_STR(from)),
@@ -1340,7 +1332,7 @@ int Psip::message_epoint(unsigned int epoint_id, int message_id, union parameter
                return(1);
 
                default:
-               PDEBUG(DEBUG_SIP, "PORT(%s) SP port with (caller id %s) received an unsupported message: %d\n", p_name, p_callerinfo.id, message_id);
+               PDEBUG(DEBUG_SIP, "PORT(%s) SIP port with (caller id %s) received an unsupported message: %d\n", p_name, p_callerinfo.id, message_id);
        }
 
        return 0;
@@ -1436,6 +1428,37 @@ int Psip::parse_sdp(sip_t const *sip, unsigned int *ip, unsigned short *port, ui
        return 0;
 }
 
+const char *Psip::generate_sdp(unsigned int rtp_ip_local, unsigned short rtp_port_local, int payloads, unsigned char *payload_types, int *media_types)
+{
+       struct in_addr ia;
+       static char sdp_str[256], sub_str[128];
+       int i;
+
+       memset(&ia, 0, sizeof(ia));
+       ia.s_addr = htonl(get_local_ip(p_s_rtp_ip_local));
+       SPRINT(sdp_str,
+               "v=0\r\n"
+               "o=LCR-Sofia-SIP 0 0 IN IP4 %s\r\n"
+               "s=SIP Call\r\n"
+               "c=IN IP4 %s\r\n"
+               "t=0 0\r\n", inet_ntoa(ia), inet_ntoa(ia));
+       if (payloads) {
+               SPRINT(sub_str, "m=audio %d RTP/AVP", p_s_rtp_port_local);
+               SCAT(sdp_str, sub_str);
+               for (i = 0; i < payloads; i++) {
+                       SPRINT(sub_str, " %d", payload_types[i]);
+                       SCAT(sdp_str, sub_str);
+               }
+               SCAT(sdp_str, "\r\n");
+               for (i = 0; i < payloads; i++) {
+                       SPRINT(sub_str, "a=rtpmap:%d %s/8000\r\n", payload_types[i], media_type2name(media_types[i]));
+                       SCAT(sdp_str, sub_str);
+               }
+       }
+
+       return sdp_str;
+}
+
 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 tags[])
 {
        sip_www_authenticate_t const *authenticate = NULL;
@@ -1499,6 +1522,25 @@ static int challenge(struct sip_inst *inst, class Psip *psip, int status, char c
        return 0;
 }
 
+static void i_options(struct sip_inst *inst, 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[])
+{
+       #define NUTAG_WITH_THIS_MSG(msg) nutag_with, tag_ptr_v(msg)
+       nua_saved_event_t saved[1];
+       nua_save_event(nua, saved);
+       nua_event_data_t const *data = nua_event_data(saved);
+
+       sip_trace_header(NULL, inst->interface_name, "OPTIONS", DIRECTION_IN);
+       end_trace();
+
+       sip_trace_header(NULL, inst->interface_name, "RESPOND", DIRECTION_OUT);
+       add_trace("respond", "value", "200 OK");
+       end_trace();
+
+       nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS_MSG(data->e_msg), TAG_END());
+       nua_handle_destroy(nh);
+       inst->register_handle = NULL;
+}
+
 static void i_register(struct sip_inst *inst, 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[])
 {
        #define NUTAG_WITH_THIS_MSG(msg) nutag_with, tag_ptr_v(msg)
@@ -1508,6 +1550,16 @@ static void i_register(struct sip_inst *inst, int status, char const *phrase, nu
        nua_save_event(nua, saved);
        nua_event_data_t const *data = nua_event_data(saved);
 
+       if (!inst->allow_register) {
+               sip_trace_header(NULL, inst->interface_name, "REGISTER", DIRECTION_IN);
+               add_trace("error", NULL, "forbidden, because we don't accept registration");
+               end_trace();
+               nua_respond(nh, SIP_403_FORBIDDEN, NUTAG_WITH_THIS_MSG(data->e_msg), TAG_END());
+               nua_handle_destroy(nh);
+               inst->register_handle = NULL;
+               return;
+       }
+
        if (contact->m_url->url_host)
                SCPY(inst->remote_peer, contact->m_url->url_host);
        if (contact->m_url->url_port && contact->m_url->url_port[0]) {
@@ -1549,6 +1601,7 @@ static void r_register(struct sip_inst *inst, int status, char const *phrase, nu
                }
                /* start option timer */
                if (inst->options_interval)
+                       PDEBUG(DEBUG_SIP, "register ok, scheduling option timer with %d seconds\n", inst->options_interval);
                        schedule_timer(&inst->register_option_timer, inst->options_interval, 0);
                break;
        case 401:
@@ -1584,9 +1637,11 @@ void Psip::i_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag
        class Endpoint *epoint;
        struct lcr_msg *message;
        struct interface *interface;
+       const char *sdp_str = NULL;
        int media_types[32];
        uint8_t payload_types[32];
        int payloads = 0;
+       unsigned char payload_type;
        int media_type;
 
        interface = getinterfacebyname(inst->interface_name);
@@ -1646,11 +1701,45 @@ void Psip::i_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag
                        add_trace("respond", "value", "400 Bad Request");
                add_trace("reason", NULL, "offered codec does not match");
                end_trace();
+               if (p_state != PORT_STATE_IDLE) {
+                       message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_RELEASE);
+                       message->param.disconnectinfo.cause = 41;
+                       message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
+                       message_put(message);
+               }
                new_state(PORT_STATE_RELEASE);
                trigger_work(&p_s_delete);
                return;
        }
 
+       /* handle re-invite */
+       if (p_state != PORT_STATE_IDLE) {
+               sip_trace_header(this, inst->interface_name, "RE-INVITE", DIRECTION_IN);
+               end_trace();
+               if (p_s_rtp_bridge) {
+                       PDEBUG(DEBUG_SIP, "RE-INVITE not implemented for RTP forwarding\n");
+                       nua_respond(nh, SIP_501_NOT_IMPLEMENTED, TAG_END());
+                       sip_trace_header(this, inst->interface_name, "RESPOND", DIRECTION_OUT);
+                       add_trace("respond", "value", "501 NOT IMPLEMENTED");
+                       add_trace("reason", NULL, "RE-INVITE not implemented for RTP forwarding");
+                       end_trace();
+               } else {
+                       PDEBUG(DEBUG_SIP, "RTP info given by remote, forward that\n");
+                       media_type = (options.law=='a') ? MEDIA_TYPE_ALAW : MEDIA_TYPE_ULAW;
+                       payload_type = (options.law=='a') ? PAYLOAD_TYPE_ALAW : PAYLOAD_TYPE_ULAW;
+                       if (rtp_connect() < 0) {
+                               goto rtp_failed;
+                       }
+                       sdp_str = generate_sdp(p_s_rtp_ip_local, p_s_rtp_port_local, 1, &payload_type, &media_type);
+                       PDEBUG(DEBUG_SIP, "Using SDP response: %s\n", sdp_str);
+                       nua_respond(p_s_handle, SIP_200_OK,
+                               NUTAG_MEDIA_ENABLE(0),
+                               SIPTAG_CONTENT_TYPE_STR("application/sdp"),
+                               SIPTAG_PAYLOAD_STR(sdp_str), TAG_END());
+               }
+               return;
+       }
+
        /* open local RTP peer (if not bridging) */
        if (!p_s_rtp_bridge && rtp_open() < 0) {
                nua_respond(nh, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
@@ -1757,23 +1846,22 @@ 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");
        /* start option timer */
-       if (inst->options_interval)
+       if (inst->options_interval) {
+               PDEBUG(DEBUG_SIP, "Invite received, scheduling option timer with %d seconds\n", 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 */
        if (!p_s_rtp_bridge && interface->is_tones == IS_YES) {
-               char sdp_str[256];
-               struct in_addr ia;
-               unsigned char payload_type;
-
                PDEBUG(DEBUG_SIP, "Connecting audio, since we have tones available\n");
                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) {
+rtp_failed:
                        nua_respond(nh, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
                        nua_handle_destroy(nh);
                        p_s_handle = NULL;
@@ -1781,8 +1869,6 @@ void Psip::i_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag
                        add_trace("respond", "value", "500 Internal Server Error");
                        add_trace("reason", NULL, "failed to connect RTP/RTCP sockts");
                        end_trace();
-                       new_state(PORT_STATE_RELEASE);
-                       trigger_work(&p_s_delete);
                        message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_RELEASE);
                        message->param.disconnectinfo.cause = 41;
                        message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
@@ -1792,17 +1878,7 @@ void Psip::i_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag
                        return;
                }
 
-               memset(&ia, 0, sizeof(ia));
-               ia.s_addr = htonl(get_local_ip(p_s_rtp_ip_local));
-               SPRINT(sdp_str,
-                       "v=0\r\n"
-                       "o=LCR-Sofia-SIP 0 0 IN IP4 %s\r\n"
-                       "s=SIP Call\r\n"
-                       "c=IN IP4 %s\r\n"
-                       "t=0 0\r\n"
-                       "m=audio %d RTP/AVP %d\r\n"
-                       "a=rtpmap:%d %s/8000\r\n"
-                       , inet_ntoa(ia), inet_ntoa(ia), p_s_rtp_port_local, payload_type, payload_type, media_type2name(media_type));
+               sdp_str = generate_sdp(p_s_rtp_ip_local, p_s_rtp_port_local, 1, &payload_type, &media_type);
                PDEBUG(DEBUG_SIP, "Using SDP response: %s\n", sdp_str);
 
                nua_respond(p_s_handle, SIP_183_SESSION_PROGRESS,
@@ -1812,6 +1888,9 @@ void Psip::i_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag
                sip_trace_header(this, inst->interface_name, "RESPOND", DIRECTION_OUT);
                add_trace("respond", "value", "183 SESSION PROGRESS");
                add_trace("reason", NULL, "audio available");
+               struct in_addr ia;
+               memset(&ia, 0, sizeof(ia));
+               ia.s_addr = htonl(get_local_ip(p_s_rtp_ip_local));
                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", "%s:%d", media_type2name(media_type), payload_type);
@@ -1819,6 +1898,18 @@ void Psip::i_invite(int status, char const *phrase, nua_t *nua, nua_magic_t *mag
        }
 }
 
+void Psip::i_options(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[])
+{
+       struct sip_inst *inst = (struct sip_inst *) p_s_sip_inst;
+
+       PDEBUG(DEBUG_SIP, "options received\n");
+
+       sip_trace_header(this, inst->interface_name, "OPTIONS", DIRECTION_IN);
+       end_trace();
+
+       nua_respond(nh, SIP_200_OK, TAG_END());
+}
+
 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 tags[])
 {
        struct sip_inst *inst = (struct sip_inst *) p_s_sip_inst;
@@ -1963,10 +2054,11 @@ 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");
        /* start option timer */
-       if (inst->options_interval)
+       if (inst->options_interval) {
+               PDEBUG(DEBUG_SIP, "Invite response, scheduling option timer with %d seconds\n", inst->options_interval);
                schedule_timer(&p_s_invite_option_timer, inst->options_interval, 0);
+       }
 
        switch (status) {
        case 100:
@@ -2054,7 +2146,7 @@ void Psip::r_options(int status, char const *phrase, nua_t *nua, nua_magic_t *ma
        PDEBUG(DEBUG_SIP, "options result %d received\n", status);
 
        if (status >= 200 && status <= 299) {
-               PDEBUG(DEBUG_SIP, "options ok, scheduling timer\n");
+               PDEBUG(DEBUG_SIP, "options ok, scheduling option timer with %d seconds\n", inst->options_interval);
                /* restart option timer */
                schedule_timer(&p_s_invite_option_timer, inst->options_interval, 0);
                return;
@@ -2081,6 +2173,17 @@ void Psip::r_options(int status, char const *phrase, nua_t *nua, nua_magic_t *ma
        trigger_work(&p_s_delete);
 }
 
+void Psip::i_state(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[])
+{
+       struct sip_inst *inst = (struct sip_inst *) p_s_sip_inst;
+
+       PDEBUG(DEBUG_SIP, "state change received\n");
+       sip_trace_header(this, inst->interface_name, "STATUS", DIRECTION_OUT);
+       add_trace("value", NULL, "%d", status);
+       add_trace("phrase", NULL, "%s", phrase);
+       end_trace();
+}
+
 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[])
 {
        struct sip_inst *inst = (struct sip_inst *) magic;
@@ -2098,21 +2201,31 @@ static void sip_callback(nua_event_t event, int status, char const *phrase, nua_
                if ((port->p_type & PORT_CLASS_mISDN_MASK) == PORT_CLASS_SIP) {
                        psip = (class Psip *)port;
                        if (psip->p_s_handle == nh) {
+                               PDEBUG(DEBUG_SIP, "Event found for port %s\n", psip->p_name);
                                break;
                        }
                }
                port = port->next;
        }
+       if (!port)
+               psip = NULL;
 
        /* new handle */
-       if (!port && !inst->register_handle) {
-               switch (event) {
-               case nua_i_register:
+       switch (event) {
+       case nua_i_options:
+               if (!inst->register_handle) {
+                       PDEBUG(DEBUG_SIP, "New options instance\n");
+                       inst->register_handle = nh;
+               }
+               break;
+       case nua_i_register:
+               if (!inst->register_handle) {
                        PDEBUG(DEBUG_SIP, "New register instance\n");
                        inst->register_handle = nh;
-                       break;
-               case nua_i_invite:
-                   {
+               }
+               break;
+       case nua_i_invite:
+               if (!psip) {
                        char name[64];
                        struct interface *interface = interface_first;
 
@@ -2125,23 +2238,26 @@ static void sip_callback(nua_event_t event, int status, char const *phrase, nua_
                                        break;
                                interface = interface->next;
                        }
-                       if (!interface) {
-                               PERROR("Cannot find interface %s.\n", inst->interface_name);
-                               return;
-                       }
+                       if (!interface)
+                               FATAL("Cannot find interface %s.\n", inst->interface_name);
                        if (!(psip = new Psip(PORT_TYPE_SIP_IN, name, NULL, interface)))
                                FATAL("Cannot create Port instance.\n");
-                       break;
-                   }
-               default:
+               }
+               break;
+       default:
+               if (!psip && !inst->register_handle) {
                        PDEBUG(DEBUG_SIP, "Destroying unknown instance\n");
                        nua_handle_destroy(nh);
+                       return;
                }
        }
 
        /* handle register process */
        if (inst->register_handle == nh) {
                switch (event) {
+               case nua_i_options:
+                       i_options(inst, status, phrase, nua, magic, nh, hmagic, sip, tags);
+                       break;
                case nua_i_register:
                        i_register(inst, status, phrase, nua, magic, nh, hmagic, sip, tags);
                        break;
@@ -2162,12 +2278,6 @@ static void sip_callback(nua_event_t event, int status, char const *phrase, nua_
                return;
        }
 
-#warning fixme: wann eine response
-       sip_trace_header(psip, inst->interface_name, "STATUS", DIRECTION_OUT);
-       add_trace("value", NULL, "%d", status);
-       add_trace("phrase", NULL, "%s", phrase);
-       end_trace();
-
        switch (status) {
        case 401:
        case 407:
@@ -2187,7 +2297,7 @@ static void sip_callback(nua_event_t event, int status, char const *phrase, nua_
                PDEBUG(DEBUG_SIP, "error received\n");
                break;
        case nua_i_state:
-               PDEBUG(DEBUG_SIP, "state change received\n");
+               psip->i_state(status, phrase, nua, magic, nh, hmagic, sip, tags);
                break;
        case nua_i_invite:
                psip->i_invite(status, phrase, nua, magic, nh, hmagic, sip, tags);
@@ -2198,6 +2308,9 @@ static void sip_callback(nua_event_t event, int status, char const *phrase, nua_
        case nua_i_active:
                PDEBUG(DEBUG_SIP, "active received\n");
                break;
+       case nua_i_options:
+               psip->i_options(status, phrase, nua, magic, nh, hmagic, sip, tags);
+               break;
        case nua_i_bye:
                psip->i_bye(status, phrase, nua, magic, nh, hmagic, sip, tags);
                break;
@@ -2346,6 +2459,9 @@ int sip_init_inst(struct interface *interface)
        SCPY(inst->interface_name, interface->name);
        SCPY(inst->local_peer, interface->sip_local_peer);
        SCPY(inst->remote_peer, interface->sip_remote_peer);
+       if (!inst->remote_peer[0])
+               inst->allow_register = 1;
+       SCPY(inst->asserted_id, interface->sip_asserted_id);
        if (interface->sip_register) {
                inst->register_state = REGISTER_STATE_UNREGISTERED;
                SCPY(inst->register_user, interface->sip_register_user);
@@ -2409,15 +2525,6 @@ int sip_init_inst(struct interface *interface)
 
        SCPY(inst->public_ip, interface->sip_public_ip);
        if (interface->sip_stun_server[0]) {
-#if 0
-               inst->stun_root = su_root_create(inst);
-               if (!inst->stun_root) {
-                       PERROR("Failed to create STUN root\n");
-                       sip_exit_inst(interface);
-                       return -EINVAL;
-               }
-               auch im exit
-#endif
                SCPY(inst->stun_server, interface->sip_stun_server);
                inst->stun_interval = interface->sip_stun_interval;
                inst->stun_handle = stun_handle_init(inst->root,
@@ -2481,7 +2588,6 @@ void sip_exit_inst(struct interface *interface)
 
 extern su_log_t su_log_default[];
 extern su_log_t nua_log[];
-//extern su_log_t soa_log[];
 
 int sip_init(void)
 {
@@ -2563,8 +2669,13 @@ static void sip_handle_register(struct sip_inst *inst)
 
                SPRINT(from, "sip:%s@%s", inst->register_user, inst->register_host);
                SPRINT(to, "sip:%s@%s", inst->register_user, inst->register_host);
-               if (inst->public_ip[0])
+               if (inst->public_ip[0]) {
+                       char *p;
                        SPRINT(contact, "sip:%s@%s", inst->register_user, inst->public_ip);
+                       p = strchr(inst->local_peer, ':');
+                       if (p)
+                               SCAT(contact, p);
+               }
 
                sip_trace_header(NULL, inst->interface_name, "REGISTER", DIRECTION_OUT);
                add_trace("from", "uri", "%s", from);
@@ -2713,4 +2824,3 @@ void Psip::load_tx(void)
        rtp_send_frame(buf, SEND_SIP_LEN, (options.law=='a')?PAYLOAD_TYPE_ALAW:PAYLOAD_TYPE_ULAW);
 }
 
-#warning den source-port beim registrieren einstellen