provider.c 40.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/*
	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/>.
*/

#include "belle_sip_internal.h"
jehan's avatar
jehan committed
20
#include "listeningpoint_internal.h"
Simon Morlat's avatar
Simon Morlat committed
21 22
#include "md5.h"

23
belle_sip_dialog_t *belle_sip_provider_find_dialog_from_msg(belle_sip_provider_t *prov, belle_sip_request_t *msg, int as_uas);
24

25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
typedef struct authorization_context {
	belle_sip_header_call_id_t* callid;
	const char* scheme;
	const char* realm;
	const char* nonce;
	const char* qop;
	const char* opaque;
	int nonce_count;
	int is_proxy;
}authorization_context_t;

GET_SET_STRING(authorization_context,realm)
GET_SET_STRING(authorization_context,nonce)
GET_SET_STRING(authorization_context,qop)
GET_SET_STRING(authorization_context,scheme)
GET_SET_STRING(authorization_context,opaque)
GET_SET_INT(authorization_context,nonce_count,int)
static authorization_context_t* belle_sip_authorization_create(belle_sip_header_call_id_t* call_id) {
	authorization_context_t* result = malloc(sizeof(authorization_context_t));
	memset(result,0,sizeof(authorization_context_t));
	result->callid=call_id;
	belle_sip_object_ref(result->callid);
	return result;
}
static void belle_sip_authorization_destroy(authorization_context_t* object) {
	DESTROY_STRING(object,scheme);
	DESTROY_STRING(object,realm);
	DESTROY_STRING(object,nonce);
	DESTROY_STRING(object,qop);
jehan's avatar
jehan committed
54
	DESTROY_STRING(object,opaque);
55 56 57
	belle_sip_object_unref(object->callid);
	belle_sip_free(object);
}
58 59

static void belle_sip_provider_uninit(belle_sip_provider_t *p){
60
	p->listeners=belle_sip_list_free(p->listeners);
jehan's avatar
jehan committed
61
	p->internal_listeners=belle_sip_list_free(p->internal_listeners);
62 63 64 65 66
	p->client_transactions=belle_sip_list_free_with_data(p->client_transactions,belle_sip_object_unref);
	p->server_transactions=belle_sip_list_free_with_data(p->server_transactions,belle_sip_object_unref);
	p->auth_contexts=belle_sip_list_free_with_data(p->auth_contexts,(void(*)(void*))belle_sip_authorization_destroy);
	p->dialogs=belle_sip_list_free_with_data(p->dialogs,belle_sip_object_unref);
	p->lps=belle_sip_list_free_with_data(p->lps,belle_sip_object_unref);
67 68
}

69
static void channel_state_changed(belle_sip_channel_listener_t *obj, belle_sip_channel_t *chan, belle_sip_channel_state_t state){
70
	belle_sip_io_error_event_t ev;
71
	belle_sip_provider_t* prov=BELLE_SIP_PROVIDER(obj);
jehan's avatar
jehan committed
72
	if (state == BELLE_SIP_CHANNEL_ERROR || state == BELLE_SIP_CHANNEL_DISCONNECTED) {
73
		ev.transport=belle_sip_channel_get_transport_name(chan);
74 75
		ev.port=chan->peer_port;
		ev.host=chan->peer_name;
jehan's avatar
jehan committed
76
		ev.source=BELLE_SIP_OBJECT(prov);
77
		BELLE_SIP_PROVIDER_INVOKE_LISTENERS(prov->listeners,process_io_error,&ev);
78 79
		/*IO error is also relevant for internal listener like refreshers*/
		BELLE_SIP_PROVIDER_INVOKE_LISTENERS(prov->internal_listeners,process_io_error,&ev);
Simon Morlat's avatar
Simon Morlat committed
80
		if (!chan->force_close) belle_sip_provider_release_channel(prov,chan);
81
	}
82 83
}

Simon Morlat's avatar
Simon Morlat committed
84 85
static void belle_sip_provider_dispatch_request(belle_sip_provider_t* prov, belle_sip_request_t *req){
	belle_sip_server_transaction_t *t;
jehan's avatar
jehan committed
86
	belle_sip_request_event_t ev;
Simon Morlat's avatar
Simon Morlat committed
87 88 89 90 91 92
	t=belle_sip_provider_find_matching_server_transaction(prov,req);
	if (t){
		belle_sip_object_ref(t);
		belle_sip_server_transaction_on_request(t,req);
		belle_sip_object_unref(t);
	}else{
Simon Morlat's avatar
Simon Morlat committed
93
		const char *method=belle_sip_request_get_method(req);
jehan's avatar
jehan committed
94
		ev.dialog=NULL;
jehan's avatar
jehan committed
95
		/* Should we limit to ACK ?  */
jehan's avatar
jehan committed
96 97
		/*Search for a dialog if exist */

98
		ev.dialog=belle_sip_provider_find_dialog_from_msg(prov,req,1/*request=uas*/);
Simon Morlat's avatar
Simon Morlat committed
99 100 101 102 103 104
		if (ev.dialog){
			if (strcmp("ACK",method)==0){
				if (belle_sip_dialog_handle_ack(ev.dialog,req)==-1){
					/*absorbed ACK retransmission, ignore */
					return;
				}
105
			}else if (!belle_sip_dialog_is_authorized_transaction(ev.dialog,method)){
Simon Morlat's avatar
Simon Morlat committed
106 107 108
				belle_sip_server_transaction_t *tr=belle_sip_provider_create_server_transaction(prov,req);
				belle_sip_server_transaction_send_response(tr,
					belle_sip_response_create_from_request(req,491));
109 110 111
				return;
			}
		}
112 113 114 115 116 117 118 119 120 121
		if (prov->unconditional_answer_enabled && strcmp("ACK",method)!=0) { /*always answer 480 in this case*/
			belle_sip_server_transaction_t *tr=belle_sip_provider_create_server_transaction(prov,req);
			belle_sip_server_transaction_send_response(tr,belle_sip_response_create_from_request(req,480));
			return;
		} else {
			ev.source=prov;
			ev.server_transaction=NULL;
			ev.request=req;
			BELLE_SIP_PROVIDER_INVOKE_LISTENERS(prov->listeners,process_request_event,&ev);
		}
Simon Morlat's avatar
Simon Morlat committed
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
	}
}

static void belle_sip_provider_dispatch_response(belle_sip_provider_t* prov, belle_sip_response_t *msg){
	belle_sip_client_transaction_t *t;
	t=belle_sip_provider_find_matching_client_transaction(prov,msg);
	/*
	 * If a transaction is found, pass it to the transaction and let it decide what to do.
	 * Else notifies directly.
	 */
	if (t){
		/*since the add_response may indirectly terminate the transaction, we need to guarantee the transaction is not freed
		 * until full completion*/
		belle_sip_object_ref(t);
		belle_sip_client_transaction_add_response(t,msg);
		belle_sip_object_unref(t);
	}else{
		belle_sip_response_event_t event;
Simon Morlat's avatar
Simon Morlat committed
140
		event.source=prov;
Simon Morlat's avatar
Simon Morlat committed
141
		event.client_transaction=NULL;
Simon Morlat's avatar
Simon Morlat committed
142
		event.dialog=NULL;
Simon Morlat's avatar
Simon Morlat committed
143
		event.response=msg;
jehan's avatar
jehan committed
144
		BELLE_SIP_PROVIDER_INVOKE_LISTENERS(prov->listeners,process_response_event,&event);
Simon Morlat's avatar
Simon Morlat committed
145 146 147
	}
}

