provider.c 18.1 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
}

28
static void channel_state_changed(belle_sip_channel_listener_t *obj, belle_sip_channel_t *chan, belle_sip_channel_state_t state){
29 30 31 32
	belle_sip_io_error_event_t ev;
	if (state == BELLE_SIP_CHANNEL_ERROR) {
		ev.transport=belle_sip_channel_get_transport_name(chan);
		ev.source=(belle_sip_provider_t*)obj;
33 34
		ev.port=chan->peer_port;
		ev.host=chan->peer_name;
35 36
		BELLE_SIP_PROVIDER_INVOKE_LISTENERS(ev.source,process_io_error,&ev);
	}
37 38
}

Simon Morlat's avatar
Simon Morlat committed
39 40 41 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
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
71
		event.source=prov;
Simon Morlat's avatar
Simon Morlat committed
72
		event.client_transaction=NULL;
Simon Morlat's avatar
Simon Morlat committed
73
		event.dialog=NULL;
Simon Morlat's avatar
Simon Morlat committed
74 75 76 77 78 79 80 81
		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
82
	}else{
Simon Morlat's avatar
Simon Morlat committed
83
		belle_sip_provider_dispatch_response(prov,(belle_sip_response_t*)msg);
Simon Morlat's avatar
Simon Morlat committed
84
	}
85
	belle_sip_object_unref(msg);
Simon Morlat's avatar
Simon Morlat committed
86 87
}

88 89 90
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
91
	char token[7]="fixme";
92 93 94 95 96 97 98 99 100 101
	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
102 103
		/*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);
104 105 106 107
		belle_sip_header_via_set_branch(via,branchid);
		belle_sip_free(branchid);
	}
}
jehan's avatar
jehan committed
108
/*
Simon Morlat's avatar
Simon Morlat committed
109 110 111 112 113 114 115
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';
116
		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
117 118
		msg=belle_sip_message_parse(buffer);
		if (msg){
119
			if (belle_sip_message_is_request(msg)) fix_incoming_via(BELLE_SIP_REQUEST(msg),chan->peer);
Simon Morlat's avatar
Simon Morlat committed
120 121 122 123 124 125
			belle_sip_provider_dispatch_message(prov,msg);
		}else{
			belle_sip_error("Could not parse this message.");
		}
	}
}
jehan's avatar
jehan committed
126
*/
Simon Morlat's avatar
Simon Morlat committed
127 128
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){
jehan's avatar
jehan committed
129
		belle_sip_provider_dispatch_message(BELLE_SIP_PROVIDER(obj),belle_sip_channel_pick_message(chan));
Simon Morlat's avatar
Simon Morlat committed
130 131 132 133
	}
	return 0;
}

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

	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
143

Simon Morlat's avatar
Simon Morlat committed
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
	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
159
	}
jehan's avatar
jehan committed
160 161 162 163
	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);
	}
164 165
}

166
BELLE_SIP_IMPLEMENT_INTERFACE_BEGIN(belle_sip_provider_t,belle_sip_channel_listener_t)
Simon Morlat's avatar
Simon Morlat committed
167
	channel_state_changed,
168 169
	channel_on_event,
	channel_on_sending
170 171 172 173
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
174
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
175

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

jehan's avatar
jehan committed
192 193 194 195 196
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;
}
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211

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

212 213
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);
214 215
}

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

220
belle_sip_header_call_id_t * belle_sip_provider_create_call_id(const belle_sip_provider_t *prov){
221
	belle_sip_header_call_id_t *cid=belle_sip_header_call_id_new();
222 223
	char tmp[11];
	belle_sip_header_call_id_set_call_id(cid,belle_sip_random_token(tmp,sizeof(tmp)));
224 225 226
	return cid;
}

Simon Morlat's avatar
Simon Morlat committed
227 228
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
229 230 231 232 233 234 235 236
	
	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.");
		}
		return NULL;
	}
Simon Morlat's avatar
Simon Morlat committed
237
	dialog=belle_sip_dialog_new(t);
Simon Morlat's avatar
Simon Morlat committed
238 239
	if (dialog)
		t->dialog=(belle_sip_dialog_t*)belle_sip_object_ref(dialog);
Simon Morlat's avatar
Simon Morlat committed
240 241 242
	return dialog;
}

