provider.c 31.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/*
	belle-sip - SIP (RFC3261) library.
    Copyright (C) 2010  Belledonne Communications SARL

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

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

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

jehan's avatar
jehan committed
23
belle_sip_dialog_t *belle_sip_provider_find_dialog(belle_sip_provider_t *prov, belle_sip_request_t *msg, int as_uas);
24

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

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

static void belle_sip_provider_uninit(belle_sip_provider_t *p){
	belle_sip_list_free(p->listeners);
jehan's avatar
jehan committed
61
	belle_sip_list_free(p->internal_listeners);
Simon Morlat's avatar
Simon Morlat committed
62
	belle_sip_list_free_with_data(p->lps,belle_sip_object_unref);
63 64
	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);
65
	belle_sip_list_free_with_data(p->auth_contexts,(void(*)(void*))belle_sip_authorization_destroy);
66
	belle_sip_list_free_with_data(p->dialogs,belle_sip_object_unref);
67 68
}

69
static void channel_state_changed(belle_sip_channel_listener_t *obj, belle_sip_channel_t *chan, belle_sip_channel_state_t state){
70
	belle_sip_io_error_event_t ev;
jehan's avatar
jehan committed
71
	if (state == BELLE_SIP_CHANNEL_ERROR || state == BELLE_SIP_CHANNEL_DISCONNECTED) {
72
		belle_sip_provider_release_channel(ev.source,chan);
73 74
		ev.transport=belle_sip_channel_get_transport_name(chan);
		ev.source=(belle_sip_provider_t*)obj;
75 76
		ev.port=chan->peer_port;
		ev.host=chan->peer_name;
jehan's avatar
jehan committed
77
		BELLE_SIP_PROVIDER_INVOKE_LISTENERS(ev.source->listeners,process_io_error,&ev);
78
	}
79 80
}

Simon Morlat's avatar
Simon Morlat committed
81 82
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
83
	belle_sip_request_event_t ev;
Simon Morlat's avatar
Simon Morlat committed
84 85 86 87 88 89
	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{
jehan's avatar
jehan committed
90
		ev.dialog=NULL;
jehan's avatar
jehan committed
91
		/* Should we limit to ACK ?  */
jehan's avatar
jehan committed
92 93
		/*Search for a dialog if exist */

jehan's avatar
jehan committed
94
		ev.dialog=belle_sip_provider_find_dialog(prov,req,1/*request=uas*/);
95 96 97 98 99 100
		if (strcmp("ACK",belle_sip_request_get_method(req))==0 && ev.dialog){
			if (belle_sip_dialog_handle_ack(ev.dialog,req)==-1){
				/*absorbed ACK retransmission, ignore */
				return;
			}
		}
Simon Morlat's avatar
Simon Morlat committed
101 102 103
		ev.source=prov;
		ev.server_transaction=NULL;
		ev.request=req;
jehan's avatar
jehan committed
104
		BELLE_SIP_PROVIDER_INVOKE_LISTENERS(prov->listeners,process_request_event,&ev);
Simon Morlat's avatar
Simon Morlat committed
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
	}
}

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
123
		event.source=prov;
Simon Morlat's avatar
Simon Morlat committed
124
		event.client_transaction=NULL;
Simon Morlat's avatar
Simon Morlat committed
125
		event.dialog=NULL;
Simon Morlat's avatar
Simon Morlat committed
126
		event.response=msg;
jehan's avatar
jehan committed
127
		BELLE_SIP_PROVIDER_INVOKE_LISTENERS(prov->listeners,process_response_event,&event);
Simon Morlat's avatar
Simon Morlat committed
128 129 130 131 132 133
	}
}

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
134
	}else{
Simon Morlat's avatar
Simon Morlat committed
135
		belle_sip_provider_dispatch_response(prov,(belle_sip_response_t*)msg);
Simon Morlat's avatar
Simon Morlat committed
136
	}
137
	belle_sip_object_unref(msg);