148
void belle_sip_provider_dispatch_message(belle_sip_provider_t *prov, belle_sip_message_t *msg){
149 150 151 152 153 154
	if (belle_sip_message_check_headers(msg)){
		if (belle_sip_message_is_request(msg)){
			belle_sip_provider_dispatch_request(prov,(belle_sip_request_t*)msg);
		}else{
			belle_sip_provider_dispatch_response(prov,(belle_sip_response_t*)msg);
		}
Simon Morlat's avatar
Simon Morlat committed
155
	}else{
156 157 158 159 160 161 162
		/* incorrect message received, answer bad request if it was a request.*/
		if (belle_sip_message_is_request(msg)){
			belle_sip_response_t *resp=belle_sip_response_create_from_request(BELLE_SIP_REQUEST(msg),400);
			if (resp){
				belle_sip_provider_send_response(prov,resp);
			}
		}/*otherwise what can we do ?*/
Simon Morlat's avatar
Simon Morlat committed
163
	}
164
	belle_sip_object_unref(msg);
Simon Morlat's avatar
Simon Morlat committed
165 166
}

Simon Morlat's avatar
Simon Morlat committed
167 168 169
/*
 * takes example on 16.11 of RFC3261
 */
170
static void compute_hash_from_invariants(belle_sip_message_t *msg, char *branchid, size_t branchid_size, const char *initial){
Simon Morlat's avatar
Simon Morlat committed
171 172 173 174 175 176 177
	md5_state_t ctx;
	unsigned int cseq=belle_sip_header_cseq_get_seq_number(belle_sip_message_get_header_by_type(msg,belle_sip_header_cseq_t));
	char tmp[256]={0};
	uint8_t digest[16];
	const char*callid=belle_sip_header_call_id_get_call_id(belle_sip_message_get_header_by_type(msg,belle_sip_header_call_id_t));
	const char *from_tag=belle_sip_header_from_get_tag(belle_sip_message_get_header_by_type(msg,belle_sip_header_from_t));
	const char *to_tag=belle_sip_header_to_get_tag(belle_sip_message_get_header_by_type(msg,belle_sip_header_to_t));
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
	belle_sip_uri_t *requri=NULL;
	belle_sip_header_via_t *via=NULL;
	belle_sip_header_via_t *prev_via=NULL;
	const belle_sip_list_t *vias=belle_sip_message_get_headers(msg,"via");
	int is_request=belle_sip_message_is_request(msg);
	
	if (vias){
		via=(belle_sip_header_via_t*)vias->data;
		if (vias->next){
			prev_via=(belle_sip_header_via_t*)vias->next->data;
		}
	}
	
	if (is_request){
		requri=belle_sip_request_get_uri(BELLE_SIP_REQUEST(msg));
	}
Simon Morlat's avatar
Simon Morlat committed
194
	
195
	belle_sip_md5_init(&ctx);
196
	if (initial)
197
		belle_sip_md5_append(&ctx,(uint8_t*)initial,strlen(initial));
198
	if (requri){
199
		size_t offset=0;
Ghislain MARY's avatar
Ghislain MARY committed
200
		belle_sip_object_marshal((belle_sip_object_t*)requri,tmp,sizeof(tmp)-1,&offset);
201
		belle_sip_md5_append(&ctx,(uint8_t*)tmp,strlen(tmp));
202
	}
Simon Morlat's avatar
Simon Morlat committed
203
	if (from_tag)
204
		belle_sip_md5_append(&ctx,(uint8_t*)from_tag,strlen(from_tag));
Simon Morlat's avatar
Simon Morlat committed
205
	if (to_tag)
206 207 208
		belle_sip_md5_append(&ctx,(uint8_t*)to_tag,strlen(to_tag));
	belle_sip_md5_append(&ctx,(uint8_t*)callid,strlen(callid));
	belle_sip_md5_append(&ctx,(uint8_t*)&cseq,sizeof(cseq));
209 210
	if (is_request){
		if (prev_via){
211
			size_t offset=0;
Ghislain MARY's avatar
Ghislain MARY committed
212
			belle_sip_object_marshal((belle_sip_object_t*)prev_via,tmp,sizeof(tmp)-1,&offset);
213
			belle_sip_md5_append(&ctx,(uint8_t*)tmp,offset);
214 215 216
		}
	}else{
		if (via){
217
			size_t offset=0;
Ghislain MARY's avatar
Ghislain MARY committed
218
			belle_sip_object_marshal((belle_sip_object_t*)via,tmp,sizeof(tmp)-1,&offset);
219
			belle_sip_md5_append(&ctx,(uint8_t*)tmp,offset);
220
		}
Simon Morlat's avatar
Simon Morlat committed
221
	}
222
	belle_sip_md5_finish(&ctx,digest);
Simon Morlat's avatar
Simon Morlat committed
223 224 225
	belle_sip_octets_to_text(digest,sizeof(digest),branchid,branchid_size);
}

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
static char *compute_rfc2543_branch(belle_sip_request_t *req, char *branchid, size_t branchid_size){
	md5_state_t ctx;
	unsigned int cseq=belle_sip_header_cseq_get_seq_number(belle_sip_message_get_header_by_type(req,belle_sip_header_cseq_t));
	char tmp[256]={0};
	uint8_t digest[16];
	const char*callid=belle_sip_header_call_id_get_call_id(belle_sip_message_get_header_by_type(req,belle_sip_header_call_id_t));
	const char *from_tag=belle_sip_header_from_get_tag(belle_sip_message_get_header_by_type(req,belle_sip_header_from_t));
	const char *to_tag=belle_sip_header_to_get_tag(belle_sip_message_get_header_by_type(req,belle_sip_header_to_t));
	belle_sip_header_via_t *via=NULL;
	const belle_sip_list_t *vias=belle_sip_message_get_headers((belle_sip_message_t*)req,"via");
	
	belle_sip_md5_init(&ctx);
	
	if (from_tag)
		belle_sip_md5_append(&ctx,(uint8_t*)from_tag,strlen(from_tag));
	if (to_tag)
		belle_sip_md5_append(&ctx,(uint8_t*)to_tag,strlen(to_tag));
	belle_sip_md5_append(&ctx,(uint8_t*)callid,strlen(callid));
	belle_sip_md5_append(&ctx,(uint8_t*)&cseq,sizeof(cseq));
	
	for(;vias!=NULL;vias=vias->next){
		size_t offset=0;
		via=(belle_sip_header_via_t*)vias->data;
		belle_sip_object_marshal((belle_sip_object_t*)via,tmp,sizeof(tmp)-1,&offset);
		belle_sip_md5_append(&ctx,(uint8_t*)tmp,offset);
	}

	belle_sip_md5_finish(&ctx,digest);
	belle_sip_octets_to_text(digest,sizeof(digest),branchid,branchid_size);
	return branchid;
}

