Commit 628aaa24 authored by Simon Morlat's avatar Simon Morlat

implement nat-helper mode and automatic mode for contact headers.

parent 7faa117c
......@@ -151,8 +151,14 @@ BELLESIP_EXPORT belle_sip_header_contact_t* belle_sip_header_contact_create (con
*
* */
BELLESIP_EXPORT unsigned int belle_sip_header_contact_not_equals(const belle_sip_header_contact_t* a,const belle_sip_header_contact_t* b);
/**
* Enable automatic filling of the contact ip, port and transport according to the channel that sends this message.
**/
BELLESIP_EXPORT void belle_sip_header_contact_set_automatic(belle_sip_header_contact_t *a, int enabled);
BELLESIP_EXPORT int belle_sip_header_contact_get_automatic(const belle_sip_header_contact_t *a);
#define BELLE_SIP_RANDOM_TAG ((const char*)-1)
#define BELLE_SIP_HEADER_CONTACT(t) BELLE_SIP_CAST(t,belle_sip_header_contact_t)
#define BELLE_SIP_CONTACT "Contact"
......
......@@ -95,6 +95,21 @@ BELLESIP_EXPORT void belle_sip_provider_enable_rport(belle_sip_provider_t *prov,
BELLESIP_EXPORT int belle_sip_provider_is_rport_enabled(belle_sip_provider_t *prov);
/**
* Enable discovery of NAT's public address and port during SIP exchanges.
* When activated, automatic contacts ( see belle_sip_header_contact_set_automatic() )
* will use discovered public IP address and port (if any) instead of local ones.
* NAT public address and port are discovered using received and rport parameters in via header of responses.
* As a result, disabling rport ( see belle_sip_provider_enable_rport() ) will also break this feature.
**/
BELLESIP_EXPORT void belle_sip_provider_enable_nat_helper(belle_sip_provider_t *prov, int enabled);
/**
* Returns if nat helper behavior is enabled.
* @see belle_sip_provider_enable_nat_helper()
**/
BELLESIP_EXPORT int belle_sip_provider_nat_helper_enabled(const belle_sip_provider_t *prov);
BELLE_SIP_END_DECLS
#define BELLE_SIP_PROVIDER(obj) BELLE_SIP_CAST(obj,belle_sip_provider_t)
......
......@@ -223,7 +223,9 @@ GET_SET_STRING(belle_sip_header_allow,method);
***********************/
struct _belle_sip_header_contact {
belle_sip_header_address_t address;
unsigned int wildcard;
unsigned char wildcard;
unsigned char automatic;
unsigned char pad[2];
};
void belle_sip_header_contact_destroy(belle_sip_header_contact_t* contact) {
......@@ -231,6 +233,7 @@ void belle_sip_header_contact_destroy(belle_sip_header_contact_t* contact) {
void belle_sip_header_contact_clone(belle_sip_header_contact_t *contact, const belle_sip_header_contact_t *orig){
contact->wildcard=orig->wildcard;
contact->automatic=orig->automatic;
}
belle_sip_error_code belle_sip_header_contact_marshal(belle_sip_header_contact_t* contact, char* buff, size_t buff_size, size_t *offset) {
......@@ -284,6 +287,14 @@ unsigned int belle_sip_header_contact_equals(const belle_sip_header_contact_t* a
unsigned int belle_sip_header_contact_not_equals(const belle_sip_header_contact_t* a,const belle_sip_header_contact_t* b) {
return !belle_sip_header_contact_equals(a,b);
}
void belle_sip_header_contact_set_automatic(belle_sip_header_contact_t *a, int enabled){
a->automatic=enabled;
}
int belle_sip_header_contact_get_automatic(const belle_sip_header_contact_t *a){
return a->automatic;
}
/**************************
* From header object inherent from header_address
****************************
......
......@@ -508,7 +508,8 @@ struct belle_sip_provider{
belle_sip_list_t *server_transactions;
belle_sip_list_t *dialogs;
belle_sip_list_t *auth_contexts;
int rport_enabled; /*0 if rport should not be set in via header*/
unsigned char rport_enabled; /*0 if rport should not be set in via header*/
unsigned char nat_helper;
};
belle_sip_provider_t *belle_sip_provider_new(belle_sip_stack_t *s, belle_sip_listening_point_t *lp);
......
......@@ -121,8 +121,6 @@ void belle_sip_parameters_remove_parameter(belle_sip_parameters_t* params,const
belle_sip_param_pair_destroy(lResult->data);
params->param_list=belle_sip_list_delete_link(params->param_list,lResult);
}
} else {
belle_sip_warning("cannot remove param %s because not present",name);
}
}
......@@ -65,6 +65,7 @@ static void belle_sip_channel_destroy(belle_sip_channel_t *obj){
belle_sip_main_loop_remove_source(obj->stack->ml,obj->inactivity_timer);
belle_sip_object_unref(obj->inactivity_timer);
}
if (obj->public_ip) belle_sip_free(obj->public_ip);
belle_sip_message("Channel [%p] destroyed",obj);
}
......@@ -195,8 +196,56 @@ static size_t belle_sip_channel_input_stream_get_buff_length(belle_sip_channel_i
return MAX_CHANNEL_BUFF_SIZE - (input_stream->write_ptr-input_stream->buff);
}
void belle_sip_channel_set_public_ip_port(belle_sip_channel_t *obj, const char *public_ip, int port){
if (obj->public_ip){
int ip_changed=0;
int port_changed=0;
if (public_ip && strcmp(obj->public_ip,public_ip)!=0){
ip_changed=1;
}
if (port!=obj->public_port){
port_changed=1;
}
if (ip_changed || port_changed){
belle_sip_warning("channel [%p]: public ip is changed from [%s:%i] to [%s:%i]",obj,obj->public_ip,obj->public_port,public_ip,port);
}
belle_sip_free(obj->public_ip);
obj->public_ip=NULL;
}else if (public_ip){
belle_sip_message("channel [%p]: discovered public ip and port are [%s:%i]",obj,public_ip,port);
}
if (public_ip){
obj->public_ip=belle_sip_strdup(public_ip);
}
obj->public_port=port;
}
static void belle_sip_channel_learn_public_ip_port(belle_sip_channel_t *obj, belle_sip_response_t *resp){
belle_sip_header_via_t *via=belle_sip_message_get_header_by_type(resp,belle_sip_header_via_t);
const char *received;
int rport;
if (!via){
belle_sip_error("channel [%p]: no via in response.",obj);
return;
}
received=belle_sip_header_via_get_received(via);
if (received){
rport=belle_sip_header_via_get_rport(via);
if (rport<=0){
/* no rport, the via port might be good then*/
rport=belle_sip_header_via_get_listening_port(via);
}
belle_sip_channel_set_public_ip_port(obj,received,rport);
}
}
static void belle_sip_channel_message_ready(belle_sip_channel_t *obj){
obj->incoming_messages=belle_sip_list_append(obj->incoming_messages,obj->input_stream.msg);
belle_sip_message_t *msg=obj->input_stream.msg;
if (belle_sip_message_is_response(msg)) belle_sip_channel_learn_public_ip_port(obj,BELLE_SIP_RESPONSE(msg));
obj->incoming_messages=belle_sip_list_append(obj->incoming_messages,msg);
belle_sip_channel_input_stream_reset(&obj->input_stream);
}
......@@ -461,9 +510,7 @@ const struct addrinfo * belle_sip_channel_get_peer(belle_sip_channel_t *obj){
belle_sip_message_t* belle_sip_channel_pick_message(belle_sip_channel_t *obj) {
belle_sip_message_t* result=NULL;
belle_sip_list_t* front;
if ((front=obj->incoming_messages)==NULL) {
belle_sip_error("Cannot pickup incoming message, empty list");
} else {
if ((front=obj->incoming_messages)!=NULL) {
result = (belle_sip_message_t*)obj->incoming_messages->data;
obj->incoming_messages=belle_sip_list_remove_link(obj->incoming_messages,obj->incoming_messages);
belle_sip_free(front);
......@@ -535,6 +582,7 @@ static void _send_message(belle_sip_channel_t *obj, belle_sip_message_t *msg){
BELLE_SIP_INVOKE_LISTENERS_ARG1_ARG2(obj->listeners,belle_sip_channel_listener_t,on_sending,obj,msg);
error=belle_sip_object_marshal((belle_sip_object_t*)msg,buffer,sizeof(buffer),&len);
if ((error==BELLE_SIP_OK) && (len>0)){
buffer[len]='\0';
if (!obj->stack->send_error)
ret=belle_sip_channel_send(obj,buffer,len);
else
......
......@@ -84,6 +84,8 @@ struct belle_sip_channel{
int peer_port;
char *local_ip;
int local_port;
char *public_ip;
int public_port;
unsigned long resolver_id;
struct addrinfo *peer_list;
struct addrinfo *current_peer;
......
......@@ -251,29 +251,53 @@ static int channel_on_event(belle_sip_channel_listener_t *obj, belle_sip_channel
}
static void channel_on_sending(belle_sip_channel_listener_t *obj, belle_sip_channel_t *chan, belle_sip_message_t *msg){
belle_sip_header_contact_t* contact = (belle_sip_header_contact_t*)belle_sip_message_get_header(msg,"Contact");
belle_sip_header_contact_t* contact;
belle_sip_header_content_length_t* content_lenght = (belle_sip_header_content_length_t*)belle_sip_message_get_header(msg,"Content-Length");
belle_sip_uri_t* contact_uri;
const belle_sip_list_t *contacts;
const char *ip=NULL;
int port=0;
belle_sip_provider_t *prov=BELLE_SIP_PROVIDER(obj);
if (belle_sip_message_is_request(msg)){
/*probably better to be in channel*/
fix_outgoing_via((belle_sip_provider_t*)obj,chan,msg);
}
if (contact){
/* fix the contact if empty*/
if (!(contact_uri =belle_sip_header_address_get_uri((belle_sip_header_address_t*)contact))) {
for (contacts=belle_sip_message_get_headers(msg,"Contact");contacts!=NULL;contacts=contacts->next){
const char *transport;
contact=(belle_sip_header_contact_t*)contacts->data;
if (belle_sip_header_contact_is_wildcard(contact)) continue;
/* fix the contact if in automatic mode or null uri (for backward compatibility)*/
if (!(contact_uri = belle_sip_header_address_get_uri((belle_sip_header_address_t*)contact))) {
contact_uri = belle_sip_uri_new();
belle_sip_header_address_set_uri((belle_sip_header_address_t*)contact,contact_uri);
belle_sip_header_contact_set_automatic(contact,TRUE);
}else if (belle_sip_uri_get_host(contact_uri)==NULL){
belle_sip_header_contact_set_automatic(contact,TRUE);
}
if (!belle_sip_uri_get_host(contact_uri)) {
belle_sip_uri_set_host(contact_uri,chan->local_ip);
if (!belle_sip_header_contact_get_automatic(contact)) continue;
if (ip==NULL){
if (prov->nat_helper){
ip=chan->public_ip ? chan->public_ip : chan->local_ip;
port=chan->public_port ? chan->public_port : chan->local_port;
}else{
ip=chan->local_ip;
port=chan->local_port;
}
}
if (belle_sip_uri_get_transport_param(contact_uri) == NULL && strcasecmp("udp",belle_sip_channel_get_transport_name(chan))!=0) {
belle_sip_uri_set_transport_param(contact_uri,belle_sip_channel_get_transport_name_lower_case(chan));
belle_sip_uri_set_host(contact_uri,ip);
transport=belle_sip_channel_get_transport_name_lower_case(chan);
if (strcmp(transport,"udp")==0){
belle_sip_parameters_remove_parameter(BELLE_SIP_PARAMETERS(contact_uri),"transport");
}else{
belle_sip_uri_set_transport_param(contact_uri,transport);
}
if (belle_sip_uri_get_port(contact_uri) <= 0 && chan->local_port!=5060) {
belle_sip_uri_set_port(contact_uri,chan->local_port);
if (belle_sip_uri_get_port(contact_uri) <= 0 && port!=belle_sip_listening_point_get_well_known_port(transport)) {
belle_sip_uri_set_port(contact_uri,port);
}
belle_sip_uri_fix(contact_uri);
}
......@@ -880,3 +904,12 @@ void belle_sip_provider_enable_rport(belle_sip_provider_t *prov, int enable) {
int belle_sip_provider_is_rport_enabled(belle_sip_provider_t *prov) {
return prov->rport_enabled;
}
void belle_sip_provider_enable_nat_helper(belle_sip_provider_t *prov, int enabled){
prov->nat_helper=enabled;
}
int belle_sip_provider_nat_helper_enabled(const belle_sip_provider_t *prov){
return prov->nat_helper;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment