belle_sip_uri_impl.c 11.6 KB
Newer Older
jehan's avatar
jehan committed
1
/*
jehan's avatar
jehan committed
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
	belle-sip - SIP (RFC3261) library.
    Copyright (C) 2010  Belledonne Communications SARL

    This program 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 3 of the License, or
    (at your option) any later version.

    This program 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, see <http://www.gnu.org/licenses/>.
*/
jehan's avatar
jehan committed
18

19
#include "belle-sip/uri.h"
jehan's avatar
jehan committed
20
#include "belle-sip/parameters.h"
jehan's avatar
jehan committed
21 22
#include <stdlib.h>
#include <string.h>
jehan's avatar
jehan committed
23
#include <stdarg.h>
jehan's avatar
jehan committed
24 25
#include "belle_sip_messageParser.h"
#include "belle_sip_messageLexer.h"
Simon Morlat's avatar
Simon Morlat committed
26
#include "belle_sip_internal.h"
jehan's avatar
jehan committed
27
#include "listeningpoint_internal.h"
jehan's avatar
jehan committed
28 29


jehan's avatar
jehan committed
30
#define SIP_URI_GET_SET_STRING(attribute) GET_SET_STRING(belle_sip_uri,attribute)
jehan's avatar
jehan committed
31
#define SIP_URI_GET_SET_STRING_PARAM(attribute) GET_SET_STRING_PARAM2(belle_sip_uri,attribute,attribute##_param)
jehan's avatar
jehan committed
32 33


34 35
#define SIP_URI_GET_SET_UINT(attribute) GET_SET_INT(belle_sip_uri,attribute,unsigned int)
#define SIP_URI_GET_SET_INT(attribute) GET_SET_INT(belle_sip_uri,attribute,int)
jehan's avatar
jehan committed
36
#define SIP_URI_GET_SET_INT_PARAM(attribute) GET_SET_INT_PARAM2(belle_sip_uri,attribute,int,attribute##_param)
jehan's avatar
jehan committed
37

38

jehan's avatar
jehan committed
39 40
#define SIP_URI_GET_SET_BOOL(attribute) GET_SET_BOOL(belle_sip_uri,attribute,is)
#define SIP_URI_HAS_SET_BOOL(attribute) GET_SET_BOOL(belle_sip_uri,attribute,has)
jehan's avatar
jehan committed
41
#define SIP_URI_HAS_SET_BOOL_PARAM(attribute) GET_SET_BOOL_PARAM2(belle_sip_uri,attribute,has,attribute##_param)
jehan's avatar
jehan committed
42 43 44



jehan's avatar
jehan committed
45
struct _belle_sip_uri {
jehan's avatar
jehan committed
46
	belle_sip_parameters_t params;
47
	unsigned int secure;
48 49
	char* user;
	char* host;
jehan's avatar
jehan committed
50
	int port;
jehan's avatar
jehan committed
51
	belle_sip_parameters_t * header_list;
jehan's avatar
jehan committed
52
};
53

54
static void belle_sip_uri_destroy(belle_sip_uri_t* uri) {
jehan's avatar
jehan committed
55 56 57 58
	if (uri->user) belle_sip_free (uri->user);
	if (uri->host) belle_sip_free (uri->host);
	belle_sip_object_unref(BELLE_SIP_OBJECT(uri->header_list));
}
jehan's avatar
jehan committed
59

60
static void belle_sip_uri_clone(belle_sip_uri_t* uri, const belle_sip_uri_t *orig){
61
	uri->secure=orig->secure;
62 63
	uri->user=orig->user?belle_sip_strdup(orig->user):NULL;
	uri->host=orig->host?belle_sip_strdup(orig->host):NULL;
64
	uri->port=orig->port;
65 66 67 68 69
	if (orig->header_list){
		uri->header_list=(belle_sip_parameters_t*)belle_sip_object_clone(BELLE_SIP_OBJECT(orig->header_list));
		belle_sip_object_ref(uri->header_list);
	}
	
70 71
}

