+ nua_authenticate(nh, /*SIPTAG_EXPIRES_STR("3600"),*/ NUTAG_AUTH(authentication), TAG_END());
+
+ 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)
+ nua_saved_event_t saved[1];
+ sip_contact_t const *contact = NULL;
+ contact = sip->sip_contact;
+ nua_save_event(nua, saved);
+ nua_event_data_t const *data = nua_event_data(saved);
+ sip_authorization_t const *authorization;
+ char uri[256] = "";
+ const char *auth_text = NULL;
+ char auth_str[256] = "";
+
+ if (contact->m_url->url_host)
+ SCPY(uri, contact->m_url->url_host);
+ if (contact->m_url->url_port && contact->m_url->url_port[0]) {
+ SCAT(uri, ":");
+ SCAT(uri, contact->m_url->url_port);
+ }
+
+ 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;
+ }
+
+ sip_trace_header(NULL, inst->interface_name, "REGISTER", DIRECTION_IN);
+ add_trace("contact", "uri", "%s", uri);
+ end_trace();
+
+ sip_trace_header(NULL, inst->interface_name, "Authorization", DIRECTION_IN);
+ if (inst->auth_realm[0]) {
+ authorization = sip->sip_authorization;
+ status = check_authorization(authorization, "REGISTER", inst->auth_user, inst->auth_password, inst->auth_realm, inst->auth_nonce, &auth_text);
+ if (status == 401) {
+ if (!inst->auth_nonce[0])
+ generate_nonce(inst->auth_nonce);
+ SPRINT(auth_str, "Digest realm=\"%s\", nonce=\"%s\", algorithm=MD5, qop=\"auth\"", inst->auth_realm, inst->auth_nonce);
+ }
+ } else {
+ status = 200;
+ auth_text = "Authentication not required";
+ }
+ add_trace("result", NULL, "%s", auth_text);
+ end_trace();
+
+ if (status == 200) {
+ SCPY(inst->remote_peer, uri);
+ }
+
+ sip_trace_header(NULL, inst->interface_name, "RESPOND", DIRECTION_OUT);
+ add_trace("respond", "value", "%d", status);
+ add_trace("reason", NULL, "peer registers");
+ end_trace();
+
+ nua_respond(nh, status, auth_text, SIPTAG_CONTACT(sip->sip_contact), NUTAG_WITH_THIS_MSG(data->e_msg), TAG_IF(auth_str[0], SIPTAG_WWW_AUTHENTICATE_STR(auth_str)), TAG_END());
+ nua_handle_destroy(nh);
+ inst->register_handle = NULL;
+}
+
+static void r_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[])
+{
+ int rc;
+
+ sip_trace_header(NULL, inst->interface_name, "STATUS", DIRECTION_IN);
+ add_trace("value", NULL, "%d", status);
+ add_trace("phrase", NULL, "%s", phrase);
+ end_trace();
+
+ switch (status) {
+ case 200:
+ status_200:
+ /* 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)
+ 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:
+ case 407:
+ PDEBUG(DEBUG_SIP, "Register challenge received\n");
+ 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(nh);
+ inst->register_handle = NULL;
+ /* 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);
+ }
+}
+
+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 tags[])
+{
+ struct sip_inst *inst = (struct sip_inst *) p_s_sip_inst;
+ const char *from = "", *to = "", *name = "";
+ char imsi[16] = "";
+ int ret;
+ 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;
+ sip_authorization_t const *authorization;
+ const char *auth_text = NULL;
+ char auth_str[256] = "";
+
+ interface = getinterfacebyname(inst->interface_name);
+ if (!interface) {
+ PERROR("Cannot find interface %s.\n", inst->interface_name);
+ return;
+ }
+
+ 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, inst->interface_name, "Authorization", DIRECTION_IN);
+ if (inst->auth_realm[0] || p_state != PORT_STATE_IDLE) {
+ /* only authenticate remote, if we have a realm set and we don't have re-invite */
+ authorization = sip->sip_proxy_authorization;
+ status = check_authorization(authorization, "INVITE", inst->auth_user, inst->auth_password, inst->auth_realm, inst->auth_nonce, &auth_text);
+ if (status == 407) {
+ if (!inst->auth_nonce[0])
+ generate_nonce(inst->auth_nonce);
+ SPRINT(auth_str, "Digest realm=\"%s\", nonce=\"%s\", algorithm=MD5, qop=\"auth\"", inst->auth_realm, inst->auth_nonce);
+ }
+ } else {
+ status = 200;
+ auth_text = "Authentication not required";
+ }
+ add_trace("result", NULL, "%s", auth_text);
+ end_trace();
+
+ if (status == 200) {
+ } else {
+ sip_trace_header(this, inst->interface_name, "INVITE", DIRECTION_IN);
+ end_trace();
+
+ sip_trace_header(this, inst->interface_name, "RESPOND", DIRECTION_OUT);
+ add_trace("respond", "value", "%d", status);
+ add_trace("reason", NULL, "peer invited");
+ end_trace();
+
+ nua_respond(nh, status, auth_text, SIPTAG_CONTACT(sip->sip_contact), TAG_IF(auth_str[0], SIPTAG_PROXY_AUTHENTICATE_STR(auth_str)), TAG_END());
+ new_state(PORT_STATE_RELEASE);
+ trigger_work(&p_s_delete);
+ return;
+ }
+
+ sip_trace_header(this, inst->interface_name, "Payload received", DIRECTION_NONE);
+ ret = parse_sdp(sip, &p_s_rtp_ip_remote, &p_s_rtp_port_remote, payload_types, media_types, &payloads, sizeof(payload_types));
+ if (!ret) {
+ /* if no RTP bridge, we must support LAW codec, otherwise we forward what we have */
+ if (!p_s_rtp_bridge) {
+ int i;
+
+ /* check if supported payload type exists */
+ for (i = 0; i < payloads; i++) {
+ if (media_types[i] == ((options.law=='a') ? MEDIA_TYPE_ALAW : MEDIA_TYPE_ULAW))
+ break;
+ }
+ if (i == payloads) {
+ add_trace("error", NULL, "Expected LAW payload type (not bridged)");
+ ret = 415;
+ }
+ }
+ }
+ end_trace();
+ if (ret) {
+ if (ret == 400)
+ nua_respond(nh, SIP_400_BAD_REQUEST, TAG_END());
+ else
+ nua_respond(nh, SIP_415_UNSUPPORTED_MEDIA, TAG_END());
+ nua_handle_destroy(nh);
+ p_s_handle = NULL;
+ sip_trace_header(this, inst->interface_name, "RESPOND", DIRECTION_OUT);
+ if (ret == 400)
+ add_trace("respond", "value", "415 Unsupported Media");
+ else
+ 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());
+ nua_handle_destroy(nh);
+ p_s_handle = NULL;
+ sip_trace_header(this, inst->interface_name, "RESPOND", DIRECTION_OUT);
+ add_trace("respond", "value", "500 Internal Server Error");
+ add_trace("reason", NULL, "failed to open RTP/RTCP sockts");
+ end_trace();
+ new_state(PORT_STATE_RELEASE);
+ trigger_work(&p_s_delete);
+ return;
+ }
+
+ /* apply handle */
+// sip_trace_header(this, inst->interface_name, "NEW handle", DIRECTION_IN);
+// add_trace("handle", "new", "0x%x", nh);
+// end_trace();
+//
+ p_s_handle = nh;
+
+ sip_trace_header(this, inst->interface_name, "INVITE", DIRECTION_IN);
+ add_trace("rtp", "port", "%d", p_s_rtp_port_remote);
+ /* caller information */
+ if (!from[0]) {
+ p_callerinfo.present = INFO_PRESENT_NOTAVAIL;
+ p_callerinfo.ntype = INFO_NTYPE_NOTPRESENT;
+ add_trace("calling", "present", "unavailable");
+ } else {
+ p_callerinfo.present = INFO_PRESENT_ALLOWED;
+ add_trace("calling", "present", "allowed");
+ p_callerinfo.screen = INFO_SCREEN_NETWORK;
+ 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 */
+ if (to[0]) {
+ p_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
+ SCAT(p_dialinginfo.id, to);
+ add_trace("dialing", "number", "%s", to);
+ }
+ /* redir info */
+ /* bearer capability */
+ p_capainfo.bearer_capa = INFO_BC_SPEECH;
+ p_capainfo.bearer_info1 = (options.law=='a')?3:2;
+ p_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
+ add_trace("bearer", "capa", "speech");
+ add_trace("bearer", "mode", "circuit");
+ /* if packet mode works some day, see dss1.cpp for conditions */
+ p_capainfo.source_mode = B_MODE_TRANSPARENT;
+
+ end_trace();
+
+ /* create endpoint */
+ if (p_epointlist)
+ FATAL("Incoming call but already got an endpoint.\n");