Simon Morlat's avatar
Simon Morlat committed
138 139
}

Simon Morlat's avatar
Simon Morlat committed
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
/*
 * takes example on 16.11 of RFC3261
 */
static void compute_branch(belle_sip_message_t *msg, 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(msg,belle_sip_header_cseq_t));
	char tmp[256]={0};
	uint8_t digest[16];
	const char*callid=belle_sip_header_call_id_get_call_id(belle_sip_message_get_header_by_type(msg,belle_sip_header_call_id_t));
	const char *from_tag=belle_sip_header_from_get_tag(belle_sip_message_get_header_by_type(msg,belle_sip_header_from_t));
	const char *to_tag=belle_sip_header_to_get_tag(belle_sip_message_get_header_by_type(msg,belle_sip_header_to_t));
	belle_sip_header_via_t *prev_via=(belle_sip_header_via_t*)belle_sip_message_get_headers(msg,"via")->next;
	
	md5_init(&ctx);
	belle_sip_object_marshal((belle_sip_object_t*)belle_sip_request_get_uri(BELLE_SIP_REQUEST(msg)),tmp,0,sizeof(tmp)-1);
	md5_append(&ctx,(uint8_t*)tmp,strlen(tmp));
	if (from_tag)
		md5_append(&ctx,(uint8_t*)from_tag,strlen(from_tag));
	if (to_tag)
		md5_append(&ctx,(uint8_t*)to_tag,strlen(to_tag));
	md5_append(&ctx,(uint8_t*)callid,strlen(callid));
	md5_append(&ctx,(uint8_t*)&cseq,sizeof(cseq));
	if (prev_via){
		belle_sip_object_marshal((belle_sip_object_t*)prev_via,tmp,0,sizeof(tmp)-1);
		md5_append(&ctx,(uint8_t*)tmp,strlen(tmp));
	}
	md5_finish(&ctx,digest);
	belle_sip_octets_to_text(digest,sizeof(digest),branchid,branchid_size);
}

170 171 172
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
173

174 175 176 177 178 179 180 181 182 183
	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
184 185 186 187 188
		/*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];
		compute_branch(msg,token,sizeof(token));
		snprintf(branchid,sizeof(branchid)-1,BELLE_SIP_BRANCH_MAGIC_COOKIE ".%s",token);
189
		belle_sip_header_via_set_branch(via,branchid);
Simon Morlat's avatar
Simon Morlat committed
190
		belle_sip_message("Computing branch id %s for message sent statelessly", branchid);
191 192
	}
}
jehan's avatar
jehan committed
193
/*
Simon Morlat's avatar
Simon Morlat committed
194 195 196 197 198 199 200
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';
201
		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
202 203
		msg=belle_sip_message_parse(buffer);
		if (msg){
204
			if (belle_sip_message_is_request(msg)) fix_incoming_via(BELLE_SIP_REQUEST(msg),chan->peer);
Simon Morlat's avatar
Simon Morlat committed
205 206 207 208 209 210
			belle_sip_provider_dispatch_message(prov,msg);
		}else{
			belle_sip_error("Could not parse this message.");
		}
	}
}
jehan's avatar
jehan committed
211
*/
Simon Morlat's avatar
Simon Morlat committed
212 213
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){
214
		belle_sip_message_t *msg=belle_sip_channel_pick_message(chan);
215
		belle_sip_provider_dispatch_message(BELLE_SIP_PROVIDER(obj),msg);
Simon Morlat's avatar
Simon Morlat committed
216 217 218 219
	}
	return 0;
}

220
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
221
	belle_sip_header_contact_t* contact = (belle_sip_header_contact_t*)belle_sip_message_get_header(msg,"Contact");
jehan's avatar
jehan committed
222
	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
223
	belle_sip_uri_t* contact_uri;
Simon Morlat's avatar
Simon Morlat committed
224 225 226 227 228

	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
229

Simon Morlat's avatar
Simon Morlat committed
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
	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
245
	}
jehan's avatar
jehan committed
246 247 248 249
	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);
	}
