provider.c 50.8 KB
Newer Older
1 2
/*
	belle-sip - SIP (RFC3261) library.
3
	Copyright (C) 2010  Belledonne Communications SARL
4

5 6 7 8
	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 2 of the License, or
	(at your option) any later version.
9

10 11 12 13
	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.
14

15 16
	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 18 19
*/

#include "belle_sip_internal.h"
jehan's avatar
jehan committed
20
#include "listeningpoint_internal.h"
Simon Morlat's avatar
Simon Morlat committed
21
#include "md5.h"
22
#include "belle-sip/message.h"
Simon Morlat's avatar
Simon Morlat committed
23

24 25 26 27 28 29 30
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;
31
	const char* user_id;
32
	const char* algorithm;
33 34 35 36 37 38 39 40 41
	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)
42
GET_SET_STRING(authorization_context,user_id)
43
GET_SET_STRING(authorization_context,algorithm)
44 45 46 47 48 49 50 51 52 53 54 55 56
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
57
	DESTROY_STRING(object,opaque);
58
	DESTROY_STRING(object,user_id);
59
	DESTROY_STRING(object,algorithm);
60 61 62
	belle_sip_object_unref(object->callid);
	belle_sip_free(object);
}
63

64 65 66 67 68 69 70 71 72 73 74 75 76
static void finalize_transaction(belle_sip_transaction_t *tr){
	belle_sip_transaction_state_t state=belle_sip_transaction_get_state(tr);
	if (state!=BELLE_SIP_TRANSACTION_TERMINATED){
		belle_sip_message("Transaction [%p] still in state [%s], will force termination.",tr,belle_sip_transaction_state_to_string(state));
		belle_sip_transaction_terminate(tr);
	}
}

static void finalize_transactions(const belle_sip_list_t *l){
	belle_sip_list_t *copy=belle_sip_list_copy(l);
	belle_sip_list_free_with_data(copy,(void (*)(void*))finalize_transaction);
}

77
static void belle_sip_provider_uninit(belle_sip_provider_t *p){
78 79 80 81
	finalize_transactions(p->client_transactions);
	p->client_transactions=NULL;
	finalize_transactions(p->server_transactions);
	p->server_transactions=NULL;
82
	p->listeners=belle_sip_list_free(p->listeners);
jehan's avatar
jehan committed
83
	p->internal_listeners=belle_sip_list_free(p->internal_listeners);
84 85 86
	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);
87 88
}

89
static void channel_state_changed(belle_sip_channel_listener_t *obj, belle_sip_channel_t *chan, belle_sip_channel_state_t state){
90
	belle_sip_io_error_event_t ev;
91
	belle_sip_provider_t* prov=BELLE_SIP_PROVIDER(obj);
jehan's avatar
jehan committed
92
	if (state == BELLE_SIP_CHANNEL_ERROR || state == BELLE_SIP_CHANNEL_DISCONNECTED) {
93
		ev.transport=belle_sip_channel_get_transport_name(chan);
94 95
		ev.port=chan->peer_port;
		ev.host=chan->peer_name;
jehan's avatar
jehan committed
96
		ev.source=BELLE_SIP_OBJECT(prov);
97
		BELLE_SIP_PROVIDER_INVOKE_LISTENERS(prov->listeners,process_io_error,&ev);
98 99
		/*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
100
		if (!chan->force_close) belle_sip_provider_release_channel(prov,chan);
101
	}
102 103
}

Simon Morlat's avatar
Simon Morlat committed
104 105
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
106
	belle_sip_request_event_t ev;
Simon Morlat's avatar
Simon Morlat committed
107 108 109 110 111 112
	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
113
		const char *method=belle_sip_request_get_method(req);
jehan's avatar
jehan committed
114
		ev.dialog=NULL;
jehan's avatar
jehan committed
115
		/* Should we limit to ACK ?  */
jehan's avatar
jehan committed
116 117
		/*Search for a dialog if exist */

118
		ev.dialog=belle_sip_provider_find_dialog_from_message(prov,(belle_sip_message_t*)req,1/*request=uas*/);
Simon Morlat's avatar
Simon Morlat committed
119 120 121 122 123 124
		if (ev.dialog){
			if (strcmp("ACK",method)==0){
				if (belle_sip_dialog_handle_ack(ev.dialog,req)==-1){
					/*absorbed ACK retransmission, ignore */
					return;
				}
125
			}else if (!belle_sip_dialog_is_authorized_transaction(ev.dialog,method)){
Simon Morlat's avatar
Simon Morlat committed
126 127 128
				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));
129 130 131
				return;
			}
		}