258 259
static void fix_outgoing_via(belle_sip_provider_t *p, belle_sip_channel_t *chan, belle_sip_message_t *msg){
	belle_sip_header_via_t *via=BELLE_SIP_HEADER_VIA(belle_sip_message_get_header(msg,"via"));
260
	if (p->rport_enabled) belle_sip_parameters_set_parameter(BELLE_SIP_PARAMETERS(via),"rport",NULL);
Simon Morlat's avatar
Simon Morlat committed
261

262 263 264 265 266
	belle_sip_header_via_set_host(via,chan->local_ip);
	belle_sip_header_via_set_port(via,chan->local_port);
	belle_sip_header_via_set_protocol(via,"SIP/2.0");
	belle_sip_header_via_set_transport(via,belle_sip_channel_get_transport_name(chan));
	
267
	if (belle_sip_header_via_get_branch(via)==NULL){
Simon Morlat's avatar
Simon Morlat committed
268 269 270
		/*branch id should not be set random here (stateless forwarding): but rather a hash of message invariants*/
		char branchid[24];
		char token[BELLE_SIP_BRANCH_ID_LENGTH];
271
		compute_hash_from_invariants(msg,token,sizeof(token),NULL);
Simon Morlat's avatar
Simon Morlat committed
272
		snprintf(branchid,sizeof(branchid)-1,BELLE_SIP_BRANCH_MAGIC_COOKIE ".%s",token);
273
		belle_sip_header_via_set_branch(via,branchid);
Simon Morlat's avatar
Simon Morlat committed
274
		belle_sip_message("Computing branch id %s for message sent statelessly", branchid);
275 276
	}
}
jehan's avatar
jehan committed
277

Simon Morlat's avatar
Simon Morlat committed
278 279
static int channel_on_event(belle_sip_channel_listener_t *obj, belle_sip_channel_t *chan, unsigned int revents){
	if (revents & BELLE_SIP_EVENT_READ){
280 281 282
		belle_sip_message_t *msg;
		while ((msg=belle_sip_channel_pick_message(chan)))
			belle_sip_provider_dispatch_message(BELLE_SIP_PROVIDER(obj),msg);
Simon Morlat's avatar
Simon Morlat committed
283 284 285
	}
	return 0;
}
Simon Morlat's avatar
Simon Morlat committed
286

jehan's avatar
jehan committed
287 288 289 290
static int channel_on_auth_requested(belle_sip_channel_listener_t *obj, belle_sip_channel_t *chan, const char* distinguished_name){
	if (BELLE_SIP_IS_INSTANCE_OF(chan,belle_sip_tls_channel_t)) {
		belle_sip_provider_t *prov=BELLE_SIP_PROVIDER(obj);
		belle_sip_auth_event_t* auth_event = belle_sip_auth_event_create(NULL,NULL);
Simon Morlat's avatar
Simon Morlat committed
291
		belle_sip_tls_channel_t *tls_chan=BELLE_SIP_TLS_CHANNEL(chan);
jehan's avatar
jehan committed
292 293 294
		auth_event->mode=BELLE_SIP_AUTH_MODE_TLS;
		belle_sip_auth_event_set_distinguished_name(auth_event,distinguished_name);
		BELLE_SIP_PROVIDER_INVOKE_LISTENERS(prov->listeners,process_auth_requested,auth_event);
Simon Morlat's avatar
Simon Morlat committed
295 296
		belle_sip_tls_channel_set_client_certificates_chain(tls_chan,auth_event->cert);
		belle_sip_tls_channel_set_client_certificate_key(tls_chan,auth_event->key);
jehan's avatar
jehan committed
297 298 299 300
		belle_sip_auth_event_destroy(auth_event);
	}
	return 0;
}
Simon Morlat's avatar
Simon Morlat committed
301

302
static void channel_on_sending(belle_sip_channel_listener_t *obj, belle_sip_channel_t *chan, belle_sip_message_t *msg){
303
	belle_sip_header_contact_t* contact;
jehan's avatar
jehan committed
304
	belle_sip_header_content_length_t* content_lenght = (belle_sip_header_content_length_t*)belle_sip_message_get_header(msg,"Content-Length");
jehan's avatar
jehan committed
305
	belle_sip_uri_t* contact_uri;
306 307 308 309
	const belle_sip_list_t *contacts;
	const char *ip=NULL;
	int port=0;
	belle_sip_provider_t *prov=BELLE_SIP_PROVIDER(obj);
Simon Morlat's avatar
Simon Morlat committed
310 311 312 313 314

	if (belle_sip_message_is_request(msg)){
		/*probably better to be in channel*/
		fix_outgoing_via((belle_sip_provider_t*)obj,chan,msg);
	}
Simon Morlat's avatar
Simon Morlat committed
315

316 317 318 319 320 321 322
	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))) {
Simon Morlat's avatar
Simon Morlat committed
323 324
			contact_uri = belle_sip_uri_new();
			belle_sip_header_address_set_uri((belle_sip_header_address_t*)contact,contact_uri);
325 326 327
			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);
Simon Morlat's avatar
Simon Morlat committed
328
		}
329 330 331 332 333 334
		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;
335
				belle_sip_header_contact_set_unknown(contact,!chan->learnt_ip_port);
336 337 338 339
			}else{
				ip=chan->local_ip;
				port=chan->local_port;
			}
Simon Morlat's avatar
Simon Morlat committed
340
		}
341 342 343 344 345 346 347
		
		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);
Simon Morlat's avatar
Simon Morlat committed
348
		}
349
		if (port!=belle_sip_listening_point_get_well_known_port(transport)) {
350
			belle_sip_uri_set_port(contact_uri,port);
351 352
		}else{
			belle_sip_uri_set_port(contact_uri,0);
Simon Morlat's avatar
Simon Morlat committed
353
		}
jehan's avatar
jehan committed
354
	}
355
	
jehan's avatar
jehan committed
356 357 358 359
	if (!content_lenght && strcasecmp("udp",belle_sip_channel_get_transport_name(chan))!=0) {
		content_lenght = belle_sip_header_content_length_create(0);
		belle_sip_message_add_header(msg,(belle_sip_header_t*)content_lenght);
	}
360 361
}

362
BELLE_SIP_IMPLEMENT_INTERFACE_BEGIN(belle_sip_provider_t,belle_sip_channel_listener_t)
Simon Morlat's avatar
Simon Morlat committed
363
	channel_state_changed,
364
	channel_on_event,
jehan's avatar
jehan committed
365 366
	channel_on_sending,
	channel_on_auth_requested
367 368 369 370
BELLE_SIP_IMPLEMENT_INTERFACE_END

BELLE_SIP_DECLARE_IMPLEMENTED_INTERFACES_1(belle_sip_provider_t,belle_sip_channel_listener_t);
	
Simon Morlat's avatar
Simon Morlat committed
371
BELLE_SIP_INSTANCIATE_VPTR(belle_sip_provider_t,belle_sip_object_t,belle_sip_provider_uninit,NULL,NULL,FALSE);
Simon Morlat's avatar
Simon Morlat committed
372

373
belle_sip_provider_t *belle_sip_provider_new(belle_sip_stack_t *s, belle_sip_listening_point_t *lp){
Simon Morlat's avatar
Simon Morlat committed
374
	belle_sip_provider_t *p=belle_sip_object_new(belle_sip_provider_t);
375
	p->stack=s;
376
	p->rport_enabled=1;
jehan's avatar
jehan committed
377
	if (lp) belle_sip_provider_add_listening_point(p,lp);
378 379 380 381
	return p;
}

