provider.c 36.3 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 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
			}
			/* for notify exception
			As per RFC 3265;
			3.3.4. Dialog creation and termination

			If an initial SUBSCRIBE request is not sent on a pre-existing dialog,
			   the subscriber will wait for a response to the SUBSCRIBE request or a
			   matching NOTIFY.
			...
			...

			If an initial SUBSCRIBE is sent on a pre-existing dialog, a matching
			   200-class response or successful NOTIFY request merely creates a new
			   subscription associated with that dialog.
			   */

			else if (belle_sip_dialog_request_pending(ev.dialog)
					&& strcmp(method,"BYE")!=0
					&& strcmp(method,"NOTIFY")!=0 /**/){
Simon Morlat's avatar
Simon Morlat committed
124 125 126
				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));
127 128 129
				return;
			}
		}
Simon Morlat's avatar
Simon Morlat committed
130 131 132
		ev.source=prov;
		ev.server_transaction=NULL;
		ev.request=req;
jehan's avatar
jehan committed
133
		BELLE_SIP_PROVIDER_INVOKE_LISTENERS(prov->listeners,process_request_event,&ev);
Simon Morlat's avatar
Simon Morlat committed
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
	}
}

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
152
		event.source=prov;
Simon Morlat's avatar
Simon Morlat committed
153
		event.client_transaction=NULL;
Simon Morlat's avatar
Simon Morlat committed
154
		event.dialog=NULL;
Simon Morlat's avatar
Simon Morlat committed
155
		event.response=msg;
jehan's avatar
jehan committed
156
		BELLE_SIP_PROVIDER_INVOKE_LISTENERS(prov->listeners,process_response_event,&event);
Simon Morlat's avatar
Simon Morlat committed
157 158 159 160 161 162
	}
}

static void belle_sip_provider_dispatch_message(belle_sip_provider_t *prov, belle_sip_message_t *msg){
	if (belle_sip_message_is_request(msg)){
		belle_sip_provider_dispatch_request(prov,(belle_sip_request_t*)msg);
Simon Morlat's avatar
Simon Morlat committed
163
	}else{
Simon Morlat's avatar
Simon Morlat committed
164
		belle_sip_provider_dispatch_response(prov,(belle_sip_response_t*)msg);
Simon Morlat's avatar
Simon Morlat committed
165
	}
166
	belle_sip_object_unref(msg);
Simon Morlat's avatar
Simon Morlat committed
167 168
}

Simon Morlat's avatar
Simon Morlat committed
169 170 171
/*
 * takes example on 16.11 of RFC3261
 */
172
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
173 174 175 176 177 178 179
	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));
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
	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
196
	
197
	belle_sip_md5_init(&ctx);
198
	if (initial)
199
		belle_sip_md5_append(&ctx,(uint8_t*)initial,strlen(initial));
200
	if (requri){
201
		size_t offset=0;
Ghislain MARY's avatar
Ghislain MARY committed
202
		belle_sip_object_marshal((belle_sip_object_t*)requri,tmp,sizeof(tmp)-1,&offset);
203
		belle_sip_md5_append(&ctx,(uint8_t*)tmp,strlen(tmp));
204
	}
Simon Morlat's avatar
Simon Morlat committed
205
	if (from_tag)
206
		belle_sip_md5_append(&ctx,(uint8_t*)from_tag,strlen(from_tag));
Simon Morlat's avatar
Simon Morlat committed
207
	if (to_tag)
208 209 210
		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));
211 212
	if (is_request){
		if (prev_via){
213
			size_t offset=0;
Ghislain MARY's avatar
Ghislain MARY committed
214
			belle_sip_object_marshal((belle_sip_object_t*)prev_via,tmp,sizeof(tmp)-1,&offset);
215
			belle_sip_md5_append(&ctx,(uint8_t*)tmp,strlen(tmp));
216 217 218
		}
	}else{
		if (via){
219
			size_t offset=0;
Ghislain MARY's avatar
Ghislain MARY committed
220
			belle_sip_object_marshal((belle_sip_object_t*)via,tmp,sizeof(tmp)-1,&offset);
221
			belle_sip_md5_append(&ctx,(uint8_t*)tmp,strlen(tmp));
222
		}
Simon Morlat's avatar
Simon Morlat committed
223
	}
224
	belle_sip_md5_finish(&ctx,digest);
Simon Morlat's avatar
Simon Morlat committed
225 226 227
	belle_sip_octets_to_text(digest,sizeof(digest),branchid,branchid_size);
}

228 229
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"));
230
	if (p->rport_enabled) belle_sip_parameters_set_parameter(BELLE_SIP_PARAMETERS(via),"rport",NULL);
Simon Morlat's avatar
Simon Morlat committed
231

232 233 234 235 236 237 238 239 240 241
	if (belle_sip_header_via_get_host(via)==NULL){
		const char *local_ip;
		int local_port;
		local_ip=belle_sip_channel_get_local_address(chan,&local_port);
		belle_sip_header_via_set_host(via,local_ip);
		belle_sip_header_via_set_port(via,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));
	}
	if (belle_sip_header_via_get_branch(via)==NULL){
Simon Morlat's avatar
Simon Morlat committed
242 243 244
		/*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];
245
		compute_hash_from_invariants(msg,token,sizeof(token),NULL);
Simon Morlat's avatar
Simon Morlat committed
246
		snprintf(branchid,sizeof(branchid)-1,BELLE_SIP_BRANCH_MAGIC_COOKIE ".%s",token);
247
		belle_sip_header_via_set_branch(via,branchid);
Simon Morlat's avatar
Simon Morlat committed
248
		belle_sip_message("Computing branch id %s for message sent statelessly", branchid);
249 250
	}
}
jehan's avatar
jehan committed
251

Simon Morlat's avatar
Simon Morlat committed
252 253
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){
254
		belle_sip_message_t *msg=belle_sip_channel_pick_message(chan);
255
		belle_sip_provider_dispatch_message(BELLE_SIP_PROVIDER(obj),msg);
Simon Morlat's avatar
Simon Morlat committed
256 257 258 259
	}
	return 0;
}

260
static void channel_on_sending(belle_sip_channel_listener_t *obj, belle_sip_channel_t *chan, belle_sip_message_t *msg){
jehan's avatar
jehan committed
261
	belle_sip_header_contact_t* contact = (belle_sip_header_contact_t*)belle_sip_message_get_header(msg,"Contact");
jehan's avatar
jehan committed
262
	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
263
	belle_sip_uri_t* contact_uri;
Simon Morlat's avatar
Simon Morlat committed
264 265 266 267 268

	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
269

Simon Morlat's avatar
Simon Morlat committed
270 271 272 273 274 275 276 277 278 279 280 281
	if (contact){
		/* fix the contact if empty*/
		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);
		}
		if (!belle_sip_uri_get_host(contact_uri)) {
			belle_sip_uri_set_host(contact_uri,chan->local_ip);
		}
		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));
		}
jehan's avatar
jehan committed
282
		if (belle_sip_uri_get_port(contact_uri) <= 0 && chan->local_port!=5060) {
Simon Morlat's avatar
Simon Morlat committed
283 284
			belle_sip_uri_set_port(contact_uri,chan->local_port);
		}
285
		belle_sip_uri_fix(contact_uri);
jehan's avatar
jehan committed
286
	}
jehan's avatar
jehan committed
287 288 289 290
	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);
	}
291 292
}

293
BELLE_SIP_IMPLEMENT_INTERFACE_BEGIN(belle_sip_provider_t,belle_sip_channel_listener_t)
Simon Morlat's avatar
Simon Morlat committed
294
	channel_state_changed,
295 296
	channel_on_event,
	channel_on_sending
297 298 299 300
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
301
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
302

303
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
304
	belle_sip_provider_t *p=belle_sip_object_new(belle_sip_provider_t);
305
	p->stack=s;
306
	p->rport_enabled=1;
jehan's avatar
jehan committed
307
	if (lp) belle_sip_provider_add_listening_point(p,lp);
