provider.c 15.8 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 33 34 35 36
	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;
		ev.port=chan->local_port;
		ev.host=chan->local_ip;
		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
}

jehan's avatar
jehan committed
88

Simon Morlat's avatar
Simon Morlat committed
89

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

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

	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
145 146

	/* fix the contact if empty*/
jehan's avatar
jehan committed
147 148 149 150 151 152 153 154 155 156 157 158 159
	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
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 221
belle_sip_header_call_id_t * belle_sip_provider_create_call_id(belle_sip_provider_t *prov){
	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
belle_sip_client_transaction_t *belle_sip_provider_create_client_transaction(belle_sip_provider_t *prov, belle_sip_request_t *req){
228 229
	const char *method=belle_sip_request_get_method(req);
	if (strcmp(method,"INVITE")==0)
Simon Morlat's avatar
Simon Morlat committed
230
		return (belle_sip_client_transaction_t*)belle_sip_ict_new(prov,req);
231 232 233 234 235
	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);
236 237
}

Simon Morlat's avatar
Simon Morlat committed
238
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
239
	belle_sip_server_transaction_t* t;
Simon Morlat's avatar
Simon Morlat committed
240
	if (strcmp(belle_sip_request_get_method(req),"INVITE")==0)
Simon Morlat's avatar
Simon Morlat committed
241
		t=(belle_sip_server_transaction_t*)belle_sip_ist_new(prov,req);
Simon Morlat's avatar
Simon Morlat committed
242
	else 
Simon Morlat's avatar
Simon Morlat committed
243 244 245
		t=(belle_sip_server_transaction_t*)belle_sip_nist_new(prov,req);
	belle_sip_provider_add_server_transaction(prov,t);
	return t;
246 247 248 249 250 251
}

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

252 253 254 255
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;
256 257 258

	if (transport==NULL) transport="UDP";
	
259 260 261 262 263 264 265 266 267 268 269
	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
270
		else belle_sip_channel_add_listener(chan,BELLE_SIP_CHANNEL_LISTENER(p));
271 272 273
		return chan;
	}
	belle_sip_error("No listening point matching for transport %s",transport);
274
	return NULL;
Simon Morlat's avatar
wip  
Simon Morlat committed
275 276
}

277
void belle_sip_provider_send_request(belle_sip_provider_t *p, belle_sip_request_t *req){
278 279 280 281
	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);
282 283 284
	if (chan) {
		belle_sip_channel_queue_message(chan,BELLE_SIP_MESSAGE(req));
	}
285
	belle_sip_hop_free(&hop);
286 287
}

Simon Morlat's avatar
wip  
Simon Morlat committed
288
void belle_sip_provider_send_response(belle_sip_provider_t *p, belle_sip_response_t *resp){
289 290 291 292 293
	belle_sip_hop_t hop;
	belle_sip_channel_t *chan;
	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));
294
	belle_sip_hop_free(&hop);
295 296
}

297

298 299 300
/*private provider API*/

void belle_sip_provider_set_transaction_terminated(belle_sip_provider_t *p, belle_sip_transaction_t *t){
301 302 303 304 305 306 307 308
	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
309
		belle_sip_provider_remove_client_transaction(p,(belle_sip_client_transaction_t*)t);
Simon Morlat's avatar
Simon Morlat committed
310 311
	}else{
		belle_sip_provider_remove_server_transaction(p,(belle_sip_server_transaction_t*)t);
Simon Morlat's avatar
Simon Morlat committed
312 313 314 315 316
	}
}

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
317
}
318

319 320 321 322 323 324 325 326 327 328 329 330 331
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
332 333
belle_sip_client_transaction_t * belle_sip_provider_find_matching_client_transaction(belle_sip_provider_t *prov, 
                                                                                   belle_sip_response_t *resp){
334 335 336 337 338 339 340 341 342
	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
343
	if (cseq==NULL){
344 345 346 347 348 349 350 351 352 353 354
		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
355 356
}

357
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
358
	prov->client_transactions=belle_sip_list_remove(prov->client_transactions,t);
359
	belle_sip_object_unref(t);
Simon Morlat's avatar
Simon Morlat committed
360
}
Simon Morlat's avatar
Simon Morlat committed
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413

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