Ghislain MARY's avatar
Ghislain MARY committed
72
belle_sip_error_code belle_sip_uri_marshal(const belle_sip_uri_t* uri, char* buff, size_t buff_size, unsigned int *offset) {
jehan's avatar
jehan committed
73
	const belle_sip_list_t* list=belle_sip_parameters_get_parameters(uri->header_list);
Ghislain MARY's avatar
Ghislain MARY committed
74
	belle_sip_error_code error=BELLE_SIP_OK;
jehan's avatar
jehan committed
75

Ghislain MARY's avatar
Ghislain MARY committed
76 77
	error=belle_sip_snprintf(buff,buff_size,offset,"%s:",uri->secure?"sips":"sip");
	if (error!=BELLE_SIP_OK) return error;
78
	
jehan's avatar
jehan committed
79
	if (uri->user) {
80
		char* escaped_username=belle_sip_to_escaped_string(uri->user);
Ghislain MARY's avatar
Ghislain MARY committed
81
		error=belle_sip_snprintf(buff,buff_size,offset,"%s@",escaped_username);
82
		belle_sip_free(escaped_username);
Ghislain MARY's avatar
Ghislain MARY committed
83
		if (error!=BELLE_SIP_OK) return error;
jehan's avatar
jehan committed
84 85
	}
	if (uri->host) {
jehan's avatar
jehan committed
86
		if (strchr(uri->host,':')) { /*ipv6*/
Ghislain MARY's avatar
Ghislain MARY committed
87
			error=belle_sip_snprintf(buff,buff_size,offset,"[%s]",uri->host);
jehan's avatar
jehan committed
88
		} else {
Ghislain MARY's avatar
Ghislain MARY committed
89
			error=belle_sip_snprintf(buff,buff_size,offset,"%s",uri->host);
jehan's avatar
jehan committed
90
		}
Ghislain MARY's avatar
Ghislain MARY committed
91
		if (error!=BELLE_SIP_OK) return error;
jehan's avatar
jehan committed
92 93 94 95
	} else {
		belle_sip_warning("no host found in this uri");
	}
	if (uri->port>0) {
Ghislain MARY's avatar
Ghislain MARY committed
96 97
		error=belle_sip_snprintf(buff,buff_size,offset,":%i",uri->port);
		if (error!=BELLE_SIP_OK) return error;
jehan's avatar
jehan committed
98
	}
Ghislain MARY's avatar
Ghislain MARY committed
99 100
	error=belle_sip_parameters_marshal(&uri->params,buff,buff_size,offset);
	if (error!=BELLE_SIP_OK) return error;
jehan's avatar
jehan committed
101 102 103 104 105

	for(;list!=NULL;list=list->next){
		belle_sip_param_pair_t* container = list->data;
		if (list == belle_sip_parameters_get_parameters(uri->header_list)) {
			//first case
Ghislain MARY's avatar
Ghislain MARY committed
106
			error=belle_sip_snprintf(buff,buff_size,offset,"?%s=%s",container->name,container->value);
jehan's avatar
jehan committed
107 108
		} else {
			//subsequent headers
Ghislain MARY's avatar
Ghislain MARY committed
109
			error=belle_sip_snprintf(buff,buff_size,offset,"&%s=%s",container->name,container->value);
jehan's avatar
jehan committed
110
		}
Ghislain MARY's avatar
Ghislain MARY committed
111
		if (error!=BELLE_SIP_OK) return error;
jehan's avatar
jehan committed
112
	}
Ghislain MARY's avatar
Ghislain MARY committed
113
	return error;
jehan's avatar
jehan committed
114
}
115

jehan's avatar
jehan committed
116
BELLE_SIP_PARSE(uri);
117

118
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_uri_t);
Simon Morlat's avatar
Simon Morlat committed
119
BELLE_SIP_INSTANCIATE_VPTR(belle_sip_uri_t,belle_sip_parameters_t,belle_sip_uri_destroy,belle_sip_uri_clone,belle_sip_uri_marshal,TRUE);
Simon Morlat's avatar
Simon Morlat committed
120 121


122
belle_sip_uri_t* belle_sip_uri_new () {
Simon Morlat's avatar
Simon Morlat committed
123
	belle_sip_uri_t* l_object = belle_sip_object_new(belle_sip_uri_t);
jehan's avatar
jehan committed
124 125
	belle_sip_parameters_init((belle_sip_parameters_t*)l_object); /*super*/
	l_object->header_list = belle_sip_parameters_new();
126
	belle_sip_object_ref(l_object->header_list);
jehan's avatar
jehan committed
127
	return l_object;
jehan's avatar
jehan committed
128
}
129

jehan's avatar
jehan committed
130 131 132 133 134 135
belle_sip_uri_t* belle_sip_uri_create (const char* username,const char* host) {
	belle_sip_uri_t* uri = belle_sip_uri_new();
	belle_sip_uri_set_user(uri,username);
	belle_sip_uri_set_host(uri,host);
	return uri;
}
jehan's avatar
jehan committed
136 137


