provider.c 18.9 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"
21 22 23 24


static void belle_sip_provider_uninit(belle_sip_provider_t *p){
	belle_sip_list_free(p->listeners);
Simon Morlat's avatar
Simon Morlat committed
25
	belle_sip_list_free_with_data(p->lps,belle_sip_object_unref);
26 27
	belle_sip_list_free_with_data(p->client_transactions,belle_sip_object_unref);
	belle_sip_list_free_with_data(p->server_transactions,belle_sip_object_unref);
28 29
}

30
static void channel_state_changed(belle_sip_channel_listener_t *obj, belle_sip_channel_t *chan, belle_sip_channel_state_t state){
31
	belle_sip_io_error_event_t ev;
jehan's avatar
jehan committed
32
	if (state == BELLE_SIP_CHANNEL_ERROR || state == BELLE_SIP_CHANNEL_DISCONNECTED) {
33
		belle_sip_provider_release_channel(ev.source,chan);
34 35
		ev.transport=belle_sip_channel_get_transport_name(chan);
		ev.source=(belle_sip_provider_t*)obj;
36 37
		ev.port=chan->peer_port;
		ev.host=chan->peer_name;
38 39
		BELLE_SIP_PROVIDER_INVOKE_LISTENERS(ev.source,process_io_error,&ev);
	}
40 41
}

Simon Morlat's avatar
Simon Morlat committed
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
static void belle_sip_provider_dispatch_request(belle_sip_provider_t* prov, belle_sip_request_t *req){
	belle_sip_server_transaction_t *t;
	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{
		belle_sip_request_event_t ev;
		ev.source=prov;
		ev.server_transaction=NULL;
		ev.dialog=NULL;
		ev.request=req;
		BELLE_SIP_PROVIDER_INVOKE_LISTENERS(prov,process_request_event,&ev);
	}
}

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
74
		event.source=prov;
Simon Morlat's avatar
Simon Morlat committed
75
		event.client_transaction=NULL;
Simon Morlat's avatar
Simon Morlat committed
76
		event.dialog=NULL;
Simon Morlat's avatar
Simon Morlat committed
77 78 79 80 81 82 83 84
		event.response=msg;
		BELLE_SIP_PROVIDER_INVOKE_LISTENERS(prov,process_response_event,&event);
	}
}

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
85
	}else{
Simon Morlat's avatar
Simon Morlat committed
86
		belle_sip_provider_dispatch_response(prov,(belle_sip_response_t*)msg);
Simon Morlat's avatar
Simon Morlat committed
87
	}
88
	belle_sip_object_unref(msg);
Simon Morlat's avatar
Simon Morlat committed
89 90
}

91 92 93
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"));
	belle_sip_parameters_set_parameter(BELLE_SIP_PARAMETERS(via),"rport",NULL);
Simon Morlat's avatar
Simon Morlat committed
94
	char token[7]="fixme";
95 96 97 98 99 100 101 102 103 104
	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
105 106
		/*FIXME: should not be set random here: but rather a hash of message invariants*/
		char *branchid=belle_sip_strdup_printf(BELLE_SIP_BRANCH_MAGIC_COOKIE ".%s",token);
107 108 109 110
		belle_sip_header_via_set_branch(via,branchid);
		belle_sip_free(branchid);
	}
}
jehan's avatar
jehan committed
111
/*
Simon Morlat's avatar
Simon Morlat committed
112 113 114 115 116 117 118
static void belle_sip_provider_read_message(belle_sip_provider_t *prov, belle_sip_channel_t *chan){
	char buffer[belle_sip_network_buffer_size];
	int err;
	err=belle_sip_channel_recv(chan,buffer,sizeof(buffer));
	if (err>0){
		belle_sip_message_t *msg;
		buffer[err]='\0';
119
		belle_sip_message("provider %p read message from %s:%i\n%s",prov,chan->peer_name,chan->peer_port,buffer);
Simon Morlat's avatar
Simon Morlat committed
120 121
		msg=belle_sip_message_parse(buffer);
		if (msg){
122
			if (belle_sip_message_is_request(msg)) fix_incoming_via(BELLE_SIP_REQUEST(msg),chan->peer);
Simon Morlat's avatar
Simon Morlat committed
123 124 125 126 127 128
			belle_sip_provider_dispatch_message(prov,msg);
		}else{
			belle_sip_error("Could not parse this message.");
		}
	}
}
jehan's avatar
jehan committed
129
*/
Simon Morlat's avatar
Simon Morlat committed
130 131
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){
132 133
		belle_sip_message_t *msg=(belle_sip_message_t*)belle_sip_object_ref(belle_sip_channel_pick_message(chan));
		belle_sip_provider_dispatch_message(BELLE_SIP_PROVIDER(obj),msg);
Simon Morlat's avatar
Simon Morlat committed
134 135 136 137
	}
	return 0;
}