132 133 134 135 136
		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 {
Simon Morlat's avatar
Simon Morlat committed
137
			ev.source=(belle_sip_object_t*)prov;
138 139 140 141
			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
142 143 144
	}
}

145
static belle_sip_list_t*  belle_sip_provider_get_auth_context_by_realm_or_call_id(belle_sip_provider_t *p,belle_sip_header_call_id_t* call_id,belle_sip_uri_t *from_uri,const char* realm);
146

147 148 149 150 151 152 153
static int belle_sip_auth_context_find_by_nonce(const void* elem, const void* nonce_value){
	authorization_context_t * a = (authorization_context_t*)elem;

	return strcmp(a->nonce, (const char*)nonce_value);
}

static void belle_sip_provider_dispatch_response(belle_sip_provider_t* p, belle_sip_response_t *msg){
Simon Morlat's avatar
Simon Morlat committed
154
	belle_sip_client_transaction_t *t;
155
	t=belle_sip_provider_find_matching_client_transaction(p,msg);
156 157

	/*good opportunity to cleanup auth context if answer = 401|407|403*/
158

159 160 161 162
	switch (belle_sip_response_get_status_code(msg)) {
	case 401:
	case 403:
	case 407: {
163 164 165 166 167 168 169 170 171 172 173 174 175
		if (t!=NULL){
			const char* nonce = NULL;
			belle_sip_message_t* req = BELLE_SIP_MESSAGE(belle_sip_transaction_get_request((belle_sip_transaction_t*)t));
			belle_sip_header_authorization_t* authorization=BELLE_SIP_HEADER_AUTHORIZATION(belle_sip_message_get_header_by_type(req, belle_sip_header_proxy_authorization_t));
			if (authorization==NULL) authorization=belle_sip_message_get_header_by_type(req, belle_sip_header_authorization_t);
			if (authorization!=NULL){
				nonce = belle_sip_header_authorization_get_nonce(authorization);
				if (nonce != NULL){
					belle_sip_list_t * auth_context_with_nonce = NULL;
					while ((auth_context_with_nonce = belle_sip_list_find_custom(p->auth_contexts, belle_sip_auth_context_find_by_nonce, nonce)) != NULL){
						belle_sip_authorization_destroy(auth_context_with_nonce->data);
						p->auth_contexts = belle_sip_list_delete_link(p->auth_contexts, auth_context_with_nonce);
					}
176 177
				}
			}
178
		}
179 180
	}
	}
Simon Morlat's avatar
Simon Morlat committed
181 182 183 184 185 186 187 188 189 190 191 192
	/*
	 * 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;
193
		event.source=(belle_sip_object_t*)p;
Simon Morlat's avatar
Simon Morlat committed
194
		event.client_transaction=NULL;
Simon Morlat's avatar
Simon Morlat committed
195
		event.dialog=NULL;
Simon Morlat's avatar
Simon Morlat committed
196
		event.response=msg;
197
		BELLE_SIP_PROVIDER_INVOKE_LISTENERS(p->listeners,process_response_event,&event);
Simon Morlat's avatar
Simon Morlat committed
198 199 200
	}
}

201
void belle_sip_provider_dispatch_message(belle_sip_provider_t *prov, belle_sip_message_t *msg){
202 203 204 205 206 207

	if (TRUE
#ifndef BELLE_SIP_DONT_CHECK_HEADERS_IN_MESSAGE
			&& belle_sip_message_check_headers(msg)
#endif
	){
208 209 210 211 212
		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
213
	}else{
214 215 216 217 218 219 220
		/* 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
221
	}
222
	belle_sip_object_unref(msg);
Simon Morlat's avatar
Simon Morlat committed
223 224
}

Simon Morlat's avatar
Simon Morlat committed
225 226 227
/*
 * takes example on 16.11 of RFC3261
 */
228
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
229 230 231
	md5_state_t ctx;
	char tmp[256]={0};
	uint8_t digest[16];
232 233 234 235 236 237 238 239 240 241 242

	belle_sip_header_call_id_t* callid_hdr = belle_sip_message_get_header_by_type(msg,belle_sip_header_call_id_t);
	belle_sip_header_cseq_t*      cseq_hdr = belle_sip_message_get_header_by_type(msg,belle_sip_header_cseq_t);
	belle_sip_header_from_t*      from_hdr = belle_sip_message_get_header_by_type(msg,belle_sip_header_from_t);
	belle_sip_header_to_t*          to_hdr = belle_sip_message_get_header_by_type(msg,belle_sip_header_to_t);

	unsigned int    cseq = cseq_hdr   ? belle_sip_header_cseq_get_seq_number(cseq_hdr)   : 0;
	const char   *callid = callid_hdr ? belle_sip_header_call_id_get_call_id(callid_hdr) : "";
	const char *from_tag = from_hdr   ? belle_sip_header_from_get_tag(from_hdr)          : "";
	const char   *to_tag = to_hdr     ? belle_sip_header_to_get_tag(to_hdr)              : "";

243 244 245 246 247
	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);