308 309 310 311
	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
312 313 314 315
	if (lp == NULL) {
		belle_sip_error("Cannot add NULL lp to provider [%p]",p);
		return -1;
	}
316
	belle_sip_listening_point_set_channel_listener(lp,BELLE_SIP_CHANNEL_LISTENER(p));
Simon Morlat's avatar
Simon Morlat committed
317
	p->lps=belle_sip_list_append(p->lps,belle_sip_object_ref(lp));
318 319
	return 0;
}
Simon Morlat's avatar
Simon Morlat committed
320

jehan's avatar
jehan committed
321 322 323 324 325
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;
}
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340

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;
}

jehan's avatar
jehan committed
341 342 343 344 345 346 347 348
void belle_sip_provider_add_internal_sip_listener(belle_sip_provider_t *p, belle_sip_listener_t *l){
	p->internal_listeners=belle_sip_list_append(p->internal_listeners,l);
}

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);
}

349 350
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);
351 352
}

353 354
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);
355 356
}

357
belle_sip_header_call_id_t * belle_sip_provider_create_call_id(const belle_sip_provider_t *prov){
358
	belle_sip_header_call_id_t *cid=belle_sip_header_call_id_new();
359 360
	char tmp[11];
	belle_sip_header_call_id_set_call_id(cid,belle_sip_random_token(tmp,sizeof(tmp)));
361 362
	return cid;
}
363

jehan's avatar
jehan committed
364 365 366
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);
}
367

jehan's avatar
jehan committed
368
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
369
	belle_sip_dialog_t *dialog=NULL;
Simon Morlat's avatar
Simon Morlat committed
370
	
jehan's avatar
jehan committed
371
	if (check_last_resp && t->last_response){
Simon Morlat's avatar
Simon Morlat committed
372 373 374
		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
375
			return NULL;
Simon Morlat's avatar
Simon Morlat committed
376 377
		}
	}
Simon Morlat's avatar
Simon Morlat committed
378
	dialog=belle_sip_dialog_new(t);
jehan's avatar
jehan committed
379
	if (dialog) {
Simon Morlat's avatar
Simon Morlat committed
380 381
		belle_sip_transaction_set_dialog(t,dialog);
		belle_sip_provider_add_dialog(prov,dialog);
jehan's avatar
jehan committed
382
	}
Simon Morlat's avatar
Simon Morlat committed
383 384 385
	return dialog;
}

Simon Morlat's avatar
Simon Morlat committed
386
/*finds an existing dialog for an outgoing or incoming request */
387
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
388 389
	belle_sip_list_t *elem;
	belle_sip_dialog_t *dialog;
jehan's avatar
jehan committed
390
	belle_sip_dialog_t *returned_dialog=NULL;
391 392
	belle_sip_header_call_id_t *call_id;
	belle_sip_header_from_t *from;
Simon Morlat's avatar
Simon Morlat committed
393 394 395 396 397
	belle_sip_header_to_t *to=belle_sip_message_get_header_by_type(msg,belle_sip_header_to_t);
	const char *from_tag;
	const char *to_tag;
	const char *call_id_value;
	const char *local_tag,*remote_tag;
398 399 400 401 402 403 404 405
	
	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
406

407
	if (call_id==NULL || from==NULL) return NULL;
Simon Morlat's avatar
Simon Morlat committed
408 409 410

	call_id_value=belle_sip_header_call_id_get_call_id(call_id);
	from_tag=belle_sip_header_from_get_tag(from);
411
	
Simon Morlat's avatar
Simon Morlat committed
412 413 414 415 416
	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