138
char* belle_sip_uri_to_string(belle_sip_uri_t* uri)  {
jehan's avatar
jehan committed
139
	return belle_sip_object_to_string(BELLE_SIP_OBJECT(uri));
jehan's avatar
jehan committed
140 141
}

jehan's avatar
jehan committed
142

143
const char* belle_sip_uri_get_header(const belle_sip_uri_t* uri,const char* name) {
jehan's avatar
jehan committed
144
	return belle_sip_parameters_get_parameter(uri->header_list,name);
jehan's avatar
jehan committed
145
}
146 147

void belle_sip_uri_set_header(belle_sip_uri_t* uri,const char* name,const char* value) {
jehan's avatar
jehan committed
148
	belle_sip_parameters_set_parameter(uri->header_list,name,value);
jehan's avatar
jehan committed
149 150
}

151 152 153 154
void belle_sip_uri_remove_header(belle_sip_uri_t *uri, const char *name){
	belle_sip_parameters_remove_parameter(uri->header_list,name);
}

155
const belle_sip_list_t*	belle_sip_uri_get_header_names(const belle_sip_uri_t* uri) {
jehan's avatar
jehan committed
156
	return belle_sip_parameters_get_parameter_names(uri->header_list);
jehan's avatar
jehan committed
157 158
}

159 160 161
int belle_sip_uri_get_listening_port(const belle_sip_uri_t *uri){
	int port=belle_sip_uri_get_port(uri);
	const char *transport=belle_sip_uri_get_transport_param(uri);
Simon Morlat's avatar
Simon Morlat committed
162
	if (port==0)
163 164 165
		port=belle_sip_listening_point_get_well_known_port(transport ? transport : "UDP");
	return port;
}
jehan's avatar
jehan committed
166

167 168 169 170 171 172 173
void belle_sip_uri_fix(belle_sip_uri_t *uri){
	const char *transport=belle_sip_uri_get_transport_param(uri);
	if (transport && strcasecmp(transport,"tls")==0){
		belle_sip_uri_set_secure(uri,TRUE);
	}
}

174
SIP_URI_GET_SET_BOOL(secure)
jehan's avatar
jehan committed
175

jehan's avatar
jehan committed
176 177
SIP_URI_GET_SET_STRING(user)
SIP_URI_GET_SET_STRING(host)
jehan's avatar
jehan committed
178
SIP_URI_GET_SET_INT(port)
179

jehan's avatar
jehan committed
180 181 182 183 184 185
SIP_URI_GET_SET_STRING_PARAM(transport)
SIP_URI_GET_SET_STRING_PARAM(user)
SIP_URI_GET_SET_STRING_PARAM(method)
SIP_URI_GET_SET_STRING_PARAM(maddr)
SIP_URI_GET_SET_INT_PARAM(ttl)
SIP_URI_HAS_SET_BOOL_PARAM(lr)
jehan's avatar
jehan committed
186 187


jehan's avatar
jehan committed
188

jehan's avatar
jehan committed
189 190 191

static int uri_strncmp_common(const char*a,const char*b,size_t n,int case_sensitive) {
	int result=0;
192
	size_t index_a=0,index_b=0;
jehan's avatar
jehan committed
193 194 195
	char char_a,char_b;

	while (a[index_a]!='\0'&&b[index_b]!='\0'&&index_a<n&&index_b<n) {
jehan's avatar
jehan committed
196 197
		index_a+=belle_sip_get_char(a+index_a,n-index_a,&char_a);
		index_b+=belle_sip_get_char(b+index_b,n-index_b,&char_b);
jehan's avatar
jehan committed
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
		if (!case_sensitive && char_a<0x7B && char_a>0x60) char_a-=0x20;
		if (!case_sensitive && char_b<0x7B && char_b>0x60) char_b-=0x20;
		result+=(char_a!=char_b);
	}
	return result;
}
static int uri_strncmp(const char*a,const char*b,size_t n) {
	return uri_strncmp_common(a,b,n,1);
}
static int uri_strncasecmp(const char*a,const char*b,size_t n) {
	return uri_strncmp_common(a,b,n,0);
}
#define IS_EQUAL(a,b) uri_strncmp(a,b,MIN(strlen(a),strlen(b)))!=0

#define IS_EQUAL_CASE(a,b) uri_strncasecmp(a,b,MIN(strlen(a),strlen(b)))!=0
#define PARAM_CASE_CMP(uri_a,uri_b,param) \
jehan's avatar
jehan committed
214 215
		a_param=belle_sip_parameters_get_case_parameter((belle_sip_parameters_t*) uri_a,param); \
		b_param=belle_sip_parameters_get_case_parameter((belle_sip_parameters_t*) uri_b,param);\