int belle_sip_provider_add_listening_point(belle_sip_provider_t *p, belle_sip_listening_point_t *lp){
jehan's avatar
jehan committed
382 383 384 385
	if (lp == NULL) {
		belle_sip_error("Cannot add NULL lp to provider [%p]",p);
		return -1;
	}
386
	belle_sip_listening_point_set_channel_listener(lp,BELLE_SIP_CHANNEL_LISTENER(p));
Simon Morlat's avatar
Simon Morlat committed
387
	p->lps=belle_sip_list_append(p->lps,belle_sip_object_ref(lp));
388 389
	return 0;
}
Simon Morlat's avatar
Simon Morlat committed
390

jehan's avatar
jehan committed
391 392 393 394 395
void belle_sip_provider_remove_listening_point(belle_sip_provider_t *p, belle_sip_listening_point_t *lp) {
	p->lps=belle_sip_list_remove(p->lps,lp);
	belle_sip_object_unref(lp);
	return;
}
396 397 398 399 400 401 402 403 404 405 406 407 408 409 410

belle_sip_listening_point_t *belle_sip_provider_get_listening_point(belle_sip_provider_t *p, const char *transport){
	belle_sip_list_t *l;
	for(l=p->lps;l!=NULL;l=l->next){
		belle_sip_listening_point_t *lp=(belle_sip_listening_point_t*)l->data;
		if (strcasecmp(belle_sip_listening_point_get_transport(lp),transport)==0)
			return lp;
	}
	return NULL;
}

const belle_sip_list_t *belle_sip_provider_get_listening_points(belle_sip_provider_t *p){
	return p->lps;
}

411 412 413 414 415
void belle_sip_provider_add_internal_sip_listener(belle_sip_provider_t *p, belle_sip_listener_t *l, int prepend){
	if (prepend)
		p->internal_listeners=belle_sip_list_prepend(p->internal_listeners,l);
	else 
		p->internal_listeners=belle_sip_list_append(p->internal_listeners,l);
jehan's avatar
jehan committed
416 417 418 419 420 421
}

void belle_sip_provider_remove_internal_sip_listener(belle_sip_provider_t *p, belle_sip_listener_t *l){
	p->internal_listeners=belle_sip_list_remove(p->internal_listeners,l);
}

422 423
void belle_sip_provider_add_sip_listener(belle_sip_provider_t *p, belle_sip_listener_t *l){
	p->listeners=belle_sip_list_append(p->listeners,l);
424 425
}

426 427
void belle_sip_provider_remove_sip_listener(belle_sip_provider_t *p, belle_sip_listener_t *l){
	p->listeners=belle_sip_list_remove(p->listeners,l);
428 429
}

430
belle_sip_header_call_id_t * belle_sip_provider_create_call_id(const belle_sip_provider_t *prov){
431
	belle_sip_header_call_id_t *cid=belle_sip_header_call_id_new();
432 433
	char tmp[11];
	belle_sip_header_call_id_set_call_id(cid,belle_sip_random_token(tmp,sizeof(tmp)));
434 435
	return cid;
}
436

jehan's avatar
jehan committed
437 438 439
belle_sip_dialog_t * belle_sip_provider_create_dialog(belle_sip_provider_t *prov, belle_sip_transaction_t *t) {
	return belle_sip_provider_create_dialog_internal(prov,t,TRUE);
}
440

jehan's avatar
jehan committed
441
belle_sip_dialog_t * belle_sip_provider_create_dialog_internal(belle_sip_provider_t *prov, belle_sip_transaction_t *t,unsigned int check_last_resp){
Simon Morlat's avatar
Simon Morlat committed
442
	belle_sip_dialog_t *dialog=NULL;
Simon Morlat's avatar
Simon Morlat committed
443
	
jehan's avatar
jehan committed
444
	if (check_last_resp && t->last_response){
Simon Morlat's avatar
Simon Morlat committed
445 446 447
		int code=belle_sip_response_get_status_code(t->last_response);
		if (code>=200 && code<300){
			belle_sip_fatal("You must not create dialog after sending the response that establish the dialog.");
jehan's avatar
jehan committed
448
			return NULL;
Simon Morlat's avatar
Simon Morlat committed
449 450
		}
	}
Simon Morlat's avatar
Simon Morlat committed
451
	dialog=belle_sip_dialog_new(t);
jehan's avatar
jehan committed
452
	if (dialog) {
Simon Morlat's avatar
Simon Morlat committed
453 454
		belle_sip_transaction_set_dialog(t,dialog);
		belle_sip_provider_add_dialog(prov,dialog);
jehan's avatar
jehan committed
455
	}
Simon Morlat's avatar
Simon Morlat committed
456 457 458
	return dialog;
}

Simon Morlat's avatar
Simon Morlat committed
459
/*finds an existing dialog for an outgoing or incoming request */
460
belle_sip_dialog_t *belle_sip_provider_find_dialog_from_msg(belle_sip_provider_t *prov, belle_sip_request_t *msg, int as_uas){
Simon Morlat's avatar
Simon Morlat committed
461 462
	belle_sip_list_t *elem;
	belle_sip_dialog_t *dialog;
jehan's avatar
jehan committed
463
	belle_sip_dialog_t *returned_dialog=NULL;
464 465
	belle_sip_header_call_id_t *call_id;
	belle_sip_header_from_t *from;
466
	belle_sip_header_to_t *to;
Simon Morlat's avatar
Simon Morlat committed
467 468 469 470
	const char *from_tag;
	const char *to_tag;
	const char *call_id_value;
	const char *local_tag,*remote_tag;
471
	
472 473 474 475 476 477
	if (msg->dialog){
		return msg->dialog;
	}
	
	to=belle_sip_message_get_header_by_type(msg,belle_sip_header_to_t);
	
478 479 480 481 482 483 484
	if (to==NULL || (to_tag=belle_sip_header_to_get_tag(to))==NULL){
		/* a request without to tag cannot be part of a dialog */
		return NULL;
	}
	
	call_id=belle_sip_message_get_header_by_type(msg,belle_sip_header_call_id_t);
	from=belle_sip_message_get_header_by_type(msg,belle_sip_header_from_t);
Simon Morlat's avatar
Simon Morlat committed
485

486
	if (call_id==NULL || from==NULL) return NULL;
Simon Morlat's avatar
Simon Morlat committed
487 488 489

	call_id_value=belle_sip_header_call_id_get_call_id(call_id);
	from_tag=belle_sip_header_from_get_tag(from);
490
	
Simon Morlat's avatar
Simon Morlat committed
491 492 493 494 495
	local_tag=as_uas ? to_tag : from_tag;
	remote_tag=as_uas ? from_tag : to_tag;
	
	for (elem=prov->dialogs;elem!=NULL;elem=elem->next){
		dialog=(belle_sip_dialog_t*)elem->data;
jehan's avatar
jehan committed
496 497 498 499 500 501 502
		/*ignore dialog in state BELLE_SIP_DIALOG_NULL, is it really the correct things to do*/
		if (belle_sip_dialog_get_state(dialog) != BELLE_SIP_DIALOG_NULL && _belle_sip_dialog_match(dialog,call_id_value,local_tag,remote_tag)) {
			if (!returned_dialog)
				returned_dialog=dialog;
			else
				belle_sip_fatal("More than 1 dialog is matching, check your app");
		}
Simon Morlat's avatar
Simon Morlat committed
503
	}
jehan's avatar
jehan committed
504
	return returned_dialog;
Simon Morlat's avatar
Simon Morlat committed
505 506
}