248

249 250 251 252 253 254
	if (vias){
		via=(belle_sip_header_via_t*)vias->data;
		if (vias->next){
			prev_via=(belle_sip_header_via_t*)vias->next->data;
		}
	}
255

256 257 258
	if (is_request){
		requri=belle_sip_request_get_uri(BELLE_SIP_REQUEST(msg));
	}
259

260
	belle_sip_md5_init(&ctx);
261
	if (initial)
262
		belle_sip_md5_append(&ctx,(uint8_t*)initial,strlen(initial));
263
	if (requri){
264
		size_t offset=0;
Ghislain MARY's avatar
Ghislain MARY committed
265
		belle_sip_object_marshal((belle_sip_object_t*)requri,tmp,sizeof(tmp)-1,&offset);
266
		belle_sip_md5_append(&ctx,(uint8_t*)tmp,strlen(tmp));
267
	}
Simon Morlat's avatar
Simon Morlat committed
268
	if (from_tag)
269
		belle_sip_md5_append(&ctx,(uint8_t*)from_tag,strlen(from_tag));
Simon Morlat's avatar
Simon Morlat committed
270
	if (to_tag)
271 272 273
		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));
274 275
	if (is_request){
		if (prev_via){
276
			size_t offset=0;
Ghislain MARY's avatar
Ghislain MARY committed
277
			belle_sip_object_marshal((belle_sip_object_t*)prev_via,tmp,sizeof(tmp)-1,&offset);
278
			belle_sip_md5_append(&ctx,(uint8_t*)tmp,offset);
279 280 281
		}
	}else{
		if (via){
282
			size_t offset=0;
Ghislain MARY's avatar
Ghislain MARY committed
283
			belle_sip_object_marshal((belle_sip_object_t*)via,tmp,sizeof(tmp)-1,&offset);
284
			belle_sip_md5_append(&ctx,(uint8_t*)tmp,offset);
285
		}
Simon Morlat's avatar
Simon Morlat committed
286
	}
287
	belle_sip_md5_finish(&ctx,digest);
Simon Morlat's avatar
Simon Morlat committed
288 289 290
	belle_sip_octets_to_text(digest,sizeof(digest),branchid,branchid_size);
}

291 292 293 294
/*
 * RFC2543 10.1.2:
 * "Responses are mapped to requests by the matching To, From, Call-ID,
 * CSeq headers and the branch parameter of the first Via header."
295
 *
296 297 298 299
 * to-tag must not be used because an ACK will contain one while original INVITE will not.
 * Cseq's method is changed for CANCEL so we must not use it as well.
**/

300 301 302 303
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));
	uint8_t digest[16];
304 305 306 307 308 309 310
	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));
	belle_sip_header_via_t *via=belle_sip_message_get_header_by_type(req,belle_sip_header_via_t);
	const char *v_branch=belle_sip_header_via_get_branch(via);
	belle_sip_header_from_t *from=belle_sip_message_get_header_by_type(req,belle_sip_header_from_t);
	char *from_str=belle_sip_object_to_string(from);
	belle_sip_header_to_t *to=belle_sip_message_get_header_by_type(req,belle_sip_header_to_t);
	char *to_str=belle_sip_object_to_string(belle_sip_header_address_get_uri((belle_sip_header_address_t*)to));
311

312
	belle_sip_md5_init(&ctx);
313

314 315
	belle_sip_md5_append(&ctx,(uint8_t*)from_str,strlen(from_str));
	belle_sip_md5_append(&ctx,(uint8_t*)to_str,strlen(to_str));
316 317
	belle_sip_md5_append(&ctx,(uint8_t*)callid,strlen(callid));
	belle_sip_md5_append(&ctx,(uint8_t*)&cseq,sizeof(cseq));
318 319
	belle_sip_free(from_str);
	belle_sip_free(to_str);
320

321 322
	if (v_branch)
		belle_sip_md5_append(&ctx,(uint8_t*)v_branch,strlen(v_branch));
323 324 325 326 327 328

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