jehan's avatar
jehan committed
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328
		if (a_param && b_param) { \
			if (IS_EQUAL_CASE(a_param,b_param)) return 0; \
		} else if (a_param != b_param) {\
			return 0;\
		}

/*
 * RFC 3261            SIP: Session Initiation Protocol           June 2002
 * 19.1.4 URI Comparison

   Some operations in this specification require determining whether two
   SIP or SIPS URIs are equivalent.  In this specification, registrars
   need to compare bindings in Contact URIs in REGISTER requests (see
   Section 10.3.).  SIP and SIPS URIs are compared for equality
   according to the following rules:
*/
int belle_sip_uri_equals(const belle_sip_uri_t* uri_a,const belle_sip_uri_t* uri_b) {
	const belle_sip_list_t *	params;
	const char* b_param;
	const char* a_param;
/*
      o  A SIP and SIPS URI are never equivalent.
*/
	if (belle_sip_uri_is_secure(uri_a)!=belle_sip_uri_is_secure(uri_b)) {
		return 0;
	}
/*
	o  Comparison of the userinfo of SIP and SIPS URIs is case-
         sensitive.  This includes userinfo containing passwords or
         formatted as telephone-subscribers.  Comparison of all other
         components of the URI is case-insensitive unless explicitly
         defined otherwise.
*/
	if (uri_a->user && uri_b->user) {
		if (IS_EQUAL(uri_a->user,uri_b->user)) return 0;
	} else if (uri_a->user != uri_a->user) {
		return 0;
	}
/*
      o  The ordering of parameters and header fields is not significant
         in comparing SIP and SIPS URIs.

      o  Characters other than those in the "reserved" set (see RFC 2396
         [5]) are equivalent to their ""%" HEX HEX" encoding.

      o  An IP address that is the result of a DNS lookup of a host name
         does not match that host name.

      o  For two URIs to be equal, the user, password, host, and port
         components must match.
*/
		if (!uri_a->host || !uri_b->host) {
			return 0;
		} else if  (IS_EQUAL_CASE(uri_a->host,uri_b->host)) {
			return 0;
		}
		if (uri_a->port !=uri_b->port) return 0;
/*
         A URI omitting the user component will not match a URI that
         includes one.  A URI omitting the password component will not
         match a URI that includes one.

         A URI omitting any component with a default value will not
         match a URI explicitly containing that component with its
         default value.  For instance, a URI omitting the optional port
         component will not match a URI explicitly declaring port 5060.
         The same is true for the transport-parameter, ttl-parameter,
         user-parameter, and method components.

            Defining sip:user@host to not be equivalent to
            sip:user@host:5060 is a change from RFC 2543.  When deriving
            addresses from URIs, equivalent addresses are expected from
            equivalent URIs.  The URI sip:user@host:5060 will always
            resolve to port 5060.  The URI sip:user@host may resolve to
            other ports through the DNS SRV mechanisms detailed in [4].

      o  URI uri-parameter components are compared as follows:

         -  Any uri-parameter appearing in both URIs must match.
*/
/*
 *         -  A user, ttl, or method uri-parameter appearing in only one
            URI never matches, even if it contains the default value.
           -  A URI that includes an maddr parameter will not match a URI
            that contains no maddr parameter.
 * */
		PARAM_CASE_CMP(uri_a,uri_b,"transport")
		PARAM_CASE_CMP(uri_a,uri_b,"user")
		PARAM_CASE_CMP(uri_a,uri_b,"ttl")
		PARAM_CASE_CMP(uri_a,uri_b,"method")
		PARAM_CASE_CMP(uri_a,uri_b,"maddr")


		for(params=belle_sip_parameters_get_parameters((belle_sip_parameters_t*) uri_a);params!=NULL;params=params->next) {
			if ((b_param=belle_sip_parameters_get_parameter((belle_sip_parameters_t*) uri_b,(const char*)params->data)) !=NULL) {
				if (IS_EQUAL_CASE(b_param,(const char*)params->data)) return 0;
			}

		}

 /*


         -  All other uri-parameters appearing in only one URI are
            ignored when comparing the URIs.
*/
/* *fixme ignored for now*/
/*
      o  URI header components are never ignored.  Any present header
         component MUST be present in both URIs and match for the URIs
         to match.  The matching rules are defined for each header field
         in Section 20.
 */
329
	return 1;
jehan's avatar
jehan committed
330
}
jehan's avatar
jehan committed
331