Simon Morlat's avatar
Simon Morlat committed
507 508 509 510
void belle_sip_provider_add_dialog(belle_sip_provider_t *prov, belle_sip_dialog_t *dialog){
	prov->dialogs=belle_sip_list_prepend(prov->dialogs,belle_sip_object_ref(dialog));
}

jehan's avatar
jehan committed
511 512 513 514 515
static void notify_dialog_terminated(belle_sip_dialog_terminated_event_t* ev) {
	BELLE_SIP_PROVIDER_INVOKE_LISTENERS(((belle_sip_provider_t*)ev->source)->listeners,process_dialog_terminated,ev);
	belle_sip_object_unref(ev->dialog);
	belle_sip_free(ev);
}
Simon Morlat's avatar
Simon Morlat committed
516

Simon Morlat's avatar
Simon Morlat committed
517
void belle_sip_provider_remove_dialog(belle_sip_provider_t *prov, belle_sip_dialog_t *dialog){
jehan's avatar
jehan committed
518 519 520
	belle_sip_dialog_terminated_event_t* ev=belle_sip_malloc(sizeof(belle_sip_dialog_terminated_event_t));
	ev->source=prov;
	ev->dialog=dialog;
Simon Morlat's avatar
Simon Morlat committed
521
	prov->dialogs=belle_sip_list_remove(prov->dialogs,dialog);
jehan's avatar
jehan committed
522 523 524 525
	belle_sip_main_loop_do_later(belle_sip_stack_get_main_loop(prov->stack)
													,(belle_sip_callback_t) notify_dialog_terminated
													, ev);

Simon Morlat's avatar
Simon Morlat committed
526 527
}

Simon Morlat's avatar
Simon Morlat committed
528
belle_sip_client_transaction_t *belle_sip_provider_create_client_transaction(belle_sip_provider_t *prov, belle_sip_request_t *req){
529
	const char *method=belle_sip_request_get_method(req);
530
	belle_sip_client_transaction_t *t;
531
	belle_sip_client_transaction_t *inv_transaction;
532
	if (strcmp(method,"INVITE")==0)
533
		t=(belle_sip_client_transaction_t*)belle_sip_ict_new(prov,req);
534 535 536
	else if (strcmp(method,"ACK")==0){
		belle_sip_error("belle_sip_provider_create_client_transaction() cannot be used for ACK requests.");
		return NULL;
537 538 539 540 541 542 543 544 545 546 547
	} else {
		t=(belle_sip_client_transaction_t*)belle_sip_nict_new(prov,req);
		if (strcmp(method,"CANCEL")==0){
			/*force next hop*/
			inv_transaction=belle_sip_provider_find_matching_client_transaction_from_req(prov,req);
			if (inv_transaction && inv_transaction->next_hop) {
				/*found corresponding ict, taking next hop*/
				/*9.1 Client Behavior
				 * The destination address,
				   port, and transport for the CANCEL MUST be identical to those used to
				   send the original request.*/
Simon Morlat's avatar
Simon Morlat committed
548
				t->next_hop=(belle_sip_hop_t*)belle_sip_object_ref(inv_transaction->next_hop);
549
			} else {
Simon Morlat's avatar
Simon Morlat committed
550
				belle_sip_error ("No corresponding ict nor dest found for cancel request attached to transaction [%p]",t);
551 552
			}
		}
553
	}
554
	belle_sip_transaction_set_dialog((belle_sip_transaction_t*)t,belle_sip_provider_find_dialog_from_msg(prov,req,FALSE));
555 556
	belle_sip_request_set_dialog(req,NULL);/*get rid of the reference to the dialog, which is no longer needed in the message.
					This is to avoid circular references.*/
557
	return t;
558 559
}

Simon Morlat's avatar
Simon Morlat committed
560
belle_sip_server_transaction_t *belle_sip_provider_create_server_transaction(belle_sip_provider_t *prov, belle_sip_request_t *req){
Simon Morlat's avatar
Simon Morlat committed
561
	belle_sip_server_transaction_t* t;
562
	if (strcmp(belle_sip_request_get_method(req),"INVITE")==0){
Simon Morlat's avatar
Simon Morlat committed
563
		t=(belle_sip_server_transaction_t*)belle_sip_ist_new(prov,req);
564 565 566 567
	}else if (strcmp(belle_sip_request_get_method(req),"ACK")==0){
		belle_sip_error("Creating a server transaction for an ACK is not a good idea, probably");
		return NULL;
	}else 
Simon Morlat's avatar
Simon Morlat committed
568
		t=(belle_sip_server_transaction_t*)belle_sip_nist_new(prov,req);
569
	belle_sip_transaction_set_dialog((belle_sip_transaction_t*)t,belle_sip_provider_find_dialog_from_msg(prov,req,TRUE));
Simon Morlat's avatar
Simon Morlat committed
570 571
	belle_sip_provider_add_server_transaction(prov,t);
	return t;
572 573 574 575 576 577
}

belle_sip_stack_t *belle_sip_provider_get_sip_stack(belle_sip_provider_t *p){
	return p->stack;
}

578
belle_sip_channel_t * belle_sip_provider_get_channel(belle_sip_provider_t *p, const belle_sip_hop_t *hop){
579 580 581
	belle_sip_list_t *l;
	belle_sip_listening_point_t *candidate=NULL,*lp;
	belle_sip_channel_t *chan;
582
	
jehan's avatar
jehan committed
583 584 585 586 587 588 589 590 591 592 593 594 595
	if (hop->transport!=NULL) {
		for(l=p->lps;l!=NULL;l=l->next){
			lp=(belle_sip_listening_point_t*)l->data;
			if (strcasecmp(belle_sip_listening_point_get_transport(lp),hop->transport)==0){
				chan=belle_sip_listening_point_get_channel(lp,hop);
				if (chan) return chan;
				candidate=lp;
			}
		}
		if (candidate){
			chan=belle_sip_listening_point_create_channel(candidate,hop);
			if (!chan) belle_sip_error("Could not create channel to [%s://%s:%i]",hop->transport,hop->host,hop->port);
			return chan;
596 597
		}
	}
jehan's avatar
jehan committed
598
	belle_sip_error("No listening point matching for [%s://%s:%i]",hop->transport,hop->host,hop->port);
599
	return NULL;
Simon Morlat's avatar
wip  
Simon Morlat committed
600 601
}

Simon Morlat's avatar
wip  
Simon Morlat committed
602 603 604 605
void belle_sip_provider_release_channel(belle_sip_provider_t *p, belle_sip_channel_t *chan){
	belle_sip_listening_point_remove_channel(chan->lp,chan);
}

606 607 608
void belle_sip_provider_clean_channels(belle_sip_provider_t *p){
	belle_sip_list_t *l;
	belle_sip_listening_point_t *lp;
Simon Morlat's avatar
Simon Morlat committed
609
	
610 611 612 613 614 615
	for(l=p->lps;l!=NULL;l=l->next){
		lp=(belle_sip_listening_point_t*)l->data;
		belle_sip_listening_point_clean_channels(lp);
	}
}