138
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
139
	belle_sip_header_contact_t* contact = (belle_sip_header_contact_t*)belle_sip_message_get_header(msg,"Contact");
jehan's avatar
jehan committed
140
	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
141
	belle_sip_uri_t* contact_uri;
Simon Morlat's avatar
Simon Morlat committed
142 143 144 145 146

	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
147

Simon Morlat's avatar
Simon Morlat committed
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
	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));
		}
		if (belle_sip_uri_get_port(contact_uri) == 0 && chan->local_port!=5060) {
			belle_sip_uri_set_port(contact_uri,chan->local_port);
		}
jehan's avatar
jehan committed
163
	}
jehan's avatar
jehan committed
164 165 166 167
	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);
	}
168 169
}

170
BELLE_SIP_IMPLEMENT_INTERFACE_BEGIN(belle_sip_provider_t,belle_sip_channel_listener_t)
Simon Morlat's avatar
Simon Morlat committed
171
	channel_state_changed,
172 173
	channel_on_event,
	channel_on_sending
174 175 176 177
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
178
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
179

180
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
181
	belle_sip_provider_t *p=belle_sip_object_new(belle_sip_provider_t);
182
	p->stack=s;
jehan's avatar
jehan committed
183
	if (lp) belle_sip_provider_add_listening_point(p,lp);
184 185 186 187
	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
188 189 190 191
	if (lp == NULL) {
		belle_sip_error("Cannot add NULL lp to provider [%p]",p);
		return -1;
	}
Simon Morlat's avatar
Simon Morlat committed
192
	p->lps=belle_sip_list_append(p->lps,belle_sip_object_ref(lp));
193 194
	return 0;
}
Simon Morlat's avatar
Simon Morlat committed
195

jehan's avatar
jehan committed
196 197 198 199 200
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;
}
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215

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

216 217
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);
218 219
}

220 221
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);
222 223
}

224
belle_sip_header_call_id_t * belle_sip_provider_create_call_id(const belle_sip_provider_t *prov){
225
	belle_sip_header_call_id_t *cid=belle_sip_header_call_id_new();
226 227
	char tmp[11];
	belle_sip_header_call_id_set_call_id(cid,belle_sip_random_token(tmp,sizeof(tmp)));
228 229 230
	return cid;
}

Simon Morlat's avatar
Simon Morlat committed
231 232
belle_sip_dialog_t * belle_sip_provider_create_dialog(belle_sip_provider_t *prov, belle_sip_transaction_t *t){
	belle_sip_dialog_t *dialog=NULL;
Simon Morlat's avatar
Simon Morlat committed
233 234 235 236 237
	
	if (t->last_response){
		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
238
			return NULL;
Simon Morlat's avatar
Simon Morlat committed
239 240
		}
	}
Simon Morlat's avatar
Simon Morlat committed
241
	dialog=belle_sip_dialog_new(t);
Simon Morlat's avatar
Simon Morlat committed
242 243
	if (dialog)
		t->dialog=(belle_sip_dialog_t*)belle_sip_object_ref(dialog);
Simon Morlat's avatar
Simon Morlat committed
244 245 246
	return dialog;
}

Simon Morlat's avatar
Simon Morlat committed
247 248 249 250
/*finds an existing dialog for an outgoing or incoming request */
belle_sip_dialog_t *belle_sip_provider_find_dialog(belle_sip_provider_t *prov, belle_sip_request_t *msg, int as_uas){
	belle_sip_list_t *elem;
	belle_sip_dialog_t *dialog;
251 252
	belle_sip_header_call_id_t *call_id;
	belle_sip_header_from_t *from;
Simon Morlat's avatar
Simon Morlat committed
253 254 255 256 257
	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;
258 259 260 261 262 263 264 265
	
	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
266

267
	if (call_id==NULL || from==NULL) return NULL;
Simon Morlat's avatar
Simon Morlat committed
268 269 270

	call_id_value=belle_sip_header_call_id_get_call_id(call_id);
	from_tag=belle_sip_header_from_get_tag(from);
271
	
Simon Morlat's avatar
Simon Morlat committed
272 273 274 275 276 277 278 279 280 281 282
	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;
		if (_belle_sip_dialog_match(dialog,call_id_value,local_tag,remote_tag))
			return dialog;
	}
	return NULL;
}

