/*
eXosip - This is the eXtended osip library.
Copyright (C) 2002, 2003 Aymeric MOIZARD - jack@atosc.org
eXosip is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
eXosip is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef ENABLE_MPATROL
#include <mpatrol.h>
#endif
#include "eXosip2.h"
extern eXosip_t eXosip;
int
_eXosip_build_response_default (osip_message_t ** dest,
osip_dialog_t * dialog, int status,
osip_message_t * request)
{
osip_generic_param_t *tag;
osip_message_t *response;
int pos;
int i;
*dest = NULL;
if (request == NULL)
return -1;
i = osip_message_init (&response);
if (i != 0)
return -1;
/* initialise osip_message_t structure */
/* yet done... */
response->sip_version = (char *) osip_malloc (8 * sizeof (char));
sprintf (response->sip_version, "SIP/2.0");
osip_message_set_status_code (response, status);
/* handle some internal reason definitions. */
if (MSG_IS_NOTIFY (request) && status == 481)
{
response->reason_phrase = osip_strdup ("Subscription Does Not Exist");
} else if (MSG_IS_SUBSCRIBE (request) && status == 202)
{
response->reason_phrase = osip_strdup ("Accepted subscription");
} else
{
response->reason_phrase = osip_strdup (osip_message_get_reason (status));
if (response->reason_phrase == NULL)
{
if (response->status_code == 101)
response->reason_phrase = osip_strdup ("Dialog Establishement");
else
response->reason_phrase = osip_strdup ("Unknown code");
}
response->req_uri = NULL;
response->sip_method = NULL;
}
i = osip_to_clone (request->to, &(response->to));
if (i != 0)
goto grd_error_1;
i = osip_to_get_tag (response->to, &tag);
if (i != 0)
{ /* we only add a tag if it does not already contains one! */
if ((dialog != NULL) && (dialog->local_tag != NULL))
/* it should contain the local TAG we created */
{
osip_to_set_tag (response->to, osip_strdup (dialog->local_tag));
} else
{
if (status != 100)
osip_to_set_tag (response->to, osip_to_tag_new_random ());
}
}
i = osip_from_clone (request->from, &(response->from));
if (i != 0)
goto grd_error_1;
pos = 0;
while (!osip_list_eol (&request->vias, pos))
{
osip_via_t *via;
osip_via_t *via2;
via = (osip_via_t *) osip_list_get (&request->vias, pos);
i = osip_via_clone (via, &via2);
if (i != -0)
goto grd_error_1;
osip_list_add (&response->vias, via2, -1);
pos++;
}
i = osip_call_id_clone (request->call_id, &(response->call_id));
if (i != 0)
goto grd_error_1;
i = osip_cseq_clone (request->cseq, &(response->cseq));
if (i != 0)
goto grd_error_1;
if (MSG_IS_SUBSCRIBE (request))
{
osip_header_t *exp;
osip_header_t *evt_hdr;
osip_message_header_get_byname (request, "event", 0, &evt_hdr);
if (evt_hdr != NULL && evt_hdr->hvalue != NULL)
osip_message_set_header (response, "Event", evt_hdr->hvalue);
else
osip_message_set_header (response, "Event", "presence");
i = osip_message_get_expires (request, 0, &exp);
if (exp == NULL)
{
osip_header_t *cp;
i = osip_header_clone (exp, &cp);
if (cp != NULL)
osip_list_add (&response->headers, cp, 0);
}
}
#if 0
osip_message_set_allow (response, "INVITE");
osip_message_set_allow (response, "ACK");
osip_message_set_allow (response, "OPTIONS");
osip_message_set_allow (response, "CANCEL");
osip_message_set_allow (response, "BYE");
osip_message_set_allow (response, "SUBSCRIBE");
osip_message_set_allow (response, "NOTIFY");
osip_message_set_allow (response, "MESSAGE");
osip_message_set_allow (response, "INFO");
osip_message_set_allow (response, "REFER");
osip_message_set_allow (response, "UPDATE");
#endif
osip_message_set_user_agent (response, eXosip.user_agent);
*dest = response;
return 0;
grd_error_1:
osip_message_free (response);
return -1;
}
int
complete_answer_that_establish_a_dialog (osip_message_t * response,
osip_message_t * request)
{
int i;
int pos = 0;
char contact[1000];
char locip[50];
struct eXosip_net *net;
/* 12.1.1:
copy all record-route in response
add a contact with global scope
*/
while (!osip_list_eol (&request->record_routes, pos))
{
osip_record_route_t *rr;
osip_record_route_t *rr2;
rr = osip_list_get (&request->record_routes, pos);
i = osip_record_route_clone (rr, &rr2);
if (i != 0)
return -1;
osip_list_add (&response->record_routes, rr2, -1);
pos++;
}
i = _eXosip_find_protocol (response);
if (i == IPPROTO_UDP)
{
net = &eXosip.net_interfaces[0];
} else if (i == IPPROTO_TCP)
{
net = &eXosip.net_interfaces[1];
} else
{
net = &eXosip.net_interfaces[0];
OSIP_TRACE (osip_trace
(__FILE__, __LINE__, OSIP_ERROR, NULL,
"eXosip: unsupported protocol (default to UDP)\n"));
return -1;
}
memset(locip, '\0', sizeof(locip));
#ifdef SM
eXosip_get_localip_from_via (response, locip, 49);
#else
eXosip_guess_ip_for_via (net->net_ip_family, locip, 49);
#endif
if (request->to->url->username == NULL)
snprintf (contact, 1000, "<sip:%s:%s>", locip, net->net_port);
else
snprintf (contact, 1000, "<sip:%s@%s:%s>", request->to->url->username,
locip, net->net_port);
if (eXosip.net_interfaces[0].net_firewall_ip[0] != '\0')
{
osip_contact_t *con =
(osip_contact_t *) osip_list_get (&request->contacts, 0);
if (con != NULL && con->url != NULL && con->url->host != NULL)
{
char *c_address = con->url->host;
struct addrinfo *addrinfo;
struct __eXosip_sockaddr addr;
i = eXosip_get_addrinfo (&addrinfo, con->url->host, 5060, IPPROTO_UDP);
if (i == 0)
{
memcpy (&addr, addrinfo->ai_addr, addrinfo->ai_addrlen);
freeaddrinfo (addrinfo);
c_address = inet_ntoa (((struct sockaddr_in *) &addr)->sin_addr);
OSIP_TRACE (osip_trace
(__FILE__, __LINE__, OSIP_INFO1, NULL,
"eXosip: here is the resolved destination host=%s\n",
c_address));
}
/* If c_address is a PUBLIC address, the request was
coming from the PUBLIC network. */
if (eXosip_is_public_address (c_address))
{
if (request->to->url->username == NULL)
snprintf (contact, 1000, "<sip:%s:%s>",
eXosip.net_interfaces[0].net_firewall_ip, net->net_port);
else
snprintf (contact, 1000, "<sip:%s@%s:%s>",
request->to->url->username,
eXosip.net_interfaces[0].net_firewall_ip, net->net_port);
}
}
}
osip_message_set_contact (response, contact);
return 0;
}
int
_eXosip_answer_invite_1xx (eXosip_call_t * jc, eXosip_dialog_t * jd, int code,
osip_message_t ** answer)
{
int i;
osip_transaction_t *tr;
*answer = NULL;
tr = eXosip_find_last_inc_invite (jc, jd);
if (tr == NULL)
{
OSIP_TRACE (osip_trace
(__FILE__, __LINE__, OSIP_ERROR, NULL,
"eXosip: cannot find transaction to answer"));
return -1;
}
/* is the transaction already answered? */
if (tr->state == IST_COMPLETED
|| tr->state == IST_CONFIRMED || tr->state == IST_TERMINATED)
{
OSIP_TRACE (osip_trace
(__FILE__, __LINE__, OSIP_ERROR, NULL,
"eXosip: transaction already answered\n"));
return -1;
}
if (jd == NULL)
i = _eXosip_build_response_default (answer, NULL, code, tr->orig_request);
else
i =
_eXosip_build_response_default (answer, jd->d_dialog, code,
tr->orig_request);
if (i != 0)
{
OSIP_TRACE (osip_trace
(__FILE__, __LINE__, OSIP_ERROR, NULL,
"ERROR: Could not create response for invite\n"));
return -2;
}
osip_message_set_content_length (*answer, "0");
/* send message to transaction layer */
if (code > 100)
{
i = complete_answer_that_establish_a_dialog (*answer, tr->orig_request);
}
return 0;
}
int
_eXosip_answer_invite_2xx (eXosip_call_t * jc, eXosip_dialog_t * jd, int code,
osip_message_t ** answer)
{
int i;
osip_transaction_t *tr;
*answer = NULL;
tr = eXosip_find_last_inc_invite (jc, jd);
if (tr == NULL || tr->orig_request == NULL)
{
OSIP_TRACE (osip_trace
(__FILE__, __LINE__, OSIP_ERROR, NULL,
"eXosip: cannot find transaction to answer\n"));
return -1;
}
if (jd != NULL && jd->d_dialog == NULL)
{ /* element previously removed */
OSIP_TRACE (osip_trace
(__FILE__, __LINE__, OSIP_ERROR, NULL,
"eXosip: cannot answer this closed transaction\n"));
return -1;
}
/* is the transaction already answered? */
if (tr->state == IST_COMPLETED
|| tr->state == IST_CONFIRMED || tr->state == IST_TERMINATED)
{
OSIP_TRACE (osip_trace
(__FILE__, __LINE__, OSIP_ERROR, NULL,
"eXosip: transaction already answered\n"));
return -1;
}
if (jd == NULL)
i = _eXosip_build_response_default (answer, NULL, code, tr->orig_request);
else
i =
_eXosip_build_response_default (answer, jd->d_dialog, code,
tr->orig_request);
if (i != 0)
{
OSIP_TRACE (osip_trace
(__FILE__, __LINE__, OSIP_INFO1, NULL,
"ERROR: Could not create response for invite\n"));
return -1;
}
/* request that estabish a dialog: */
/* 12.1.1 UAS Behavior */
{
i = complete_answer_that_establish_a_dialog (*answer, tr->orig_request);
if (i != 0)
goto g2atii_error_1;; /* ?? */
}
return 0;
g2atii_error_1:
osip_message_free (*answer);
return -1;
}
int
_eXosip_answer_invite_3456xx (eXosip_call_t * jc, eXosip_dialog_t * jd,
int code, osip_message_t ** answer)
{
int i;
osip_transaction_t *tr;
*answer = NULL;
tr = eXosip_find_last_inc_invite (jc, jd);
if (tr == NULL)
{
OSIP_TRACE (osip_trace
(__FILE__, __LINE__, OSIP_ERROR, NULL,
"eXosip: cannot find transaction to answer"));
return -1;
}
/* is the transaction already answered? */
if (tr->state == IST_COMPLETED
|| tr->state == IST_CONFIRMED || tr->state == IST_TERMINATED)
{
OSIP_TRACE (osip_trace
(__FILE__, __LINE__, OSIP_ERROR, NULL,
"eXosip: transaction already answered\n"));
return -1;
}
i =
_eXosip_build_response_default (answer, jd->d_dialog, code, tr->orig_request);
if (i != 0)
{
OSIP_TRACE (osip_trace
(__FILE__, __LINE__, OSIP_INFO1, NULL,
"ERROR: Could not create response for invite\n"));
return -1;
}
if ((300 <= code) && (code <= 399))
{
/* Should add contact fields */
/* ... */
}
osip_message_set_content_length (*answer, "0");
/* send message to transaction layer */
return 0;
}
int
_eXosip_default_answer_invite_1xx (eXosip_call_t * jc, eXosip_dialog_t * jd,
int code)
{
osip_event_t *evt_answer;
osip_message_t *response;
int i;
osip_transaction_t *tr;
tr = eXosip_find_last_inc_invite (jc, jd);
if (tr == NULL)
{
OSIP_TRACE (osip_trace
(__FILE__, __LINE__, OSIP_ERROR, NULL,
"eXosip: cannot find transaction to answer"));
return -1;
}
/* is the transaction already answered? */
if (tr->state == IST_COMPLETED
|| tr->state == IST_CONFIRMED || tr->state == IST_TERMINATED)
{
OSIP_TRACE (osip_trace
(__FILE__, __LINE__, OSIP_ERROR, NULL,
"eXosip: transaction already answered\n"));
return -1;
}
if (jd == NULL)
i = _eXosip_build_response_default (&response, NULL, code, tr->orig_request);
else
i =
_eXosip_build_response_default (&response, jd->d_dialog, code,
tr->orig_request);
if (i != 0)
{
OSIP_TRACE (osip_trace
(__FILE__, __LINE__, OSIP_ERROR, NULL,
"ERROR: Could not create response for invite\n"));
return -2;
}
osip_message_set_content_length (response, "0");
/* send message to transaction layer */
if (code > 100)
{
/* request that estabish a dialog: */
/* 12.1.1 UAS Behavior */
i = complete_answer_that_establish_a_dialog (response, tr->orig_request);
if (jd == NULL)
{
i = eXosip_dialog_init_as_uas (&jd, tr->orig_request, response);
if (i != 0)
{
OSIP_TRACE (osip_trace
(__FILE__, __LINE__, OSIP_ERROR, NULL,
"eXosip: cannot create dialog!\n"));
} else
{
ADD_ELEMENT (jc->c_dialogs, jd);
}
}
}
evt_answer = osip_new_outgoing_sipmessage (response);
evt_answer->transactionid = tr->transactionid;
osip_transaction_add_event (tr, evt_answer);
__eXosip_wakeup ();
return 0;
}
int
_eXosip_default_answer_invite_3456xx (eXosip_call_t * jc,
eXosip_dialog_t * jd, int code)
{
osip_event_t *evt_answer;
osip_message_t *response;
int i;
osip_transaction_t *tr;
tr = eXosip_find_last_inc_invite (jc, jd);
if (tr == NULL)
{
OSIP_TRACE (osip_trace
(__FILE__, __LINE__, OSIP_ERROR, NULL,
"eXosip: cannot find transaction to answer"));
return -1;
}
/* is the transaction already answered? */
if (tr->state == IST_COMPLETED
|| tr->state == IST_CONFIRMED || tr->state == IST_TERMINATED)
{
OSIP_TRACE (osip_trace
(__FILE__, __LINE__, OSIP_ERROR, NULL,
"eXosip: transaction already answered\n"));
return -1;
}
i =
_eXosip_build_response_default (&response, jd->d_dialog, code,
tr->orig_request);
if (i != 0)
{
OSIP_TRACE (osip_trace
(__FILE__, __LINE__, OSIP_INFO1, NULL,
"ERROR: Could not create response for invite\n"));
return -1;
}
osip_message_set_content_length (response, "0");
/* send message to transaction layer */
evt_answer = osip_new_outgoing_sipmessage (response);
evt_answer->transactionid = tr->transactionid;
osip_transaction_add_event (tr, evt_answer);
__eXosip_wakeup ();
return 0;
}
int
_eXosip_insubscription_answer_1xx (eXosip_notify_t * jn, eXosip_dialog_t * jd,
int code)
{
osip_event_t *evt_answer;
osip_message_t *response;
int i;
osip_transaction_t *tr;
tr = eXosip_find_last_inc_subscribe (jn, jd);
if (tr == NULL)
{
OSIP_TRACE (osip_trace
(__FILE__, __LINE__, OSIP_ERROR, NULL,
"eXosip: cannot find transaction to answer"));
return -1;
}
if (jd == NULL)
i = _eXosip_build_response_default (&response, NULL, code, tr->orig_request);
else
i =
_eXosip_build_response_default (&response, jd->d_dialog, code,
tr->orig_request);
if (i != 0)
{
OSIP_TRACE (osip_trace
(__FILE__, __LINE__, OSIP_ERROR, NULL,
"ERROR: Could not create response for subscribe\n"));
return -1;
}
if (code > 100)
{
/* request that estabish a dialog: */
/* 12.1.1 UAS Behavior */
i = complete_answer_that_establish_a_dialog (response, tr->orig_request);
if (jd == NULL)
{
i = eXosip_dialog_init_as_uas (&jd, tr->orig_request, response);
if (i != 0)
{
OSIP_TRACE (osip_trace
(__FILE__, __LINE__, OSIP_ERROR, NULL,
"eXosip: cannot create dialog!\n"));
}
ADD_ELEMENT (jn->n_dialogs, jd);
}
}
evt_answer = osip_new_outgoing_sipmessage (response);
evt_answer->transactionid = tr->transactionid;
osip_transaction_add_event (tr, evt_answer);
__eXosip_wakeup ();
return 0;
}
#if 0
int
_eXosip_insubscription_answer_2xx (eXosip_notify_t * jn, eXosip_dialog_t * jd,
int code)
{
osip_event_t *evt_answer;
osip_message_t *response;
int i;
osip_transaction_t *tr;
tr = eXosip_find_last_inc_subscribe (jn, jd);
if (tr == NULL || tr->orig_request == NULL)
{
OSIP_TRACE (osip_trace
(__FILE__, __LINE__, OSIP_ERROR, NULL,
"eXosip: cannot find transaction to answer\n"));
return -1;
}
if (jd != NULL && jd->d_dialog == NULL)
{ /* element previously removed, this is a no hop! */
OSIP_TRACE (osip_trace
(__FILE__, __LINE__, OSIP_ERROR, NULL,
"eXosip: cannot answer this closed transaction\n"));
return -1;
}
if (jd == NULL)
i = _eXosip_build_response_default (&response, NULL, code, tr->orig_request);
else
i =
_eXosip_build_response_default (&response, jd->d_dialog, code,
tr->orig_request);
if (i != 0)
{
OSIP_TRACE (osip_trace
(__FILE__, __LINE__, OSIP_INFO1, NULL,
"ERROR: Could not create response for subscribe\n"));
code = 500; /* ? which code to use? */
return -1;
}
/* request that estabish a dialog: */
/* 12.1.1 UAS Behavior */
{
i = complete_answer_that_establish_a_dialog (response, tr->orig_request);
if (i != 0)
goto g2atii_error_1;; /* ?? */
}
/* THIS RESPONSE MUST BE SENT RELIABILY until the final ACK is received !! */
/* this response must be stored at the upper layer!!! (it will be destroyed */
/* right after being sent! */
if (jd == NULL)
{
i = eXosip_dialog_init_as_uas (&jd, tr->orig_request, response);
if (i != 0)
{
OSIP_TRACE (osip_trace
(__FILE__, __LINE__, OSIP_ERROR, NULL,
"eXosip: cannot create dialog!\n"));
return -1;
}
ADD_ELEMENT (jn->n_dialogs, jd);
}
eXosip_dialog_set_200ok (jd, response);
evt_answer = osip_new_outgoing_sipmessage (response);
evt_answer->transactionid = tr->transactionid;
osip_transaction_add_event (tr, evt_answer);
__eXosip_wakeup ();
osip_dialog_set_state (jd->d_dialog, DIALOG_CONFIRMED);
return 0;
g2atii_error_1:
osip_message_free (response);
return -1;
}
#endif
int
_eXosip_insubscription_answer_3456xx (eXosip_notify_t * jn,
eXosip_dialog_t * jd, int code)
{
osip_event_t *evt_answer;
osip_message_t *response;
int i;
osip_transaction_t *tr;
tr = eXosip_find_last_inc_subscribe (jn, jd);
if (tr == NULL)
{
OSIP_TRACE (osip_trace
(__FILE__, __LINE__, OSIP_ERROR, NULL,
"eXosip: cannot find transaction to answer"));
return -1;
}
if (jd == NULL)
i = _eXosip_build_response_default (&response, NULL, code, tr->orig_request);
else
i =
_eXosip_build_response_default (&response, jd->d_dialog, code,
tr->orig_request);
if (i != 0)
{
OSIP_TRACE (osip_trace
(__FILE__, __LINE__, OSIP_INFO1, NULL,
"ERROR: Could not create response for subscribe\n"));
return -1;
}
if ((300 <= code) && (code <= 399))
{
/* Should add contact fields */
/* ... */
}
evt_answer = osip_new_outgoing_sipmessage (response);
evt_answer->transactionid = tr->transactionid;
osip_transaction_add_event (tr, evt_answer);
__eXosip_wakeup ();
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1