Simon Morlat's avatar
Simon Morlat committed
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
/*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;
	belle_sip_header_call_id_t *call_id=belle_sip_message_get_header_by_type(msg,belle_sip_header_call_id_t);
	belle_sip_header_from_t *from=belle_sip_message_get_header_by_type(msg,belle_sip_header_from_t);
	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;

	if (call_id==NULL || from==NULL || to==NULL) return NULL;

	call_id_value=belle_sip_header_call_id_get_call_id(call_id);
	from_tag=belle_sip_header_from_get_tag(from);
	to_tag=belle_sip_header_to_get_tag(to);
	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
271 272 273 274 275 276 277 278 279
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
280
belle_sip_client_transaction_t *belle_sip_provider_create_client_transaction(belle_sip_provider_t *prov, belle_sip_request_t *req){
281 282
	const char *method=belle_sip_request_get_method(req);
	if (strcmp(method,"INVITE")==0)
Simon Morlat's avatar
Simon Morlat committed
283
		return (belle_sip_client_transaction_t*)belle_sip_ict_new(prov,req);
284 285 286 287 288
	else if (strcmp(method,"ACK")==0){
		belle_sip_error("belle_sip_provider_create_client_transaction() cannot be used for ACK requests.");
		return NULL;
	}
	else return (belle_sip_client_transaction_t*)belle_sip_nict_new(prov,req);
289 290
}

Simon Morlat's avatar
Simon Morlat committed
291
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
292
	belle_sip_server_transaction_t* t;
Simon Morlat's avatar
Simon Morlat committed
293
	if (strcmp(belle_sip_request_get_method(req),"INVITE")==0)
Simon Morlat's avatar
Simon Morlat committed
294
		t=(belle_sip_server_transaction_t*)belle_sip_ist_new(prov,req);
Simon Morlat's avatar
Simon Morlat committed
295
	else 
Simon Morlat's avatar
Simon Morlat committed
296 297 298
		t=(belle_sip_server_transaction_t*)belle_sip_nist_new(prov,req);
	belle_sip_provider_add_server_transaction(prov,t);
	return t;
299 300 301 302 303 304
}

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

305 306 307 308
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;
309 310 311

	if (transport==NULL) transport="UDP";
	
312 313 314 315 316 317 318 319 320 321 322
	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
323
		else belle_sip_channel_add_listener(chan,BELLE_SIP_CHANNEL_LISTENER(p));
324 325 326
		return chan;
	}
	belle_sip_error("No listening point matching for transport %s",transport);
327
	return NULL;
Simon Morlat's avatar
wip  
Simon Morlat committed
328 329
}

330
void belle_sip_provider_send_request(belle_sip_provider_t *p, belle_sip_request_t *req){
331 332 333 334
	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);
335 336 337
	if (chan) {
		belle_sip_channel_queue_message(chan,BELLE_SIP_MESSAGE(req));
	}
338
	belle_sip_hop_free(&hop);
339 340
}

Simon Morlat's avatar
wip  
Simon Morlat committed
341
void belle_sip_provider_send_response(belle_sip_provider_t *p, belle_sip_response_t *resp){
342 343
	belle_sip_hop_t hop;
	belle_sip_channel_t *chan;
344 345 346 347 348
	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.");
	}
349 350 351
	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));
352
	belle_sip_hop_free(&hop);
353 354
}

355

356 357 358
/*private provider API*/

void belle_sip_provider_set_transaction_terminated(belle_sip_provider_t *p, belle_sip_transaction_t *t){
359 360 361 362 363 364 365 366
	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
367
		belle_sip_provider_remove_client_transaction(p,(belle_sip_client_transaction_t*)t);
Simon Morlat's avatar
Simon Morlat committed
368 369
	}else{
		belle_sip_provider_remove_server_transaction(p,(belle_sip_server_transaction_t*)t);
Simon Morlat's avatar
Simon Morlat committed
370 371 372 373 374
	}
}

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
375
}
376

377 378 379 380 381 382 383 384 385 386 387 388 389
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
390 391
belle_sip_client_transaction_t * belle_sip_provider_find_matching_client_transaction(belle_sip_provider_t *prov, 
                                                                                   belle_sip_response_t *resp){
392 393 394 395 396 397 398 399 400
	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
401
	if (cseq==NULL){
402 403 404 405 406 407 408 409 410 411 412
		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
413 414
}

415
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
416
	prov->client_transactions=belle_sip_list_remove(prov->client_transactions,t);
417
	belle_sip_object_unref(t);
Simon Morlat's avatar
Simon Morlat committed
418
}
Simon Morlat's avatar
Simon Morlat committed
419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 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

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