250 251
}

252
BELLE_SIP_IMPLEMENT_INTERFACE_BEGIN(belle_sip_provider_t,belle_sip_channel_listener_t)
Simon Morlat's avatar
Simon Morlat committed
253
	channel_state_changed,
254 255
	channel_on_event,
	channel_on_sending
256 257 258 259
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
260
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
261

262
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
263
	belle_sip_provider_t *p=belle_sip_object_new(belle_sip_provider_t);
264
	p->stack=s;
jehan's avatar
jehan committed
265
	if (lp) belle_sip_provider_add_listening_point(p,lp);
266 267 268 269
	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
270 271 272 273
	if (lp == NULL) {
		belle_sip_error("Cannot add NULL lp to provider [%p]",p);
		return -1;
	}
jehan's avatar
jehan committed
274
	belle_sip_listener_set_channel_listener(lp,BELLE_SIP_CHANNEL_LISTENER(p));
Simon Morlat's avatar
Simon Morlat committed
275
	p->lps=belle_sip_list_append(p->lps,belle_sip_object_ref(lp));
276 277
	return 0;
}
Simon Morlat's avatar
Simon Morlat committed
278

jehan's avatar
jehan committed
279 280 281 282 283
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;
}
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298

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

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

jehan's avatar
jehan committed
299 300 301 302 303 304 305 306
void belle_sip_provider_add_internal_sip_listener(belle_sip_provider_t *p, belle_sip_listener_t *l){
	p->internal_listeners=belle_sip_list_append(p->internal_listeners,l);
}

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

307 308
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);
309 310
}

311 312
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);
313 314
}

315
belle_sip_header_call_id_t * belle_sip_provider_create_call_id(const belle_sip_provider_t *prov){
316
	belle_sip_header_call_id_t *cid=belle_sip_header_call_id_new();
317 318
	char tmp[11];
	belle_sip_header_call_id_set_call_id(cid,belle_sip_random_token(tmp,sizeof(tmp)));
319 320
	return cid;
}
321

jehan's avatar
jehan committed
322 323 324
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);
}
325

jehan's avatar
jehan committed
326
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
327
	belle_sip_dialog_t *dialog=NULL;
Simon Morlat's avatar
Simon Morlat committed
328
	
jehan's avatar
jehan committed
329
	if (check_last_resp && t->last_response){
Simon Morlat's avatar
Simon Morlat committed
330 331 332
		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
333
			return NULL;
Simon Morlat's avatar
Simon Morlat committed
334 335
		}
	}
Simon Morlat's avatar
Simon Morlat committed
336
	dialog=belle_sip_dialog_new(t);
jehan's avatar
jehan committed
337
	if (dialog) {
Simon Morlat's avatar
Simon Morlat committed
338 339
		belle_sip_transaction_set_dialog(t,dialog);
		belle_sip_provider_add_dialog(prov,dialog);
jehan's avatar
jehan committed
340
	}
Simon Morlat's avatar
Simon Morlat committed
341 342 343
	return dialog;
}