417 418 419 420 421 422 423
		/*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
424
	}
jehan's avatar
jehan committed
425
	return returned_dialog;
Simon Morlat's avatar
Simon Morlat committed
426 427
}

Simon Morlat's avatar
Simon Morlat committed
428 429 430 431
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
432 433 434 435 436
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
437

Simon Morlat's avatar
Simon Morlat committed
438
void belle_sip_provider_remove_dialog(belle_sip_provider_t *prov, belle_sip_dialog_t *dialog){
jehan's avatar
jehan committed
439 440 441
	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
442
	prov->dialogs=belle_sip_list_remove(prov->dialogs,dialog);
jehan's avatar
jehan committed
443 444 445 446
	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
447 448
}

Simon Morlat's avatar
Simon Morlat committed
449
belle_sip_client_transaction_t *belle_sip_provider_create_client_transaction(belle_sip_provider_t *prov, belle_sip_request_t *req){
450
	const char *method=belle_sip_request_get_method(req);
451
	belle_sip_client_transaction_t *t;
452
	belle_sip_client_transaction_t *inv_transaction;
453
	if (strcmp(method,"INVITE")==0)
454
		t=(belle_sip_client_transaction_t*)belle_sip_ict_new(prov,req);
455 456 457
	else if (strcmp(method,"ACK")==0){
		belle_sip_error("belle_sip_provider_create_client_transaction() cannot be used for ACK requests.");
		return NULL;
458 459 460 461 462 463 464 465 466 467 468
	} 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
469
				t->next_hop=(belle_sip_hop_t*)belle_sip_object_ref(inv_transaction->next_hop);
470
			} else {
Simon Morlat's avatar
Simon Morlat committed
471
				belle_sip_error ("No corresponding ict nor dest found for cancel request attached to transaction [%p]",t);
472 473
			}
		}
474
	}
475
	belle_sip_transaction_set_dialog((belle_sip_transaction_t*)t,belle_sip_provider_find_dialog_from_msg(prov,req,FALSE));
476
	return t;
477 478
}

Simon Morlat's avatar
Simon Morlat committed
479
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
480
	belle_sip_server_transaction_t* t;
481
	if (strcmp(belle_sip_request_get_method(req),"INVITE")==0){
Simon Morlat's avatar
Simon Morlat committed
482
		t=(belle_sip_server_transaction_t*)belle_sip_ist_new(prov,req);
483 484 485 486
	}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
487
		t=(belle_sip_server_transaction_t*)belle_sip_nist_new(prov,req);
488
	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
489 490
	belle_sip_provider_add_server_transaction(prov,t);
	return t;
491 492 493 494 495 496
}

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

497
belle_sip_channel_t * belle_sip_provider_get_channel(belle_sip_provider_t *p, const belle_sip_hop_t *hop){
498 499 500
	belle_sip_list_t *l;
	belle_sip_listening_point_t *candidate=NULL,*lp;
	belle_sip_channel_t *chan;
501
	const char *transport=hop->transport;
502 503 504

	if (transport==NULL) transport="UDP";
	
505 506 507
	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),transport)==0){
508
			chan=belle_sip_listening_point_get_channel(lp,hop);
509 510 511 512 513
			if (chan) return chan;
			candidate=lp;
		}
	}
	if (candidate){
514 515
		chan=belle_sip_listening_point_create_channel(candidate,hop);
		if (!chan) belle_sip_error("Could not create channel to %s://%s:%i",transport,hop->host,hop->port);
516 517 518
		return chan;
	}
	belle_sip_error("No listening point matching for transport %s",transport);
519
	return NULL;
Simon Morlat's avatar
wip  
Simon Morlat committed
520 521
}

Simon Morlat's avatar
wip  
Simon Morlat committed
522 523 524 525
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);
}

526 527 528
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
529
	
530 531 532 533 534 535
	for(l=p->lps;l!=NULL;l=l->next){
		lp=(belle_sip_listening_point_t*)l->data;
		belle_sip_listening_point_clean_channels(lp);
	}
}

536
void belle_sip_provider_send_request(belle_sip_provider_t *p, belle_sip_request_t *req){
537
	belle_sip_hop_t* hop;
538
	belle_sip_channel_t *chan;
Simon Morlat's avatar
Simon Morlat committed
539
	hop=belle_sip_stack_get_next_hop(p->stack,req);
540
	chan=belle_sip_provider_get_channel(p,hop);
541 542 543
	if (chan) {
		belle_sip_channel_queue_message(chan,BELLE_SIP_MESSAGE(req));
	}
544 545
}

Simon Morlat's avatar
wip  
Simon Morlat committed
546
void belle_sip_provider_send_response(belle_sip_provider_t *p, belle_sip_response_t *resp){
jehan's avatar
jehan committed
547
	belle_sip_hop_t* hop;
548
	belle_sip_channel_t *chan;
549 550 551
	belle_sip_header_to_t *to=(belle_sip_header_to_t*)belle_sip_message_get_header((belle_sip_message_t*)resp,"to");

	if (belle_sip_response_get_status_code(resp)!=100 && belle_sip_header_to_get_tag(to)==NULL){
552 553 554
		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);
555
	}
Simon Morlat's avatar
Simon Morlat committed
556
	hop=belle_sip_response_get_return_hop(resp);
557
	chan=belle_sip_provider_get_channel(p,hop);
558
	if (chan) belle_sip_channel_queue_message(chan,BELLE_SIP_MESSAGE(resp));
jehan's avatar
jehan committed
559
	belle_sip_object_unref(hop);
560 561
}

562

563 564 565
/*private provider API*/