329 330
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"));
331
	if (p->rport_enabled) belle_sip_parameters_set_parameter(BELLE_SIP_PARAMETERS(via),"rport",NULL);
Simon Morlat's avatar
Simon Morlat committed
332

333 334 335 336
	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));
337

338
	if (belle_sip_header_via_get_branch(via)==NULL){
Simon Morlat's avatar
Simon Morlat committed
339 340 341
		/*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];
342
		compute_hash_from_invariants(msg,token,sizeof(token),NULL);
Simon Morlat's avatar
Simon Morlat committed
343
		snprintf(branchid,sizeof(branchid)-1,BELLE_SIP_BRANCH_MAGIC_COOKIE ".%s",token);
344
		belle_sip_header_via_set_branch(via,branchid);
Simon Morlat's avatar
Simon Morlat committed
345
		belle_sip_message("Computing branch id %s for message sent statelessly", branchid);
346 347
	}
}
jehan's avatar
jehan committed
348

349 350 351 352 353 354 355
static void channel_on_message_headers(belle_sip_channel_listener_t *obj, belle_sip_channel_t *chan, belle_sip_message_t *msg){
	/*not used*/
}

static void channel_on_message(belle_sip_channel_listener_t *obj, belle_sip_channel_t *chan, belle_sip_message_t *msg){
	belle_sip_object_ref(msg);
	belle_sip_provider_dispatch_message(BELLE_SIP_PROVIDER(obj),msg);
Simon Morlat's avatar
Simon Morlat committed
356
}
Simon Morlat's avatar
Simon Morlat committed
357

jehan's avatar
jehan committed
358 359 360
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);
Simon Morlat's avatar
Simon Morlat committed
361
		belle_sip_auth_event_t* auth_event = belle_sip_auth_event_create((belle_sip_object_t*)prov,NULL,NULL);
Simon Morlat's avatar
Simon Morlat committed
362
		belle_sip_tls_channel_t *tls_chan=BELLE_SIP_TLS_CHANNEL(chan);
jehan's avatar
jehan committed
363 364 365
		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
366 367
		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
368 369 370 371
		belle_sip_auth_event_destroy(auth_event);
	}
	return 0;
}
Simon Morlat's avatar
Simon Morlat committed
372

373
static void channel_on_sending(belle_sip_channel_listener_t *obj, belle_sip_channel_t *chan, belle_sip_message_t *msg){
374
	belle_sip_header_contact_t* contact;
375
	belle_sip_header_content_length_t* content_length = (belle_sip_header_content_length_t*)belle_sip_message_get_header(msg,"Content-Length");
jehan's avatar
jehan committed
376
	belle_sip_uri_t* contact_uri;
377 378 379 380
	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
381 382

	if (belle_sip_message_is_request(msg)){
383
		const belle_sip_list_t *rroutes;
Simon Morlat's avatar
Simon Morlat committed
384
		/*probably better to be in channel*/
385 386 387 388 389
		fix_outgoing_via(prov, chan, msg);

		for (rroutes=belle_sip_message_get_headers(msg,"Record-Route");rroutes!=NULL;rroutes=rroutes->next){
			belle_sip_header_record_route_t* rr=(belle_sip_header_record_route_t*)rroutes->data;
			if (belle_sip_header_record_route_get_auto_outgoing(rr)) {
Simon Morlat's avatar
Simon Morlat committed
390
				belle_sip_uri_t *rr_uri = belle_sip_channel_create_routable_uri(chan);
391 392 393
				belle_sip_header_address_set_uri((belle_sip_header_address_t*) rr, rr_uri);
			}
		}
Simon Morlat's avatar
Simon Morlat committed
394
	}
Simon Morlat's avatar
Simon Morlat committed
395

396 397 398
	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;
399

400 401 402
		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
403 404
			contact_uri = belle_sip_uri_new();
			belle_sip_header_address_set_uri((belle_sip_header_address_t*)contact,contact_uri);
405 406 407
			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
408
		}
409
		if (!belle_sip_header_contact_get_automatic(contact)) continue;
410

411 412 413 414
		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;
415
				belle_sip_header_contact_set_unknown(contact,!chan->learnt_ip_port);
416 417 418 419
			}else{
				ip=chan->local_ip;
				port=chan->local_port;
			}
Simon Morlat's avatar
Simon Morlat committed
420
		}
421

422 423 424 425 426
		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{
427 428
			if (!belle_sip_uri_is_secure(contact_uri))
				belle_sip_uri_set_transport_param(contact_uri,transport);
Simon Morlat's avatar
Simon Morlat committed
429
		}