Simon Morlat's avatar
Simon Morlat committed
344 345 346 347
/*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;
jehan's avatar
jehan committed
348
	belle_sip_dialog_t *returned_dialog=NULL;
349 350
	belle_sip_header_call_id_t *call_id;
	belle_sip_header_from_t *from;
Simon Morlat's avatar
Simon Morlat committed
351 352 353 354 355
	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;
356 357 358 359 360 361 362 363
	
	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
364

365
	if (call_id==NULL || from==NULL) return NULL;
Simon Morlat's avatar
Simon Morlat committed
366 367 368

	call_id_value=belle_sip_header_call_id_get_call_id(call_id);
	from_tag=belle_sip_header_from_get_tag(from);
369
	
Simon Morlat's avatar
Simon Morlat committed
370 371 372 373 374
	local_tag=as_uas ? to_tag : from_tag;
	remote_tag=as_uas ? from_tag : to_tag;
	
	for (elem=prov->dialogs;elem!=NULL;elem=elem->next){
		dialog=(belle_sip_dialog_t*)elem->data;
jehan's avatar
jehan committed
375 376 377 378 379 380 381
		/*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
382
	}
jehan's avatar
jehan committed
383
	return returned_dialog;
Simon Morlat's avatar
Simon Morlat committed
384 385
}

Simon Morlat's avatar
Simon Morlat committed
386 387 388 389 390
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){
391 392 393
	belle_sip_dialog_terminated_event_t ev;
	ev.source=prov;
	ev.dialog=dialog;
Simon Morlat's avatar
Simon Morlat committed
394
	prov->dialogs=belle_sip_list_remove(prov->dialogs,dialog);
jehan's avatar
jehan committed
395
	BELLE_SIP_PROVIDER_INVOKE_LISTENERS(prov->listeners,process_dialog_terminated,&ev);
Simon Morlat's avatar
Simon Morlat committed
396 397 398
	belle_sip_object_unref(dialog);
}

Simon Morlat's avatar
Simon Morlat committed
399
belle_sip_client_transaction_t *belle_sip_provider_create_client_transaction(belle_sip_provider_t *prov, belle_sip_request_t *req){
400
	const char *method=belle_sip_request_get_method(req);
401
	belle_sip_client_transaction_t *t;
402
	if (strcmp(method,"INVITE")==0)
403
		t=(belle_sip_client_transaction_t*)belle_sip_ict_new(prov,req);
404 405 406 407
	else if (strcmp(method,"ACK")==0){
		belle_sip_error("belle_sip_provider_create_client_transaction() cannot be used for ACK requests.");
		return NULL;
	}
408
	else t=(belle_sip_client_transaction_t*)belle_sip_nict_new(prov,req);
Simon Morlat's avatar
Simon Morlat committed
409
	belle_sip_transaction_set_dialog((belle_sip_transaction_t*)t,belle_sip_provider_find_dialog(prov,req,FALSE));
410
	return t;
411 412
}

Simon Morlat's avatar
Simon Morlat committed
413
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
414
	belle_sip_server_transaction_t* t;
415
	if (strcmp(belle_sip_request_get_method(req),"INVITE")==0){
Simon Morlat's avatar
Simon Morlat committed
416
		t=(belle_sip_server_transaction_t*)belle_sip_ist_new(prov,req);
417 418 419 420
	}else if (strcmp(belle_sip_request_get_method(req),"ACK")==0){
		belle_sip_error("Creating a server transaction for an ACK is not a good idea, probably");
		return NULL;
	}else 
Simon Morlat's avatar
Simon Morlat committed
421
		t=(belle_sip_server_transaction_t*)belle_sip_nist_new(prov,req);
Simon Morlat's avatar
Simon Morlat committed
422
	belle_sip_transaction_set_dialog((belle_sip_transaction_t*)t,belle_sip_provider_find_dialog(prov,req,TRUE));
Simon Morlat's avatar
Simon Morlat committed
423 424
	belle_sip_provider_add_server_transaction(prov,t);
	return t;
425 426 427 428 429 430
}

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

431 432 433 434
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;
435 436 437

	if (transport==NULL) transport="UDP";
	
438 439 440 441 442 443 444 445 446 447 448 449 450 451
	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);
		return chan;
	}
	belle_sip_error("No listening point matching for transport %s",transport);
452
	return NULL;
Simon Morlat's avatar
wip  
Simon Morlat committed
453 454
}

Simon Morlat's avatar
wip  
Simon Morlat committed
455 456 457 458
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);
}

459 460 461 462 463 464 465 466 467 468
void belle_sip_provider_clean_channels(belle_sip_provider_t *p){
	belle_sip_list_t *l;
	belle_sip_listening_point_t *lp;

	for(l=p->lps;l!=NULL;l=l->next){
		lp=(belle_sip_listening_point_t*)l->data;
		belle_sip_listening_point_clean_channels(lp);
	}
}

469
void belle_sip_provider_send_request(belle_sip_provider_t *p, belle_sip_request_t *req){
470 471 472 473
	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);
474 475 476
	if (chan) {
		belle_sip_channel_queue_message(chan,BELLE_SIP_MESSAGE(req));
	}
477
	belle_sip_hop_free(&hop);
478 479
}

Simon Morlat's avatar
wip  
Simon Morlat committed
480
void belle_sip_provider_send_response(belle_sip_provider_t *p, belle_sip_response_t *resp){
481 482
	belle_sip_hop_t hop;
	belle_sip_channel_t *chan;
483 484 485 486 487
	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.");
	}
488 489 490
	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));
491
	belle_sip_hop_free(&hop);
492 493
}

494

495 496 497
/*private provider API*/