616
void belle_sip_provider_send_request(belle_sip_provider_t *p, belle_sip_request_t *req){
617
	belle_sip_hop_t* hop;
618
	belle_sip_channel_t *chan;
Simon Morlat's avatar
Simon Morlat committed
619
	hop=belle_sip_stack_get_next_hop(p->stack,req);
620
	chan=belle_sip_provider_get_channel(p,hop);
621 622 623
	if (chan) {
		belle_sip_channel_queue_message(chan,BELLE_SIP_MESSAGE(req));
	}
624 625
}

Simon Morlat's avatar
wip  
Simon Morlat committed
626
void belle_sip_provider_send_response(belle_sip_provider_t *p, belle_sip_response_t *resp){
jehan's avatar
jehan committed
627
	belle_sip_hop_t* hop;
628
	belle_sip_channel_t *chan;
629 630
	belle_sip_header_to_t *to=(belle_sip_header_to_t*)belle_sip_message_get_header((belle_sip_message_t*)resp,"to");

631
	if (belle_sip_response_get_status_code(resp)!=100 && to && belle_sip_header_to_get_tag(to)==NULL){
632 633 634
		char token[BELLE_SIP_TAG_LENGTH];
		compute_hash_from_invariants((belle_sip_message_t*)resp,token,sizeof(token),"tag");
		belle_sip_header_to_set_tag(to,token);
635
	}
Simon Morlat's avatar
Simon Morlat committed
636
	hop=belle_sip_response_get_return_hop(resp);
637 638 639 640 641
	if (hop){
		chan=belle_sip_provider_get_channel(p,hop);
		if (chan) belle_sip_channel_queue_message(chan,BELLE_SIP_MESSAGE(resp));
		belle_sip_object_unref(hop);
	}
642 643
}

644

645 646 647
/*private provider API*/

void belle_sip_provider_set_transaction_terminated(belle_sip_provider_t *p, belle_sip_transaction_t *t){
648 649 650 651 652 653
	belle_sip_transaction_terminated_event_t ev;
	
	BELLE_SIP_OBJECT_VPTR(t,belle_sip_transaction_t)->on_terminate(t);
	ev.source=t->provider;
	ev.transaction=t;
	ev.is_server_transaction=BELLE_SIP_IS_INSTANCE_OF(t,belle_sip_server_transaction_t);
jehan's avatar
jehan committed
654
	BELLE_SIP_PROVIDER_INVOKE_LISTENERS_FOR_TRANSACTION(t,process_transaction_terminated,&ev);
655
	if (!ev.is_server_transaction){
Simon Morlat's avatar
Simon Morlat committed
656
		belle_sip_provider_remove_client_transaction(p,(belle_sip_client_transaction_t*)t);
Simon Morlat's avatar
Simon Morlat committed
657 658
	}else{
		belle_sip_provider_remove_server_transaction(p,(belle_sip_server_transaction_t*)t);
Simon Morlat's avatar
Simon Morlat committed
659 660 661 662 663
	}
}

void belle_sip_provider_add_client_transaction(belle_sip_provider_t *prov, belle_sip_client_transaction_t *t){
	prov->client_transactions=belle_sip_list_prepend(prov->client_transactions,belle_sip_object_ref(t));
Simon Morlat's avatar
wip  
Simon Morlat committed
664
}
665

666 667 668 669 670 671 672 673 674 675 676 677 678
struct client_transaction_matcher{
	const char *branchid;
	const char *method;
};

static int client_transaction_match(const void *p_tr, const void *p_matcher){
	belle_sip_client_transaction_t *tr=(belle_sip_client_transaction_t*)p_tr;
	struct client_transaction_matcher *matcher=(struct client_transaction_matcher*)p_matcher;
	const char *req_method=belle_sip_request_get_method(tr->base.request);
	if (strcmp(matcher->branchid,tr->base.branch_id)==0 && strcmp(matcher->method,req_method)==0) return 0;
	return -1;
}

Simon Morlat's avatar
Simon Morlat committed
679 680
belle_sip_client_transaction_t * belle_sip_provider_find_matching_client_transaction(belle_sip_provider_t *prov, 
                                                                                   belle_sip_response_t *resp){
681 682 683 684 685 686 687 688 689
	struct client_transaction_matcher matcher;
	belle_sip_header_via_t *via=(belle_sip_header_via_t*)belle_sip_message_get_header((belle_sip_message_t*)resp,"via");
	belle_sip_header_cseq_t *cseq=(belle_sip_header_cseq_t*)belle_sip_message_get_header((belle_sip_message_t*)resp,"cseq");
	belle_sip_client_transaction_t *ret=NULL;
	belle_sip_list_t *elem;
	if (via==NULL){
		belle_sip_warning("Response has no via.");
		return NULL;
	}
Simon Morlat's avatar
Simon Morlat committed
690
	if (cseq==NULL){
691 692 693 694 695 696 697 698 699 700 701
		belle_sip_warning("Response has no cseq.");
		return NULL;
	}
	matcher.branchid=belle_sip_header_via_get_branch(via);
	matcher.method=belle_sip_header_cseq_get_method(cseq);
	elem=belle_sip_list_find_custom(prov->client_transactions,client_transaction_match,&matcher);
	if (elem){
		ret=(belle_sip_client_transaction_t*)elem->data;
		belle_sip_message("Found transaction matching response.");
	}
	return ret;
Simon Morlat's avatar
Simon Morlat committed
702 703
}

704
void belle_sip_provider_remove_client_transaction(belle_sip_provider_t *prov, belle_sip_client_transaction_t *t){	
jehan's avatar
jehan committed
705 706 707 708 709 710 711 712
	belle_sip_list_t* elem=belle_sip_list_find(prov->client_transactions,t);
	if (elem) {
		prov->client_transactions=belle_sip_list_delete_link(prov->client_transactions,elem);
		belle_sip_object_unref(t);
	} else {
		belle_sip_error("trying to remove transaction [%p] not part of provider [%p]",t,prov);
	}

Simon Morlat's avatar
Simon Morlat committed
713
}
Simon Morlat's avatar
Simon Morlat committed
714 715 716 717 718

void belle_sip_provider_add_server_transaction(belle_sip_provider_t *prov, belle_sip_server_transaction_t *t){
	prov->server_transactions=belle_sip_list_prepend(prov->server_transactions,belle_sip_object_ref(t));
}

719
struct transaction_matcher{
Simon Morlat's avatar
Simon Morlat committed
720 721 722
	const char *branchid;
	const char *method;
	const char *sentby;
723
	int is_ack_or_cancel;
Simon Morlat's avatar
Simon Morlat committed
724 725
};

726
static int transaction_match(const void *p_tr, const void *p_matcher){
727 728 729 730
	belle_sip_transaction_t *tr=(belle_sip_transaction_t*)p_tr;
	struct transaction_matcher *matcher=(struct transaction_matcher*)p_matcher;
	const char *req_method=belle_sip_request_get_method(tr->request);
	if (strcmp(matcher->branchid,tr->branch_id)==0){
Simon Morlat's avatar
Simon Morlat committed
731
		if (strcmp(matcher->method,req_method)==0) return 0;
732
		if (matcher->is_ack_or_cancel && strcmp(req_method,"INVITE")==0) return 0;
Simon Morlat's avatar
Simon Morlat committed
733 734 735 736
	}
	return -1;
}