430
		if (port!=belle_sip_listening_point_get_well_known_port(transport)) {
431
			belle_sip_uri_set_port(contact_uri,port);
432 433
		}else{
			belle_sip_uri_set_port(contact_uri,0);
Simon Morlat's avatar
Simon Morlat committed
434
		}
jehan's avatar
jehan committed
435
	}
436 437 438 439 440

/*
 * According to RFC3261, content-length is mandatory for stream based transport, but optional for datagram transport.
 * However some servers (opensips) are confused when they receive a SIP/UDP packet without Content-Length (they shouldn't).
 */
441
	if (!content_length
442 443
#ifndef BELLE_SIP_FORCE_CONTENT_LENGTH
		&& strcasecmp("udp",belle_sip_channel_get_transport_name(chan))!=0
444
#endif
445 446 447
	) {
		content_length = belle_sip_header_content_length_create(0);
		belle_sip_message_add_header(msg,(belle_sip_header_t*)content_length);
jehan's avatar
jehan committed
448
	}
449 450
}

451
BELLE_SIP_IMPLEMENT_INTERFACE_BEGIN(belle_sip_provider_t,belle_sip_channel_listener_t)
Simon Morlat's avatar
Simon Morlat committed
452
	channel_state_changed,
453 454
	channel_on_message_headers,
	channel_on_message,
jehan's avatar
jehan committed
455 456
	channel_on_sending,
	channel_on_auth_requested
457 458 459
BELLE_SIP_IMPLEMENT_INTERFACE_END

BELLE_SIP_DECLARE_IMPLEMENTED_INTERFACES_1(belle_sip_provider_t,belle_sip_channel_listener_t);
460

Simon Morlat's avatar
Simon Morlat committed
461
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
462

463
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
464
	belle_sip_provider_t *p=belle_sip_object_new(belle_sip_provider_t);
465
	p->stack=s;
466
	p->rport_enabled=1;
jehan's avatar
jehan committed
467
	if (lp) belle_sip_provider_add_listening_point(p,lp);
468 469
	return p;
}
470 471 472

/* This function is used by a proxy to set its call side record route.
 * It must be called before adding any VIA header to the message. */
473
belle_sip_uri_t *belle_sip_provider_create_inbound_record_route(belle_sip_provider_t *p, belle_sip_request_t *req) {
474 475 476
	belle_sip_uri_t* origin = belle_sip_request_extract_origin(req);
	belle_sip_hop_t *hop = belle_sip_hop_new_from_uri(origin);
	belle_sip_channel_t *inChan = belle_sip_provider_get_channel(p, hop);
Simon Morlat's avatar
Simon Morlat committed
477
	return belle_sip_channel_create_routable_uri(inChan);
478 479
}

Simon Morlat's avatar
Simon Morlat committed
480
static belle_sip_channel_t* _belle_sip_provider_find_channel_using_routable(belle_sip_provider_t *p, const belle_sip_uri_t* routable_uri) {
481 482 483 484 485 486
	const char *transport;
	belle_sip_listening_point_t *lp;
	belle_sip_list_t *elem;
	belle_sip_channel_t *chan;
	belle_sip_uri_t* chan_uri;

Simon Morlat's avatar
Simon Morlat committed
487
	if (!routable_uri) return NULL;
488

Simon Morlat's avatar
Simon Morlat committed
489
	transport = belle_sip_uri_is_secure(routable_uri) ? "TLS" : belle_sip_uri_get_transport_param(routable_uri);
490 491 492 493 494 495
	lp = belle_sip_provider_get_listening_point(p, transport);
	if (!lp) return NULL;


	for(elem=lp->channels; elem ;elem=elem->next){
		chan=(belle_sip_channel_t*)elem->data;
Simon Morlat's avatar
Simon Morlat committed
496 497 498
		chan_uri = belle_sip_channel_create_routable_uri(chan);
		if (belle_sip_uri_get_port(routable_uri) == belle_sip_uri_get_port(chan_uri) &&
			0 == strcmp(belle_sip_uri_get_host(routable_uri), belle_sip_uri_get_host(chan_uri))) {
499 500 501 502 503 504
			return chan;
		}
	}
	return NULL;
}