Simon Morlat's avatar
Simon Morlat committed
283 284 285 286 287 288 289 290 291
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));
}

void belle_sip_provider_remove_dialog(belle_sip_provider_t *prov, belle_sip_dialog_t *dialog){
	prov->dialogs=belle_sip_list_remove(prov->dialogs,dialog);
	belle_sip_object_unref(dialog);
}

Simon Morlat's avatar
Simon Morlat committed
292
belle_sip_client_transaction_t *belle_sip_provider_create_client_transaction(belle_sip_provider_t *prov, belle_sip_request_t *req){
293
	const char *method=belle_sip_request_get_method(req);
294
	belle_sip_client_transaction_t *t;
295
	if (strcmp(method,"INVITE")==0)
296
		t=(belle_sip_client_transaction_t*)belle_sip_ict_new(prov,req);
297 298 299 300
	else if (strcmp(method,"ACK")==0){
		belle_sip_error("belle_sip_provider_create_client_transaction() cannot be used for ACK requests.");
		return NULL;
	}
301 302 303
	else t=(belle_sip_client_transaction_t*)belle_sip_nict_new(prov,req);
	t->base.dialog=belle_sip_provider_find_dialog(prov,req,FALSE);
	return t;
304 305
}

Simon Morlat's avatar
Simon Morlat committed
306
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
307
	belle_sip_server_transaction_t* t;
Simon Morlat's avatar
Simon Morlat committed
308
	if (strcmp(belle_sip_request_get_method(req),"INVITE")==0)
Simon Morlat's avatar
Simon Morlat committed
309
		t=(belle_sip_server_transaction_t*)belle_sip_ist_new(prov,req);
Simon Morlat's avatar
Simon Morlat committed
310
	else 
Simon Morlat's avatar
Simon Morlat committed
311
		t=(belle_sip_server_transaction_t*)belle_sip_nist_new(prov,req);
312
	t->base.dialog=belle_sip_provider_find_dialog(prov,req,TRUE);
Simon Morlat's avatar
Simon Morlat committed
313 314
	belle_sip_provider_add_server_transaction(prov,t);
	return t;
315 316 317 318 319 320
}

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

321 322 323 324
belle_sip_channel_t * belle_sip_provider_get_channel(belle_sip_provider_t *p, const char *name, int port, const char *transport){
	belle_sip_list_t *l;
	belle_sip_listening_point_t *candidate=NULL,*lp;
	belle_sip_channel_t *chan;
325 326 327

	if (transport==NULL) transport="UDP";
	
328 329 330 331 332 333 334 335 336 337 338
	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){
			chan=belle_sip_listening_point_get_channel(lp,name,port);
			if (chan) return chan;
			candidate=lp;
		}
	}
	if (candidate){
		chan=belle_sip_listening_point_create_channel(candidate,name,port);
		if (chan==NULL) belle_sip_error("Could not create channel to %s:%s:%i",transport,name,port);
Simon Morlat's avatar
Simon Morlat committed
339
		else belle_sip_channel_add_listener(chan,BELLE_SIP_CHANNEL_LISTENER(p));
340 341 342
		return chan;
	}
	belle_sip_error("No listening point matching for transport %s",transport);
343
	return NULL;
Simon Morlat's avatar
wip  
Simon Morlat committed
344 345
}

Simon Morlat's avatar
wip  
Simon Morlat committed
346 347 348 349
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);
}

350
void belle_sip_provider_send_request(belle_sip_provider_t *p, belle_sip_request_t *req){
351 352 353 354
	belle_sip_hop_t hop={0};
	belle_sip_channel_t *chan;
	belle_sip_stack_get_next_hop(p->stack,req,&hop);
	chan=belle_sip_provider_get_channel(p,hop.host, hop.port, hop.transport);
355 356 357
	if (chan) {
		belle_sip_channel_queue_message(chan,BELLE_SIP_MESSAGE(req));
	}
358
	belle_sip_hop_free(&hop);
359 360
}