void belle_sip_provider_set_transaction_terminated(belle_sip_provider_t *p, belle_sip_transaction_t *t){
498 499 500 501 502 503
	belle_sip_transaction_terminated_event_t ev;
	
	BELLE_SIP_OBJECT_VPTR(t,belle_sip_transaction_t)->on_terminate(t);
	ev.source=t->provider;
	ev.transaction=t;
	ev.is_server_transaction=BELLE_SIP_IS_INSTANCE_OF(t,belle_sip_server_transaction_t);
jehan's avatar
jehan committed
504
	BELLE_SIP_PROVIDER_INVOKE_LISTENERS_FOR_TRANSACTION(t,process_transaction_terminated,&ev);
505
	if (!ev.is_server_transaction){
Simon Morlat's avatar
Simon Morlat committed
506
		belle_sip_provider_remove_client_transaction(p,(belle_sip_client_transaction_t*)t);
Simon Morlat's avatar
Simon Morlat committed
507 508
	}else{
		belle_sip_provider_remove_server_transaction(p,(belle_sip_server_transaction_t*)t);
Simon Morlat's avatar
Simon Morlat committed
509 510 511 512 513
	}
}

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
514
}
515

516 517 518 519 520 521 522 523 524 525 526 527 528
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
529 530
belle_sip_client_transaction_t * belle_sip_provider_find_matching_client_transaction(belle_sip_provider_t *prov, 
                                                                                   belle_sip_response_t *resp){
531 532 533 534 535 536 537 538 539
	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
540
	if (cseq==NULL){
541 542 543 544 545 546 547 548 549 550 551
		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
552 553
}

554
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
555
	prov->client_transactions=belle_sip_list_remove(prov->client_transactions,t);
556
	belle_sip_object_unref(t);
Simon Morlat's avatar
Simon Morlat committed
557
}
Simon Morlat's avatar
Simon Morlat committed
558 559 560 561 562 563 564 565 566

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;
567
	int is_ack_or_cancel;
Simon Morlat's avatar
Simon Morlat committed
568 569 570 571 572 573 574 575
};

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;
576
		if (matcher->is_ack_or_cancel && strcmp(req_method,"INVITE")==0) return 0;
Simon Morlat's avatar
Simon Morlat committed
577 578 579 580 581 582 583 584 585 586 587 588 589 590 591
	}
	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);
592
	matcher.is_ack_or_cancel=(strcmp(matcher.method,"ACK")==0 || strcmp(matcher.method,"CANCEL")==0);
Simon Morlat's avatar
Simon Morlat committed
593 594
	if (strncmp(matcher.branchid,BELLE_SIP_BRANCH_MAGIC_COOKIE,strlen(BELLE_SIP_BRANCH_MAGIC_COOKIE))==0){
		/*compliant to RFC3261*/
595
		elem=belle_sip_list_find_custom(prov->server_transactions,rfc3261_server_transaction_match,&matcher);
Simon Morlat's avatar
Simon Morlat committed
596 597 598 599 600 601 602 603 604 605 606 607 608 609 610
	}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);
}
611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626


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