Simon Morlat's avatar
Simon Morlat committed
505 506 507 508 509 510
/*
 * This function is not efficient at all, REVISIT.
 * Its goal is to determine whether a routable (route or record route) matches the local provider instance.
 * In order to do that, we go through all the channels and ask them their routable uri, and see if it matches the uri passed in argument.
 * This creates a lot of temporary objects and iterates through a potentially long list of routables.
 * Some more efficient solutions could be:
511
 * 1- insert a magic cookie parameter in each routable created by the provider, so that recognition is immediate.
Simon Morlat's avatar
Simon Morlat committed
512 513 514 515 516
 *    Drawback: use of non-standard, possibly conflicting parameter.
 * 2- check the listening point's uri first (but need to match the ip address to any local ip if it is INADDR_ANY), then use belle_sip_listening_point_get_channel()
 *    to see if a channel is matching.
 *    belle_sip_listening_point_get_channel() is not optimized currently but will have to be, so at least we leverage on something that will be optimized.
**/
517
int belle_sip_provider_is_us(belle_sip_provider_t *p, belle_sip_uri_t* uri) {
Simon Morlat's avatar
Simon Morlat committed
518
	belle_sip_channel_t* chan = _belle_sip_provider_find_channel_using_routable(p, uri);
519 520
	return !!chan;
}
Simon Morlat's avatar
Simon Morlat committed
521

522

523
int belle_sip_provider_add_listening_point(belle_sip_provider_t *p, belle_sip_listening_point_t *lp){
jehan's avatar
jehan committed
524 525 526 527
	if (lp == NULL) {
		belle_sip_error("Cannot add NULL lp to provider [%p]",p);
		return -1;
	}
528
	belle_sip_listening_point_set_channel_listener(lp,BELLE_SIP_CHANNEL_LISTENER(p));
Simon Morlat's avatar
Simon Morlat committed
529
	p->lps=belle_sip_list_append(p->lps,belle_sip_object_ref(lp));
530 531
	return 0;
}
Simon Morlat's avatar
Simon Morlat committed
532

jehan's avatar
jehan committed
533 534 535 536 537
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;
}
538 539 540 541 542 543 544 545 546 547 548 549 550 551 552

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

553 554 555
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);
556
	else
557
		p->internal_listeners=belle_sip_list_append(p->internal_listeners,l);
jehan's avatar
jehan committed
558 559 560 561 562 563
}

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

564 565
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);
566 567
}

568 569
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);
570 571
}

572
belle_sip_header_call_id_t * belle_sip_provider_create_call_id(const belle_sip_provider_t *prov){
573
	belle_sip_header_call_id_t *cid=belle_sip_header_call_id_new();
574 575
	char tmp[11];
	belle_sip_header_call_id_set_call_id(cid,belle_sip_random_token(tmp,sizeof(tmp)));
576 577
	return cid;
}
578

jehan's avatar
jehan committed
579 580 581
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);
}
582

jehan's avatar
jehan committed
583
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
584
	belle_sip_dialog_t *dialog=NULL;
585

jehan's avatar
jehan committed
586
	if (check_last_resp && t->last_response){
Simon Morlat's avatar
Simon Morlat committed
587 588 589
		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
590
			return NULL;
Simon Morlat's avatar
Simon Morlat committed
591 592
		}
	}
Simon Morlat's avatar
Simon Morlat committed
593
	dialog=belle_sip_dialog_new(t);
jehan's avatar
jehan committed
594
	if (dialog) {
Simon Morlat's avatar
Simon Morlat committed
595 596
		belle_sip_transaction_set_dialog(t,dialog);
		belle_sip_provider_add_dialog(prov,dialog);
jehan's avatar
jehan committed
597
	}
Simon Morlat's avatar
Simon Morlat committed
598 599 600
	return dialog;
}

601 602 603
/*find a dialog given the call id, from-tag and to-tag*/
belle_sip_dialog_t* belle_sip_provider_find_dialog(const belle_sip_provider_t *prov, const char* call_id, const char* from_tag, const char* to_tag) {
	belle_sip_list_t* iterator;
604

605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627
	for(iterator=prov->dialogs;iterator!=NULL;iterator=iterator->next) {
		belle_sip_dialog_t* dialog=(belle_sip_dialog_t*)iterator->data;
		if (belle_sip_dialog_get_state(dialog) != BELLE_SIP_DIALOG_NULL && strcmp(belle_sip_header_call_id_get_call_id(belle_sip_dialog_get_call_id(dialog)),call_id)==0) {
			const char* target_from;
			const char* target_to;
			if (belle_sip_dialog_is_server(dialog)) {
				target_to=belle_sip_dialog_get_local_tag(dialog);
				target_from=belle_sip_dialog_get_remote_tag(dialog);
			} else {
				target_from=belle_sip_dialog_get_local_tag(dialog);
				target_to=belle_sip_dialog_get_remote_tag(dialog);
			}
			if (strcmp(from_tag,target_from)==0 && strcmp(to_tag,target_to)==0) {
				return dialog;
			}
		}
	}
	return NULL;
}

