+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;
+ char const *realm = NULL;
+ char const *scheme = NULL;
+ 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) {
+ authenticate = sip->sip_proxy_authenticate;
+ } else {
+ PDEBUG(DEBUG_SIP, "No authentication header found\n");
+ sip_trace_header(psip, inst->interface_name, "AUTHENTICATE", DIRECTION_OUT);
+ add_trace("error", NULL, "Authentication method unknwon");
+ end_trace();
+ return -1;
+ }
+
+ scheme = (char const *) authenticate->au_scheme;
+ if (authenticate->au_params) {
+ for (i = 0; (cur = (char *) authenticate->au_params[i]); i++) {
+ if ((realm = strstr(cur, "realm="))) {
+ realm += 6;
+ break;
+ }
+ }
+ }
+
+ if (!scheme || !realm) {
+ PDEBUG(DEBUG_SIP, "No scheme or no realm in authentication header found\n");
+ sip_trace_header(psip, inst->interface_name, "AUTHENTICATE", DIRECTION_OUT);
+ add_trace("error", NULL, "Authentication header has no realm or scheme");
+ end_trace();
+ return -1;
+ }
+
+ SPRINT(authentication, "%s:%s:%s:%s", scheme, realm, inst->auth_user, inst->auth_password);
+ PDEBUG(DEBUG_SIP, "auth: '%s'\n", authentication);
+
+ sip_trace_header(psip, inst->interface_name, "AUTHENTICATE", DIRECTION_OUT);
+ add_trace("scheme", NULL, "%s", scheme);
+ add_trace("realm", NULL, "%s", realm);
+ add_trace("user", NULL, "%s", inst->auth_user);
+ add_trace("pass", NULL, "%s", inst->auth_password);
+ end_trace();
+
+ 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) {
+ 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);
+ inst->auth_nonce[0] = '\0';
+ }
+
+ 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[])