628 629 630 631 632 633 634 635 636 637 638 639
static belle_sip_list_t*  belle_sip_provider_get_auth_context_by_call_id(belle_sip_provider_t *p,belle_sip_header_call_id_t* call_id) {
	belle_sip_list_t* auth_context_lst=NULL;
	belle_sip_list_t* result=NULL;
	authorization_context_t* auth_context;
	for (auth_context_lst=p->auth_contexts;auth_context_lst!=NULL;auth_context_lst=auth_context_lst->next) {
		auth_context=(authorization_context_t*)auth_context_lst->data;
		if (belle_sip_header_call_id_equals(auth_context->callid,call_id) ) {
			result=belle_sip_list_append(result,auth_context_lst->data);
		}
	}
	return result;
}
640

641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658
static void  belle_sip_provider_update_or_create_auth_context(belle_sip_provider_t *p,belle_sip_header_call_id_t* call_id,belle_sip_header_www_authenticate_t* authenticate) {
	 belle_sip_list_t* auth_context_lst =  belle_sip_provider_get_auth_context_by_call_id(p,call_id);
	 authorization_context_t* auth_context;
	 for (;auth_context_lst!=NULL;auth_context_lst=auth_context_lst->next) {
		 auth_context= (authorization_context_t*)auth_context_lst->data;
		 if (strcmp(auth_context->realm,belle_sip_header_www_authenticate_get_realm(authenticate))==0) {
			 authorization_context_fill_from_auth(auth_context,authenticate);
			 if (auth_context_lst) belle_sip_free(auth_context_lst);
			 return; /*only one realm is supposed to be found for now*/
		 }
	 }
	 /*no auth context found, creating one*/
	 auth_context=belle_sip_authorization_create(call_id);
	 authorization_context_fill_from_auth(auth_context,authenticate);
	 p->auth_contexts=belle_sip_list_append(p->auth_contexts,auth_context);
	 if (auth_context_lst) belle_sip_free(auth_context_lst);
	 return;
}
659

660
int belle_sip_provider_add_authorization(belle_sip_provider_t *p, belle_sip_request_t* request,belle_sip_response_t *resp,belle_sip_list_t** auth_infos) {
661 662 663
	belle_sip_header_call_id_t* call_id;
	belle_sip_list_t* auth_context_lst;
	belle_sip_list_t* authenticate_lst;
jehan's avatar
jehan committed
664
	belle_sip_list_t* head;
665 666 667 668 669 670 671 672 673 674
	belle_sip_header_www_authenticate_t* authenticate;
	belle_sip_header_authorization_t* authorization;

	belle_sip_header_address_t* from;
	belle_sip_auth_event_t* auth_event;
	authorization_context_t* auth_context;
	belle_sip_uri_t* from_uri;
	const char* ha1;
	char computed_ha1[33];
	int result=0;
675
	const char* request_method;
676 677 678 679 680
	/*check params*/
	if (!p || !request) {
		belle_sip_error("belle_sip_provider_add_authorization bad parameters");
		return-1;
	}
681 682 683 684 685 686
	request_method=belle_sip_request_get_method(request);

	if (strcmp("CANCEL",request_method)==0 || strcmp("ACK",request_method)==0) {
		belle_sip_debug("no authorization header needed for method [%s]",request_method);
		return 0;
	}
687 688
	/*get authenticates value from response*/
	if (resp) {
689
		belle_sip_list_t *it;
690 691
		call_id = belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(resp),belle_sip_header_call_id_t);
		/*searching for authentication headers*/
692
		authenticate_lst = belle_sip_list_copy(belle_sip_message_get_headers(BELLE_SIP_MESSAGE(resp),BELLE_SIP_WWW_AUTHENTICATE));
693
		/*search for proxy authenticate*/
694
		authenticate_lst=belle_sip_list_concat(authenticate_lst,belle_sip_list_copy(belle_sip_message_get_headers(BELLE_SIP_MESSAGE(resp),BELLE_SIP_PROXY_AUTHENTICATE)));
695
		/*update auth contexts with authenticate headers from response*/
696 697
		for (it=authenticate_lst;it!=NULL;it=it->next) {
			authenticate=BELLE_SIP_HEADER_WWW_AUTHENTICATE(it->data);
698 699
			belle_sip_provider_update_or_create_auth_context(p,call_id,authenticate);
		}
700
		belle_sip_list_free(authenticate_lst);
701 702 703 704 705 706
	}

	/*put authorization header if passwd found*/
	call_id = belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_call_id_t);
	from = BELLE_SIP_HEADER_ADDRESS(belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_FROM));
	from_uri = belle_sip_header_address_get_uri(from);