/*finds an existing dialog for an outgoing or incoming message */
belle_sip_dialog_t *belle_sip_provider_find_dialog_from_message(belle_sip_provider_t *prov, belle_sip_message_t *msg, int as_uas){
	belle_sip_dialog_t *returned_dialog=NULL,*dialog;
628 629
	belle_sip_header_call_id_t *call_id;
	belle_sip_header_from_t *from;
630
	belle_sip_header_to_t *to;
631
	belle_sip_list_t *elem;
Simon Morlat's avatar
Simon Morlat committed
632 633 634 635
	const char *from_tag;
	const char *to_tag;
	const char *call_id_value;
	const char *local_tag,*remote_tag;
636

637 638 639 640
	if (belle_sip_message_is_request(msg)){
		belle_sip_request_t *req=BELLE_SIP_REQUEST(msg);
		if (req->dialog)
			return req->dialog;
641
	}
642

643
	to=belle_sip_message_get_header_by_type(msg,belle_sip_header_to_t);
644

645 646 647 648
	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;
	}
649

650 651
	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
652

653
	if (call_id==NULL || from==NULL || (from_tag=belle_sip_header_from_get_tag(from))==NULL) return NULL;
Simon Morlat's avatar
Simon Morlat committed
654 655 656 657

	call_id_value=belle_sip_header_call_id_get_call_id(call_id);
	local_tag=as_uas ? to_tag : from_tag;
	remote_tag=as_uas ? from_tag : to_tag;
658

Simon Morlat's avatar
Simon Morlat committed
659 660
	for (elem=prov->dialogs;elem!=NULL;elem=elem->next){
		dialog=(belle_sip_dialog_t*)elem->data;
jehan's avatar
jehan committed
661 662 663 664 665 666 667
		/*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
668
	}
jehan's avatar
jehan committed
669
	return returned_dialog;
Simon Morlat's avatar
Simon Morlat committed
670 671
}

Simon Morlat's avatar
Simon Morlat committed
672 673 674 675
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
676 677 678 679 680
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
681

Simon Morlat's avatar
Simon Morlat committed
682
void belle_sip_provider_remove_dialog(belle_sip_provider_t *prov, belle_sip_dialog_t *dialog){
jehan's avatar
jehan committed
683 684 685
	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
686
	prov->dialogs=belle_sip_list_remove(prov->dialogs,dialog);
jehan's avatar
jehan committed
687 688 689 690
	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
691 692
}

Simon Morlat's avatar
Simon Morlat committed
693
belle_sip_client_transaction_t *belle_sip_provider_create_client_transaction(belle_sip_provider_t *prov, belle_sip_request_t *req){
694
	const char *method=belle_sip_request_get_method(req);
695
	belle_sip_client_transaction_t *t;
696
	belle_sip_client_transaction_t *inv_transaction;
697
	if (strcmp(method,"INVITE")==0)
698
		t=(belle_sip_client_transaction_t*)belle_sip_ict_new(prov,req);
699 700 701
	else if (strcmp(method,"ACK")==0){
		belle_sip_error("belle_sip_provider_create_client_transaction() cannot be used for ACK requests.");
		return NULL;
702 703 704 705 706 707 708 709 710 711 712
	} 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
713
				t->next_hop=(belle_sip_hop_t*)belle_sip_object_ref(inv_transaction->next_hop);
714
			} else {
Simon Morlat's avatar
Simon Morlat committed
715
				belle_sip_error ("No corresponding ict nor dest found for cancel request attached to transaction [%p]",t);
716 717
			}
		}
718
	}
719
	belle_sip_transaction_set_dialog((belle_sip_transaction_t*)t,belle_sip_provider_find_dialog_from_message(prov,(belle_sip_message_t*)req,FALSE));
720 721
	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.*/
722
	return t;
723 724
}

Simon Morlat's avatar
Simon Morlat committed
725
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
726
	belle_sip_server_transaction_t* t;
727
	if (strcmp(belle_sip_request_get_method(req),"INVITE")==0){
Simon Morlat's avatar
Simon Morlat committed
728
		t=(belle_sip_server_transaction_t*)belle_sip_ist_new(prov,req);
729 730 731
	}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;
732
	}else
Simon Morlat's avatar
Simon Morlat committed
733
		t=(belle_sip_server_transaction_t*)belle_sip_nist_new(prov,req);