737 738
belle_sip_transaction_t * belle_sip_provider_find_matching_transaction(belle_sip_list_t *transactions, belle_sip_request_t *req){
	struct transaction_matcher matcher;
Simon Morlat's avatar
Simon Morlat committed
739
	belle_sip_header_via_t *via=(belle_sip_header_via_t*)belle_sip_message_get_header((belle_sip_message_t*)req,"via");
740
	belle_sip_transaction_t *ret=NULL;
741
	belle_sip_list_t *elem=NULL;
742 743 744 745
	const char *branch;
	char token[BELLE_SIP_BRANCH_ID_LENGTH];
	
	
Simon Morlat's avatar
Simon Morlat committed
746
	matcher.method=belle_sip_request_get_method(req);
747
	matcher.is_ack_or_cancel=(strcmp(matcher.method,"ACK")==0 || strcmp(matcher.method,"CANCEL")==0);
748 749 750 751
	
	if (via!=NULL && (branch=belle_sip_header_via_get_branch(via))!=NULL && 
		strncmp(branch,BELLE_SIP_BRANCH_MAGIC_COOKIE,strlen(BELLE_SIP_BRANCH_MAGIC_COOKIE))==0){
		matcher.branchid=branch;
Simon Morlat's avatar
Simon Morlat committed
752
	}else{
753 754 755 756
		/*this request comes from an old equipment, we need to compute our own branch for this request.*/
		matcher.branchid=compute_rfc2543_branch(req,token,sizeof(token));
		belle_sip_request_set_rfc2543_branch(req,token);
		belle_sip_message("Message from old RFC2543 stack, computed branch is %s", token);
Simon Morlat's avatar
Simon Morlat committed
757
	}
758 759

	elem=belle_sip_list_find_custom(transactions,transaction_match,&matcher);
Simon Morlat's avatar
Simon Morlat committed
760 761
	
	if (elem){
762
		ret=(belle_sip_transaction_t*)elem->data;
jehan's avatar
jehan committed
763
		belle_sip_message("Found transaction [%p] matching request.",ret);
Simon Morlat's avatar
Simon Morlat committed
764 765 766
	}
	return ret;
}
767 768 769 770 771 772 773 774
belle_sip_server_transaction_t * belle_sip_provider_find_matching_server_transaction(belle_sip_provider_t *prov, belle_sip_request_t *req) {
	belle_sip_transaction_t *ret=belle_sip_provider_find_matching_transaction(prov->server_transactions,req);
	return ret?BELLE_SIP_SERVER_TRANSACTION(ret):NULL;
}
belle_sip_client_transaction_t * belle_sip_provider_find_matching_client_transaction_from_req(belle_sip_provider_t *prov, belle_sip_request_t *req) {
	belle_sip_transaction_t *ret=belle_sip_provider_find_matching_transaction(prov->client_transactions,req);
	return ret?BELLE_SIP_CLIENT_TRANSACTION(ret):NULL;
}
Simon Morlat's avatar
Simon Morlat committed
775 776 777 778 779

void belle_sip_provider_remove_server_transaction(belle_sip_provider_t *prov, belle_sip_server_transaction_t *t){	
	prov->server_transactions=belle_sip_list_remove(prov->server_transactions,t);
	belle_sip_object_unref(t);
}
780 781 782 783 784 785 786 787 788 789 790 791


static void authorization_context_fill_from_auth(authorization_context_t* auth_context,belle_sip_header_www_authenticate_t* authenticate) {
	authorization_context_set_realm(auth_context,belle_sip_header_www_authenticate_get_realm(authenticate));
	if (auth_context->nonce && strcmp(belle_sip_header_www_authenticate_get_nonce(authenticate),auth_context->nonce)!=0) {
		/*new nonce, resetting nounce_count*/
		auth_context->nonce_count=0;
	}
	authorization_context_set_nonce(auth_context,belle_sip_header_www_authenticate_get_nonce(authenticate));
	authorization_context_set_qop(auth_context,belle_sip_header_www_authenticate_get_qop_first(authenticate));
	authorization_context_set_scheme(auth_context,belle_sip_header_www_authenticate_get_scheme(authenticate));
	authorization_context_set_opaque(auth_context,belle_sip_header_www_authenticate_get_opaque(authenticate));
792
	if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(authenticate,belle_sip_header_proxy_authenticate_t)) {
793 794 795
		auth_context->is_proxy=1;
	}
}
796

797 798 799 800 801 802 803 804 805 806 807 808
static belle_sip_list_t*  belle_sip_provider_get_auth_context_by_call_id(belle_sip_provider_t *p,belle_sip_header_call_id_t* call_id) {
	belle_sip_list_t* auth_context_lst=NULL;
	belle_sip_list_t* result=NULL;
	authorization_context_t* auth_context;
	for (auth_context_lst=p->auth_contexts;auth_context_lst!=NULL;auth_context_lst=auth_context_lst->next) {
		auth_context=(authorization_context_t*)auth_context_lst->data;
		if (belle_sip_header_call_id_equals(auth_context->callid,call_id) ) {
			result=belle_sip_list_append(result,auth_context_lst->data);
		}
	}
	return result;
}
809

810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827
static void  belle_sip_provider_update_or_create_auth_context(belle_sip_provider_t *p,belle_sip_header_call_id_t* call_id,belle_sip_header_www_authenticate_t* authenticate) {
	 belle_sip_list_t* auth_context_lst =  belle_sip_provider_get_auth_context_by_call_id(p,call_id);
	 authorization_context_t* auth_context;
	 for (;auth_context_lst!=NULL;auth_context_lst=auth_context_lst->next) {
		 auth_context= (authorization_context_t*)auth_context_lst->data;
		 if (strcmp(auth_context->realm,belle_sip_header_www_authenticate_get_realm(authenticate))==0) {
			 authorization_context_fill_from_auth(auth_context,authenticate);
			 if (auth_context_lst) belle_sip_free(auth_context_lst);
			 return; /*only one realm is supposed to be found for now*/
		 }
	 }
	 /*no auth context found, creating one*/
	 auth_context=belle_sip_authorization_create(call_id);
	 authorization_context_fill_from_auth(auth_context,authenticate);
	 p->auth_contexts=belle_sip_list_append(p->auth_contexts,auth_context);
	 if (auth_context_lst) belle_sip_free(auth_context_lst);
	 return;
}
828