void belle_sip_provider_set_transaction_terminated(belle_sip_provider_t *p, belle_sip_transaction_t *t){
566 567 568 569 570 571
	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
572
	BELLE_SIP_PROVIDER_INVOKE_LISTENERS_FOR_TRANSACTION(t,process_transaction_terminated,&ev);
573
	if (!ev.is_server_transaction){
Simon Morlat's avatar
Simon Morlat committed
574
		belle_sip_provider_remove_client_transaction(p,(belle_sip_client_transaction_t*)t);
Simon Morlat's avatar
Simon Morlat committed
575 576
	}else{
		belle_sip_provider_remove_server_transaction(p,(belle_sip_server_transaction_t*)t);
Simon Morlat's avatar
Simon Morlat committed
577 578 579 580 581
	}
}

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
582
}
583

584 585 586 587 588 589 590 591 592 593 594 595 596
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
597 598
belle_sip_client_transaction_t * belle_sip_provider_find_matching_client_transaction(belle_sip_provider_t *prov, 
                                                                                   belle_sip_response_t *resp){
599 600 601 602 603 604 605 606 607
	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
608
	if (cseq==NULL){
609 610 611 612 613 614 615 616 617 618 619
		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
620 621
}

622
void belle_sip_provider_remove_client_transaction(belle_sip_provider_t *prov, belle_sip_client_transaction_t *t){	
jehan's avatar
jehan committed
623 624 625 626 627 628 629 630
	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
631
}
Simon Morlat's avatar
Simon Morlat committed
632 633 634 635 636

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));
}

637
struct transaction_matcher{
Simon Morlat's avatar
Simon Morlat committed
638 639 640
	const char *branchid;
	const char *method;
	const char *sentby;
641
	int is_ack_or_cancel;
Simon Morlat's avatar
Simon Morlat committed
642 643
};

644 645 646 647 648
static int rfc3261_transaction_match(const void *p_tr, const void *p_matcher){
	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
649
		if (strcmp(matcher->method,req_method)==0) return 0;
650
		if (matcher->is_ack_or_cancel && strcmp(req_method,"INVITE")==0) return 0;
Simon Morlat's avatar
Simon Morlat committed
651 652 653 654
	}
	return -1;
}

655 656
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
657
	belle_sip_header_via_t *via=(belle_sip_header_via_t*)belle_sip_message_get_header((belle_sip_message_t*)req,"via");
658
	belle_sip_transaction_t *ret=NULL;
659
	belle_sip_list_t *elem=NULL;
Simon Morlat's avatar
Simon Morlat committed
660 661 662 663 664 665
	if (via==NULL){
		belle_sip_warning("Request has no via.");
		return NULL;
	}
	matcher.branchid=belle_sip_header_via_get_branch(via);
	matcher.method=belle_sip_request_get_method(req);
666
	matcher.is_ack_or_cancel=(strcmp(matcher.method,"ACK")==0 || strcmp(matcher.method,"CANCEL")==0);