jehan's avatar
jehan committed
707
	if ((head=auth_context_lst = belle_sip_provider_get_auth_context_by_call_id(p,call_id))) {
708 709 710 711 712 713 714
		/*we assume there no existing auth headers*/
		for (;auth_context_lst!=NULL;auth_context_lst=auth_context_lst->next) {
			/*clear auth info*/
			auth_context=(authorization_context_t*)auth_context_lst->data;
			auth_event = belle_sip_auth_event_create(auth_context->realm,belle_sip_uri_get_user(from_uri));
			/*put data*/
			/*call listener*/
jehan's avatar
jehan committed
715
			BELLE_SIP_PROVIDER_INVOKE_LISTENERS(p->listeners,process_auth_requested,auth_event);
716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733
			if (auth_event->passwd || auth_event->ha1) {
				if (!auth_event->userid) {
					/*if no userid, username = userid*/

					belle_sip_auth_event_set_userid(auth_event,(const char*)auth_event->username);
				}
				belle_sip_message("Auth info found for [%s] realm [%s]",auth_event->userid,auth_event->realm);
				if (auth_context->is_proxy) {
					authorization=BELLE_SIP_HEADER_AUTHORIZATION(belle_sip_header_proxy_authorization_new());
				} else {
					authorization=belle_sip_header_authorization_new();
				}
				belle_sip_header_authorization_set_scheme(authorization,auth_context->scheme);
				belle_sip_header_authorization_set_realm(authorization,auth_context->realm);
				belle_sip_header_authorization_set_username(authorization,auth_event->userid);
				belle_sip_header_authorization_set_nonce(authorization,auth_context->nonce);
				belle_sip_header_authorization_set_qop(authorization,auth_context->qop);
				belle_sip_header_authorization_set_opaque(authorization,auth_context->opaque);
Simon Morlat's avatar
Simon Morlat committed
734
				belle_sip_header_authorization_set_uri(authorization,(belle_sip_uri_t*)belle_sip_request_get_uri(request));
jehan's avatar
jehan committed
735 736
				if (auth_context->qop)
					belle_sip_header_authorization_set_nonce_count(authorization,++auth_context->nonce_count);
737 738 739 740 741 742 743 744 745 746 747 748 749
				if (auth_event->ha1) {
					ha1=auth_event->ha1;
				} else {
					belle_sip_auth_helper_compute_ha1(auth_event->userid,auth_context->realm,auth_event->passwd, computed_ha1);
					ha1=computed_ha1;
				}
				if (belle_sip_auth_helper_fill_authorization(authorization
															,belle_sip_request_get_method(request)
															,ha1)) {
					belle_sip_object_unref(authorization);
				} else
					belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(authorization));
				result=1;
750
				belle_sip_auth_event_destroy(auth_event);
751 752
		} else {
			belle_sip_message("No auth info found for call id [%s]",belle_sip_header_call_id_get_call_id(call_id));
753 754 755 756 757 758
			if (auth_infos) {
				/*stored to give user information on realm/username which requires authentications*/
				*auth_infos=belle_sip_list_append(*auth_infos,auth_event);
			} else {
				belle_sip_auth_event_destroy(auth_event);
			}
759
		}
760

761
		}
jehan's avatar
jehan committed
762
		belle_sip_list_free(head);
763 764 765 766 767
	} else {
		/*nothing to do*/
	}
	return result;
}