Simon Morlat's avatar
wip  
Simon Morlat committed
361
void belle_sip_provider_send_response(belle_sip_provider_t *p, belle_sip_response_t *resp){
362 363
	belle_sip_hop_t hop;
	belle_sip_channel_t *chan;
364 365 366 367 368
	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){
		belle_sip_fatal("Generation of unique to tags for stateless responses is not implemented.");
	}
369 370 371
	belle_sip_response_get_return_hop(resp,&hop);
	chan=belle_sip_provider_get_channel(p,hop.host, hop.port, hop.transport);
	if (chan) belle_sip_channel_queue_message(chan,BELLE_SIP_MESSAGE(resp));
372
	belle_sip_hop_free(&hop);
373 374
}

375

376 377 378
/*private provider API*/

void belle_sip_provider_set_transaction_terminated(belle_sip_provider_t *p, belle_sip_transaction_t *t){
379 380 381 382 383 384 385 386
	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);
	BELLE_SIP_PROVIDER_INVOKE_LISTENERS(t->provider,process_transaction_terminated,&ev);
	if (!ev.is_server_transaction){
Simon Morlat's avatar
Simon Morlat committed
387
		belle_sip_provider_remove_client_transaction(p,(belle_sip_client_transaction_t*)t);
Simon Morlat's avatar
Simon Morlat committed
388 389
	}else{
		belle_sip_provider_remove_server_transaction(p,(belle_sip_server_transaction_t*)t);
Simon Morlat's avatar
Simon Morlat committed
390 391 392 393 394
	}
}

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
395
}
396

397 398 399 400 401 402 403 404 405 406 407 408 409
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
410 411
belle_sip_client_transaction_t * belle_sip_provider_find_matching_client_transaction(belle_sip_provider_t *prov, 
                                                                                   belle_sip_response_t *resp){
412 413 414 415 416 417 418 419 420
	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
421
	if (cseq==NULL){
422 423 424 425 426 427 428 429 430 431 432
		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
433 434
}

435
void belle_sip_provider_remove_client_transaction(belle_sip_provider_t *prov, belle_sip_client_transaction_t *t){	
Simon Morlat's avatar
Simon Morlat committed
436
	prov->client_transactions=belle_sip_list_remove(prov->client_transactions,t);
437
	belle_sip_object_unref(t);
Simon Morlat's avatar
Simon Morlat committed
438
}
Simon Morlat's avatar
Simon Morlat committed
439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491

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

struct server_transaction_matcher{
	const char *branchid;
	const char *method;
	const char *sentby;
	int is_ack;
};

static int rfc3261_server_transaction_match(const void *p_tr, const void *p_matcher){
	belle_sip_server_transaction_t *tr=(belle_sip_server_transaction_t*)p_tr;
	struct server_transaction_matcher *matcher=(struct server_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){
		if (strcmp(matcher->method,req_method)==0) return 0;
		if (matcher->is_ack && strcmp(req_method,"INVITE")==0) return 0;
	}
	return -1;
}

belle_sip_server_transaction_t * belle_sip_provider_find_matching_server_transaction(belle_sip_provider_t *prov, belle_sip_request_t *req){
	struct server_transaction_matcher matcher;
	belle_sip_header_via_t *via=(belle_sip_header_via_t*)belle_sip_message_get_header((belle_sip_message_t*)req,"via");
	belle_sip_server_transaction_t *ret=NULL;
	belle_sip_list_t *elem;
	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);
	matcher.is_ack=(strcmp(matcher.method,"ACK")==0);
	if (strncmp(matcher.branchid,BELLE_SIP_BRANCH_MAGIC_COOKIE,strlen(BELLE_SIP_BRANCH_MAGIC_COOKIE))==0){
		/*compliant to RFC3261*/
		elem=belle_sip_list_find_custom(prov->client_transactions,rfc3261_server_transaction_match,&matcher);
	}else{
		//FIXME
	}
	
	if (elem){
		ret=(belle_sip_server_transaction_t*)elem->data;
		belle_sip_message("Found transaction matching request.");
	}
	return ret;
}

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