734
	belle_sip_transaction_set_dialog((belle_sip_transaction_t*)t,belle_sip_provider_find_dialog_from_message(prov,(belle_sip_message_t*)req,TRUE));
Simon Morlat's avatar
Simon Morlat committed
735 736
	belle_sip_provider_add_server_transaction(prov,t);
	return t;
737 738 739 740 741 742
}

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

743
belle_sip_channel_t * belle_sip_provider_get_channel(belle_sip_provider_t *p, const belle_sip_hop_t *hop){
744 745 746
	belle_sip_list_t *l;
	belle_sip_listening_point_t *candidate=NULL,*lp;
	belle_sip_channel_t *chan;
747

jehan's avatar
jehan committed
748 749 750 751 752 753 754 755 756 757 758 759 760
	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;
761 762
		}
	}
jehan's avatar
jehan committed
763
	belle_sip_error("No listening point matching for [%s://%s:%i]",hop->transport,hop->host,hop->port);
764
	return NULL;
Simon Morlat's avatar
wip  
Simon Morlat committed
765 766
}

Simon Morlat's avatar
wip  
Simon Morlat committed
767 768 769 770
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);
}

771 772 773
void belle_sip_provider_clean_channels(belle_sip_provider_t *p){
	belle_sip_list_t *l;
	belle_sip_listening_point_t *lp;
774

775 776 777 778 779 780
	for(l=p->lps;l!=NULL;l=l->next){
		lp=(belle_sip_listening_point_t*)l->data;
		belle_sip_listening_point_clean_channels(lp);
	}
}

781
void belle_sip_provider_send_request(belle_sip_provider_t *p, belle_sip_request_t *req){
782
	belle_sip_hop_t* hop;
783
	belle_sip_channel_t *chan;
Simon Morlat's avatar
Simon Morlat committed
784
	hop=belle_sip_stack_get_next_hop(p->stack,req);
785
	chan=belle_sip_provider_get_channel(p,hop);
786 787 788
	if (chan) {
		belle_sip_channel_queue_message(chan,BELLE_SIP_MESSAGE(req));
	}
789 790
}

Simon Morlat's avatar
wip  
Simon Morlat committed
791
void belle_sip_provider_send_response(belle_sip_provider_t *p, belle_sip_response_t *resp){
jehan's avatar
jehan committed
792
	belle_sip_hop_t* hop;
793
	belle_sip_channel_t *chan;
794 795
	belle_sip_header_to_t *to=(belle_sip_header_to_t*)belle_sip_message_get_header((belle_sip_message_t*)resp,"to");

796
	if (belle_sip_response_get_status_code(resp)!=100 && to && belle_sip_header_to_get_tag(to)==NULL){
797 798 799
		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);
800
	}
Simon Morlat's avatar
Simon Morlat committed
801
	hop=belle_sip_response_get_return_hop(resp);
802 803 804 805 806
	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);
	}
807 808
}

809

810 811 812
/*private provider API*/

void belle_sip_provider_set_transaction_terminated(belle_sip_provider_t *p, belle_sip_transaction_t *t){
813
	belle_sip_transaction_terminated_event_t ev;
814

815 816 817 818
	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
819
	BELLE_SIP_PROVIDER_INVOKE_LISTENERS_FOR_TRANSACTION(t,process_transaction_terminated,&ev);
820
	if (!ev.is_server_transaction){
Simon Morlat's avatar
Simon Morlat committed
821
		belle_sip_provider_remove_client_transaction(p,(belle_sip_client_transaction_t*)t);
Simon Morlat's avatar
Simon Morlat committed
822 823
	}else{
		belle_sip_provider_remove_server_transaction(p,(belle_sip_server_transaction_t*)t);
Simon Morlat's avatar
Simon Morlat committed
824 825 826 827 828
	}
}

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
829
}
830

831 832 833 834 835 836 837 838 839 840 841 842 843
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;
}

844 845
belle_sip_client_transaction_t * belle_sip_provider_find_matching_client_transaction(belle_sip_provider_t *prov,
																				   belle_sip_response_t *resp){
846 847 848 849 850 851 852 853 854
	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
855
	if (cseq==NULL){
856 857 858 859 860 861 862 863 864 865 866
		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
867 868
}

869
void belle_sip_provider_remove_client_transaction(belle_sip_provider_t *prov, belle_sip_client_transaction_t *t){
jehan's avatar
jehan committed
870 871 872 873 874 875 876 877
	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
878
}
Simon Morlat's avatar
Simon Morlat committed
879 880 881 882 883

void belle_sip_provider_add_server_transaction(