Simon Morlat's avatar
Simon Morlat committed
667 668
	if (strncmp(matcher.branchid,BELLE_SIP_BRANCH_MAGIC_COOKIE,strlen(BELLE_SIP_BRANCH_MAGIC_COOKIE))==0){
		/*compliant to RFC3261*/
669
		elem=belle_sip_list_find_custom(transactions,rfc3261_transaction_match,&matcher);
Simon Morlat's avatar
Simon Morlat committed
670 671 672 673 674
	}else{
		//FIXME
	}
	
	if (elem){
675
		ret=(belle_sip_transaction_t*)elem->data;
jehan's avatar
jehan committed
676
		belle_sip_message("Found transaction [%p] matching request.",ret);
Simon Morlat's avatar
Simon Morlat committed
677 678 679
	}
	return ret;
}
680 681 682 683 684 685 686 687
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
688 689 690 691 692

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);
}
693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708


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));
	if (belle_sip_object_is_instance_of(BELLE_SIP_OBJECT(authenticate),BELLE_SIP_TYPE_ID(belle_sip_header_proxy_authenticate_t))) {
		auth_context->is_proxy=1;
	}
}
709

710 711 712 713 714 715 716 717 718 719 720 721
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;
}
722

723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740
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;
}
741

742
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) {
743 744 745
	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
746
	belle_sip_list_t* head;
747 748 749 750 751 752 753 754 755 756
	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;
757
	const char* request_method;
758 759 760 761 762
	/*check params*/
	if (!p || !request) {
		belle_sip_error("belle_sip_provider_add_authorization bad parameters");
		return-1;
	}
763
	request_method=belle_sip_request_get_method(request);
jehan's avatar
jehan committed
764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784
/*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).
   */
785 786 787 788 789

	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;
	}
790 791
	/*get authenticates value from response*/
	if (resp) {
792
		belle_sip_list_t *it;
793 794
		call_id = belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(resp),belle_sip_header_call_id_t);
		/*searching for authentication headers*/
795
		authenticate_lst = belle_sip_list_copy(belle_sip_message_get_headers(BELLE_SIP_MESSAGE(resp),BELLE_SIP_WWW_AUTHENTICATE));
796
		/*search for proxy authenticate*/
797
		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)));
798
		/*update auth contexts with authenticate headers from response*/
799 800
		for (it=authenticate_lst;it!=NULL;it=it->next) {
			authenticate=BELLE_SIP_HEADER_WWW_AUTHENTICATE(it->data);
801 802
			belle_sip_provider_update_or_create_auth_context(p,call_id,authenticate);
		}
803
		belle_sip_list_free(authenticate_lst);
804 805 806 807 808 809
	}

	/*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
810
	if ((head=auth_context_lst = belle_sip_provider_get_auth_context_by_call_id(p,call_id))) {
811 812 813 814 815 816 817
		/*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
818
			BELLE_SIP_PROVIDER_INVOKE_LISTENERS(p->listeners,process_auth_requested,auth_event);
819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836
			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
837
				belle_sip_header_authorization_set_uri(authorization,(belle_sip_uri_t*)belle_sip_request_get_uri(request));
jehan's avatar
jehan committed
838 839
				if (auth_context->qop)
					belle_sip_header_authorization_set_nonce_count(authorization,++auth_context->nonce_count);
840 841 842 843 844 845 846 847 848 849 850 851 852 853 854
				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));
855 856 857 858 859 860 861
		}
		/*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);
862
		}
863

864
		}
jehan's avatar
jehan committed
865
		belle_sip_list_free(head);
866 867 868 869 870
	} else {
		/*nothing to do*/
	}
	return result;
}
jehan's avatar
jehan committed
871 872 873 874 875
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
876
			((belle_sip_channel_t*)channels->data)->simulated_recv_return=recv_error;
jehan's avatar
jehan committed
877 878 879 880
			((belle_sip_source_t*)channels->data)->notify_required=(recv_error<=0);
		}
	}
}
881 882 883 884 885 886 887
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;
}