829
int belle_sip_provider_add_authorization(belle_sip_provider_t *p, belle_sip_request_t* request,belle_sip_response_t *resp,belle_sip_list_t** auth_infos) {
830 831 832
	belle_sip_header_call_id_t* call_id;
	belle_sip_list_t* auth_context_lst;
	belle_sip_list_t* authenticate_lst;
jehan's avatar
jehan committed
833
	belle_sip_list_t* head;
834 835 836 837 838 839 840 841 842 843
	belle_sip_header_www_authenticate_t* authenticate;
	belle_sip_header_authorization_t* authorization;

	belle_sip_header_address_t* from;
	belle_sip_auth_event_t* auth_event;
	authorization_context_t* auth_context;
	belle_sip_uri_t* from_uri;
	const char* ha1;
	char computed_ha1[33];
	int result=0;
844
	const char* request_method;
845 846 847 848 849
	/*check params*/
	if (!p || !request) {
		belle_sip_error("belle_sip_provider_add_authorization bad parameters");
		return-1;
	}
850
	request_method=belle_sip_request_get_method(request);
jehan's avatar
jehan committed
851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871
/*22 Usage of HTTP Authentication
  22.1 Framework
   While a server can legitimately challenge most SIP requests, there
   are two requests defined by this document that require special
   handling for authentication: ACK and CANCEL.
   Under an authentication scheme that uses responses to carry values
   used to compute nonces (such as Digest), some problems come up for
   any requests that take no response, including ACK.  For this reason,
   any credentials in the INVITE that were accepted by a server MUST be
   accepted by that server for the ACK.  UACs creating an ACK message
   will duplicate all of the Authorization and Proxy-Authorization
   header field values that appeared in the INVITE to which the ACK
   corresponds.  Servers MUST NOT attempt to challenge an ACK.

   Although the CANCEL method does take a response (a 2xx), servers MUST
   NOT attempt to challenge CANCEL requests since these requests cannot
   be resubmitted.  Generally, a CANCEL request SHOULD be accepted by a
   server if it comes from the same hop that sent the request being
   canceled (provided that some sort of transport or network layer
   security association, as described in Section 26.2.1, is in place).
   */
872 873 874 875 876

	if (strcmp("CANCEL",request_method)==0 || strcmp("ACK",request_method)==0) {
		belle_sip_debug("no authorization header needed for method [%s]",request_method);
		return 0;
	}
877 878
	/*get authenticates value from response*/
	if (resp) {
879
		belle_sip_list_t *it;
880 881
		call_id = belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(resp),belle_sip_header_call_id_t);
		/*searching for authentication headers*/
882
		authenticate_lst = belle_sip_list_copy(belle_sip_message_get_headers(BELLE_SIP_MESSAGE(resp),BELLE_SIP_WWW_AUTHENTICATE));
883
		/*search for proxy authenticate*/
884
		authenticate_lst=belle_sip_list_concat(authenticate_lst,belle_sip_list_copy(belle_sip_message_get_headers(BELLE_SIP_MESSAGE(resp),BELLE_SIP_PROXY_AUTHENTICATE)));
885
		/*update auth contexts with authenticate headers from response*/
886 887
		for (it=authenticate_lst;it!=NULL;it=it->next) {
			authenticate=BELLE_SIP_HEADER_WWW_AUTHENTICATE(it->data);
888 889
			belle_sip_provider_update_or_create_auth_context(p,call_id,authenticate);
		}
890
		belle_sip_list_free(authenticate_lst);
891 892 893 894 895 896
	}

	/*put authorization header if passwd found*/
	call_id = belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_call_id_t);
	from = BELLE_SIP_HEADER_ADDRESS(belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_FROM));
	from_uri = belle_sip_header_address_get_uri(from);
jehan's avatar
jehan committed
897
	if ((head=auth_context_lst = belle_sip_provider_get_auth_context_by_call_id(p,call_id))) {
898 899 900 901 902 903 904
		/*we assume there no existing auth headers*/
		for (;auth_context_lst!=NULL;auth_context_lst=auth_context_lst->next) {
			/*clear auth info*/
			auth_context=(authorization_context_t*)auth_context_lst->data;
			auth_event = belle_sip_auth_event_create(auth_context->realm,belle_sip_uri_get_user(from_uri));
			/*put data*/
			/*call listener*/
jehan's avatar
jehan committed
905
			BELLE_SIP_PROVIDER_INVOKE_LISTENERS(p->listeners,process_auth_requested,auth_event);
906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923
			if (auth_event->passwd || auth_event->ha1) {
				if (!auth_event->userid) {
					/*if no userid, username = userid*/

					belle_sip_auth_event_set_userid(auth_event,(const char*)auth_event->username);
				}
				belle_sip_message("Auth info found for [%s] realm [%s]",auth_event->userid,auth_event->realm);
				if (auth_context->is_proxy) {
					authorization=BELLE_SIP_HEADER_AUTHORIZATION(belle_sip_header_proxy_authorization_new());
				} else {
					authorization=belle_sip_header_authorization_new();
				}
				belle_sip_header_authorization_set_scheme(authorization,auth_context->scheme);
				belle_sip_header_authorization_set_realm(authorization,auth_context->realm);
				belle_sip_header_authorization_set_username(authorization,auth_event->userid);
				belle_sip_header_authorization_set_nonce(authorization,auth_context->nonce);
				belle_sip_header_authorization_set_qop(authorization,auth_context->qop);
				belle_sip_header_authorization_set_opaque(authorization,auth_context->opaque);
Simon Morlat's avatar
Simon Morlat committed
924
				belle_sip_header_authorization_set_uri(authorization,(belle_sip_uri_t*)belle_sip_request_get_uri(request));
jehan's avatar
jehan committed
925 926
				if (auth_context->qop)
					belle_sip_header_authorization_set_nonce_count(authorization,++auth_context->nonce_count);
927 928 929 930 931 932 933 934 935 936 937 938 939 940 941
				if (auth_event->ha1) {
					ha1=auth_event->ha1;
				} else {
					belle_sip_auth_helper_compute_ha1(auth_event->userid,auth_context->realm,auth_event->passwd, computed_ha1);
					ha1=computed_ha1;
				}
				if (belle_sip_auth_helper_fill_authorization(authorization
															,belle_sip_request_get_method(request)
															,ha1)) {
					belle_sip_object_unref(authorization);
				} else
					belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(authorization));
				result=1;
		} else {
			belle_sip_message("No auth info found for call id [%s]",belle_sip_header_call_id_get_call_id(call_id));
942 943 944 945 946 947 948
		}
		/*provides auth info in any cases, uasefull even if found because auth info can contains wrong password*/
		if (auth_infos) {
			/*stored to give user information on realm/username which requires authentications*/
			*auth_infos=belle_sip_list_append(*auth_infos,auth_event);
		} else {
			belle_sip_auth_event_destroy(auth_event);
949
		}
950

951
		}
jehan's avatar
jehan committed
952
		belle_sip_list_free(head);
953 954 955 956 957
	} else {
		/*nothing to do*/
	}
	return result;
}
jehan's avatar
jehan committed
958 959 960 961 962
void belle_sip_provider_set_recv_error(belle_sip_provider_t *prov, int recv_error) {
	belle_sip_list_t *lps;
	belle_sip_list_t *channels;
	for(lps=prov->lps;lps!=NULL;lps=lps->next){
		for(channels=((belle_sip_listening_point_t*)lps->data)->channels;channels!=NULL;channels=channels->next){
Simon Morlat's avatar
Simon Morlat committed
963
			((belle_sip_channel_t*)channels->data)->simulated_recv_return=recv_error;
jehan's avatar
jehan committed
964 965 966 967
			((belle_sip_source_t*)channels->data)->notify_required=(recv_error<=0);
		}
	}
}
968 969 970 971 972 973 974
void belle_sip_provider_enable_rport(belle_sip_provider_t *prov, int enable) {
	prov->rport_enabled=enable;
}

int belle_sip_provider_is_rport_enabled(belle_sip_provider_t *prov) {
	return prov->rport_enabled;
}
975 976 977 978 979 980 981 982

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;
}
983 984
void belle_sip_provider_enable_unconditional_answer(belle_sip_provider_t *prov, int enable) {
	prov->unconditional_answer_enabled=enable;
985

986
}