transaction.c 28.5 KB
Newer Older
1 2 3 4 5 6
/*
	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
7
    the Free Software Foundation, either version 2 of the License, or
8 9 10 11 12 13 14 15 16 17 18 19 20
    (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"

21 22 23 24 25 26 27 28 29 30 31 32
const char *belle_sip_transaction_state_to_string(belle_sip_transaction_state_t state){
	switch(state){
		case BELLE_SIP_TRANSACTION_INIT:
			return "INIT";
		case BELLE_SIP_TRANSACTION_TRYING:
			return "TRYING";
		case BELLE_SIP_TRANSACTION_CALLING:
			return "CALLING";
		case BELLE_SIP_TRANSACTION_COMPLETED:
			return "COMPLETED";
		case BELLE_SIP_TRANSACTION_CONFIRMED:
			return "CONFIRMED";
33 34
		case BELLE_SIP_TRANSACTION_ACCEPTED:
			return "ACCEPTED";
35 36 37 38 39 40 41 42 43
		case BELLE_SIP_TRANSACTION_PROCEEDING:
			return "PROCEEDING";
		case BELLE_SIP_TRANSACTION_TERMINATED:
			return "TERMINATED";
	}
	belle_sip_fatal("Invalid transaction state.");
	return "INVALID";
}

jehan's avatar
jehan committed
44
void belle_sip_transaction_set_state(belle_sip_transaction_t *t, belle_sip_transaction_state_t state) {
Simon Morlat's avatar
Simon Morlat committed
45 46 47 48 49 50
	belle_sip_message("Changing [%s] [%s] transaction [%p], from state [%s] to [%s]",
				BELLE_SIP_OBJECT_IS_INSTANCE_OF(t,belle_sip_client_transaction_t) ? "client" : "server",
				belle_sip_request_get_method(t->request),
				t,
				belle_sip_transaction_state_to_string(t->state),
				belle_sip_transaction_state_to_string(state));
jehan's avatar
jehan committed
51 52
	t->state=state;
}
53 54 55 56 57

BELLESIP_EXPORT const char *belle_sip_transaction_get_method(const belle_sip_transaction_t *t){
	return belle_sip_request_get_method(t->request);
}

58
static void belle_sip_transaction_init(belle_sip_transaction_t *t, belle_sip_provider_t *prov, belle_sip_request_t *req){
Simon Morlat's avatar
Simon Morlat committed
59
	t->request=(belle_sip_request_t*)belle_sip_object_ref(req);
60 61 62 63 64
	t->provider=prov;
}

static void transaction_destroy(belle_sip_transaction_t *t){
	if (t->request) belle_sip_object_unref(t->request);
65
	if (t->last_response) belle_sip_object_unref(t->last_response);
Simon Morlat's avatar
Simon Morlat committed
66
	if (t->channel) belle_sip_object_unref(t->channel);
67
	if (t->branch_id) belle_sip_free(t->branch_id);
68
	belle_sip_transaction_set_dialog(t,NULL);
69
	belle_sip_message("Transaction [%p] deleted",t);
jehan's avatar
jehan committed
70

71
}
72

73 74 75 76 77 78 79 80
static void notify_timeout(belle_sip_transaction_t *t){
	belle_sip_timeout_event_t ev;
	ev.source=(belle_sip_object_t*)t->provider;
	ev.transaction=t;
	ev.is_server_transaction=BELLE_SIP_OBJECT_IS_INSTANCE_OF(t,belle_sip_server_transaction_t);
	BELLE_SIP_PROVIDER_INVOKE_LISTENERS_FOR_TRANSACTION(t,process_timeout,&ev);
}

81 82 83 84 85
static int server_transaction_on_call_repair_timer(belle_sip_transaction_t *t) {
	belle_sip_server_transaction_send_response(BELLE_SIP_SERVER_TRANSACTION(t), belle_sip_response_create_from_request(t->request, 503));
	return BELLE_SIP_STOP;
}

86 87 88 89 90 91
static int client_transaction_on_call_repair_timer(belle_sip_transaction_t *t) {
	belle_sip_transaction_terminate(t);
	belle_sip_object_unref(t);
	return BELLE_SIP_STOP;
}

92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
static void on_channel_state_changed(belle_sip_channel_listener_t *l, belle_sip_channel_t *chan, belle_sip_channel_state_t state){
	belle_sip_transaction_t *t=(belle_sip_transaction_t*)l;
	belle_sip_io_error_event_t ev;
	belle_sip_transaction_state_t tr_state=belle_sip_transaction_get_state((belle_sip_transaction_t*)t);

	belle_sip_message("transaction [%p] channel state changed to [%s]"
						,t
						,belle_sip_channel_state_to_string(state));
	switch(state){
		case BELLE_SIP_CHANNEL_READY:
			if (tr_state==BELLE_SIP_TRANSACTION_INIT && BELLE_SIP_OBJECT_IS_INSTANCE_OF(t,belle_sip_client_transaction_t) ){
				belle_sip_client_transaction_t *ct = (belle_sip_client_transaction_t*) t;
				BELLE_SIP_OBJECT_VPTR(ct,belle_sip_client_transaction_t)->send_request(ct);
			}
		break;
		case BELLE_SIP_CHANNEL_DISCONNECTED:
		case BELLE_SIP_CHANNEL_ERROR:
109
			belle_sip_object_ref(t);  /*take a ref in the case where the app calls belle_sip_transaction_terminate() within the listener*/
110 111 112 113 114 115 116 117 118 119 120 121 122
			ev.transport=belle_sip_channel_get_transport_name(chan);
			ev.source=BELLE_SIP_OBJECT(t);
			ev.port=chan->peer_port;
			ev.host=chan->peer_name;
			if ( tr_state!=BELLE_SIP_TRANSACTION_COMPLETED
				&& tr_state!=BELLE_SIP_TRANSACTION_CONFIRMED
				&& tr_state!=BELLE_SIP_TRANSACTION_ACCEPTED
				&& tr_state!=BELLE_SIP_TRANSACTION_TERMINATED) {
				BELLE_SIP_PROVIDER_INVOKE_LISTENERS_FOR_TRANSACTION(((belle_sip_transaction_t*)t),process_io_error,&ev);
			}
			if (t->timed_out)
				notify_timeout((belle_sip_transaction_t*)t);

123 124 125 126 127 128 129 130
			if (!t->timed_out && BELLE_SIP_OBJECT_IS_INSTANCE_OF(t, belle_sip_server_transaction_t)) {
				const belle_sip_timer_config_t *cfg = belle_sip_transaction_get_timer_config(t);
				t->call_repair_timer = belle_sip_timeout_source_new((belle_sip_source_func_t)server_transaction_on_call_repair_timer, t, 32 * cfg->T1);
				belle_sip_transaction_start_timer(t, t->call_repair_timer);
			} else if (!t->timed_out && BELLE_SIP_OBJECT_IS_INSTANCE_OF(t, belle_sip_client_transaction_t)) {
				const belle_sip_timer_config_t *cfg = belle_sip_transaction_get_timer_config(t);
				t->call_repair_timer = belle_sip_timeout_source_new((belle_sip_source_func_t)client_transaction_on_call_repair_timer, t, 32 * cfg->T1);
				belle_sip_transaction_start_timer(t, t->call_repair_timer);
131 132 133 134 135 136
			} else {
				belle_sip_transaction_terminate(t);
				belle_sip_object_unref(t);
			}
			belle_sip_object_unref(((belle_sip_transaction_t*)t)->channel);
			((belle_sip_transaction_t*)t)->channel = NULL;
137 138 139 140 141 142 143 144 145 146 147 148 149 150
		break;
		default:
			/*ignored*/
		break;
	}
}

BELLE_SIP_IMPLEMENT_INTERFACE_BEGIN(belle_sip_transaction_t,belle_sip_channel_listener_t)
on_channel_state_changed,
NULL,
NULL
BELLE_SIP_IMPLEMENT_INTERFACE_END

BELLE_SIP_DECLARE_IMPLEMENTED_INTERFACES_1(belle_sip_transaction_t, belle_sip_channel_listener_t);
Simon Morlat's avatar
Simon Morlat committed
151

152
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_transaction_t)
Simon Morlat's avatar
Simon Morlat committed
153
	{
Simon Morlat's avatar
Simon Morlat committed
154 155 156
		BELLE_SIP_VPTR_INIT(belle_sip_transaction_t,belle_sip_object_t,FALSE),
		(belle_sip_object_destroy_t) transaction_destroy,
		NULL,/*no clone*/
157
		NULL,/*no marshal*/
Simon Morlat's avatar
Simon Morlat committed
158 159
	},
	NULL /*on_terminate*/
160
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END
Simon Morlat's avatar
Simon Morlat committed
161

162
void *belle_sip_transaction_get_application_data_internal(const belle_sip_transaction_t *t){
163 164 165
	return t->appdata;
}

166 167 168 169 170 171 172 173 174
void *belle_sip_transaction_get_application_data(const belle_sip_transaction_t *t){
	if (t->is_internal) {
		belle_sip_error("belle_sip_transaction_get_application_data should not be used on internal transaction [%p]",t);
		return NULL;
	} else {
		return belle_sip_transaction_get_application_data_internal(t);
	};
}

175 176 177 178 179 180 181 182 183 184 185
void belle_sip_transaction_set_application_data(belle_sip_transaction_t *t, void *data){
	t->appdata=data;
}

const char *belle_sip_transaction_get_branch_id(const belle_sip_transaction_t *t){
	return t->branch_id;
}

belle_sip_transaction_state_t belle_sip_transaction_get_state(const belle_sip_transaction_t *t){
	return t->state;
}
186

jehan's avatar
jehan committed
187 188 189 190 191 192 193 194 195 196 197
int belle_sip_transaction_state_is_transient(const belle_sip_transaction_state_t state) {
	switch(state){
		case BELLE_SIP_TRANSACTION_INIT:
		case BELLE_SIP_TRANSACTION_TRYING:
		case BELLE_SIP_TRANSACTION_CALLING:
		case BELLE_SIP_TRANSACTION_PROCEEDING:
			return 1;
		default:
			return 0;
	}
}
198

199
void belle_sip_transaction_terminate(belle_sip_transaction_t *t){
200
	if (belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(t))!=BELLE_SIP_TRANSACTION_TERMINATED) {
201
		int is_client=BELLE_SIP_OBJECT_IS_INSTANCE_OF(t,belle_sip_client_transaction_t);
202
		belle_sip_transaction_set_state(t,BELLE_SIP_TRANSACTION_TERMINATED);
203 204 205 206 207 208
		if (t->dialog && (!t->last_response || belle_sip_response_get_status_code(t->last_response)<200)){
			/*inform the dialog if a transaction terminates without final response.*/
			belle_sip_dialog_update(t->dialog,t,!is_client);
		}
		belle_sip_message("%s%s %s transaction [%p] terminated"	,is_client ? "Client":"Server"
									,t->is_internal ? " internal":""
209 210 211
									,belle_sip_request_get_method(belle_sip_transaction_get_request(t))
									,t);
		BELLE_SIP_OBJECT_VPTR(t,belle_sip_transaction_t)->on_terminate(t);
212
		belle_sip_provider_set_transaction_terminated(t->provider,t);
213
	}
214 215 216 217 218
	if (t->call_repair_timer) {
		belle_sip_transaction_stop_timer(t, t->call_repair_timer);
		belle_sip_object_unref(t->call_repair_timer);
		t->call_repair_timer = NULL;
	}
219 220
}

jehan's avatar
jehan committed
221
belle_sip_request_t *belle_sip_transaction_get_request(const belle_sip_transaction_t *t){
222 223
	return t->request;
}
224 225 226
belle_sip_response_t *belle_sip_transaction_get_response(const belle_sip_transaction_t *t) {
	return t->last_response;
}
Simon Morlat's avatar
Simon Morlat committed
227 228

void belle_sip_transaction_notify_timeout(belle_sip_transaction_t *t){
229
	/*report the channel as possibly dead. If an alternate IP can be tryied, the channel will notify us with the RETRY state.
Simon Morlat's avatar
Simon Morlat committed
230
	 * Otherwise it will report the error.
231
	 * We limit this dead channel reporting to REGISTER transactions, who are unlikely to be unresponded.
Simon Morlat's avatar
Simon Morlat committed
232
	**/
233
	belle_sip_object_ref(t);  /*take a ref in the case where the app calls belle_sip_transaction_terminate() within the timeout listener*/
234 235 236 237 238
	if (strcmp(belle_sip_request_get_method(t->request),"REGISTER")==0){
		if ( belle_sip_channel_notify_timeout(t->channel)==TRUE){
			belle_sip_warning("Transaction [%p] reporting timeout, reporting to channel.",t);
			t->timed_out=TRUE;
		}
239 240 241 242
	}else {
		notify_timeout(t);
		belle_sip_transaction_terminate(t);
	}
243
	belle_sip_object_unref(t);
Simon Morlat's avatar
Simon Morlat committed
244 245
}

jehan's avatar
jehan committed
246 247
belle_sip_dialog_t*  belle_sip_transaction_get_dialog(const belle_sip_transaction_t *t) {
	return t->dialog;
Simon Morlat's avatar
Simon Morlat committed
248 249
}

250 251 252 253 254
static void belle_sip_transaction_reset_dialog(belle_sip_transaction_t *tr, belle_sip_dialog_t *dialog_disapeearing){
	if (tr->dialog!=dialog_disapeearing) belle_sip_error("belle_sip_transaction_reset_dialog(): inconsistency.");
	tr->dialog=NULL;
}

Simon Morlat's avatar
Simon Morlat committed
255
void belle_sip_transaction_set_dialog(belle_sip_transaction_t *t, belle_sip_dialog_t *dialog){
256
	if (t->dialog==dialog) return;
257 258
	if (dialog) belle_sip_object_weak_ref(dialog,(belle_sip_object_destroy_notify_t)belle_sip_transaction_reset_dialog,t);
	if (t->dialog) belle_sip_object_weak_unref(t->dialog,(belle_sip_object_destroy_notify_t)belle_sip_transaction_reset_dialog,t);
Simon Morlat's avatar
Simon Morlat committed
259 260 261
	t->dialog=dialog;
}

262
/*
Simon Morlat's avatar
Simon Morlat committed
263 264
 * Server transaction
 */
265

266 267 268
static void server_transaction_destroy(belle_sip_server_transaction_t *t){
}

Simon Morlat's avatar
Simon Morlat committed
269

270
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_server_transaction_t);
271
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_server_transaction_t)
Simon Morlat's avatar
Simon Morlat committed
272
	{
Simon Morlat's avatar
Simon Morlat committed
273 274 275 276 277
		{
			BELLE_SIP_VPTR_INIT(belle_sip_server_transaction_t,belle_sip_transaction_t,FALSE),
			(belle_sip_object_destroy_t) server_transaction_destroy,
			NULL,
			NULL
Simon Morlat's avatar
Simon Morlat committed
278 279 280
		},
		NULL
	}
281
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END
Simon Morlat's avatar
Simon Morlat committed
282

283
void belle_sip_server_transaction_init(belle_sip_server_transaction_t *t, belle_sip_provider_t *prov,belle_sip_request_t *req){
284
	const char *branch;
285
	belle_sip_header_via_t *via=BELLE_SIP_HEADER_VIA(belle_sip_message_get_header((belle_sip_message_t*)req,"via"));
286
	branch=belle_sip_header_via_get_branch(via);
287
	if (branch==NULL || strncmp(branch,BELLE_SIP_BRANCH_MAGIC_COOKIE,strlen(BELLE_SIP_BRANCH_MAGIC_COOKIE))!=0){
288
		branch=req->rfc2543_branch;
289
		if (branch==NULL) belle_sip_fatal("No computed branch for RFC2543 style of message, this should never happen.");
290 291
	}
	t->base.branch_id=belle_sip_strdup(branch);
292
	belle_sip_transaction_init((belle_sip_transaction_t*)t,prov,req);
293
	belle_sip_random_token(t->to_tag,sizeof(t->to_tag));
294 295
}

Simon Morlat's avatar
Simon Morlat committed
296
void belle_sip_server_transaction_send_response(belle_sip_server_transaction_t *t, belle_sip_response_t *resp){
297
	belle_sip_transaction_t *base=(belle_sip_transaction_t*)t;
298
	belle_sip_header_to_t *to=(belle_sip_header_to_t*)belle_sip_message_get_header((belle_sip_message_t*)resp,"to");
Simon Morlat's avatar
Simon Morlat committed
299
	belle_sip_dialog_t *dialog=base->dialog;
Simon Morlat's avatar
Simon Morlat committed
300
	int status_code;
301

302
	belle_sip_object_ref(resp);
303
	if (!base->last_response || !base->channel){
jehan's avatar
jehan committed
304
		belle_sip_hop_t* hop=belle_sip_response_get_return_hop(resp);
305
		base->channel=belle_sip_provider_get_channel(base->provider,hop);
jehan's avatar
jehan committed
306
		belle_sip_object_unref(hop);
307 308 309 310 311
		if (!base->channel){
			belle_sip_error("Transaction [%p]: No channel available for sending response.",t);
			return;
		}
		belle_sip_object_ref(base->channel);
312
		belle_sip_channel_add_listener(base->channel, BELLE_SIP_CHANNEL_LISTENER(t));
313
	}
Simon Morlat's avatar
Simon Morlat committed
314 315 316 317 318 319
	status_code=belle_sip_response_get_status_code(resp);
	if (status_code!=100){
		if (belle_sip_header_to_get_tag(to)==NULL){
			//add a random to tag
			belle_sip_header_to_set_tag(to,t->to_tag);
		}
jehan's avatar
jehan committed
320 321 322 323 324 325
		/*12.1 Creation of a Dialog
		   Dialogs are created through the generation of non-failure responses
		   to requests with specific methods.  Within this specification, only
		   2xx and 101-199 responses with a To tag, where the request was
		   INVITE, will establish a dialog.*/
		if (dialog && status_code>100 && status_code<300){
Simon Morlat's avatar
Simon Morlat committed
326 327
			belle_sip_response_fill_for_dialog(resp,base->request);
		}
328
	}
329 330 331 332 333
	if (BELLE_SIP_OBJECT_VPTR(t,belle_sip_server_transaction_t)->send_new_response(t,resp)==0){
		if (base->last_response)
			belle_sip_object_unref(base->last_response);
		base->last_response=resp;
	}
Simon Morlat's avatar
Simon Morlat committed
334
	if (dialog)
jehan's avatar
jehan committed
335
		belle_sip_dialog_update(dialog,BELLE_SIP_TRANSACTION(t),TRUE);
336 337
}

338 339 340
static void server_transaction_notify(belle_sip_server_transaction_t *t, belle_sip_request_t *req, belle_sip_dialog_t *dialog){
	belle_sip_request_event_t event;

Simon Morlat's avatar
Simon Morlat committed
341
	event.source=(belle_sip_object_t*)t->base.provider;
342 343 344
	event.server_transaction=t;
	event.dialog=dialog;
	event.request=req;
jehan's avatar
jehan committed
345
	BELLE_SIP_PROVIDER_INVOKE_LISTENERS_FOR_TRANSACTION(((belle_sip_transaction_t*) t),process_request_event,&event);
346 347
}

Simon Morlat's avatar
Simon Morlat committed
348 349 350
void belle_sip_server_transaction_on_request(belle_sip_server_transaction_t *t, belle_sip_request_t *req){
	const char *method=belle_sip_request_get_method(req);
	if (strcmp(method,"ACK")==0){
351 352 353
		/*this must be for an INVITE server transaction */
		if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(t,belle_sip_ist_t)){
			belle_sip_ist_t *ist=(belle_sip_ist_t*)t;
354 355
			if (belle_sip_ist_process_ack(ist,(belle_sip_message_t*)req)==0){
				belle_sip_dialog_t *dialog=t->base.dialog;
356 357 358 359
				if (dialog && belle_sip_dialog_handle_ack(dialog,req)==0)
					server_transaction_notify(t,req,dialog);
				/*else nothing to do because retransmission of ACK*/

360
			}
361 362 363
		}else{
			belle_sip_warning("ACK received for non-invite server transaction ?");
		}
Simon Morlat's avatar
Simon Morlat committed
364
	}else if (strcmp(method,"CANCEL")==0){
365
		server_transaction_notify(t,req,t->base.dialog);
Simon Morlat's avatar
Simon Morlat committed
366 367
	}else
		BELLE_SIP_OBJECT_VPTR(t,belle_sip_server_transaction_t)->on_request_retransmission(t);
Simon Morlat's avatar
Simon Morlat committed
368
}
369

Simon Morlat's avatar
Simon Morlat committed
370 371 372 373
/*
 * client transaction
 */

374

375

376
belle_sip_request_t * belle_sip_client_transaction_create_cancel(belle_sip_client_transaction_t *t){
377 378 379 380 381 382 383
	belle_sip_message_t *orig=(belle_sip_message_t*)t->base.request;
	belle_sip_request_t *req;
	const char *orig_method=belle_sip_request_get_method((belle_sip_request_t*)orig);
	if (strcmp(orig_method,"ACK")==0 || strcmp(orig_method,"INVITE")!=0){
		belle_sip_error("belle_sip_client_transaction_create_cancel() cannot be used for ACK or non-INVITE transactions.");
		return NULL;
	}
384 385
	if ((t->base.state != BELLE_SIP_TRANSACTION_PROCEEDING) && (t->base.state != BELLE_SIP_TRANSACTION_CALLING)) {
		belle_sip_error("belle_sip_client_transaction_create_cancel() can only be used in state PROCEEDING or CALLING"
386
		               " but current transaction state is %s",belle_sip_transaction_state_to_string(t->base.state));
387
		return NULL;
388 389 390
	}
	req=belle_sip_request_new();
	belle_sip_request_set_method(req,"CANCEL");
391 392 393 394 395 396 397 398 399 400
/*	9.1 Client Behavior
	   Since requests other than INVITE are responded to immediately,
	   sending a CANCEL for a non-INVITE request would always create a
	   race condition.
	   The following procedures are used to construct a CANCEL request.  The
	   Request-URI, Call-ID, To, the numeric part of CSeq, and From header
	   fields in the CANCEL request MUST be identical to those in the
	   request being cancelled, including tags.  A CANCEL constructed by a
	   client MUST have only a single Via header field value matching the
	   top Via value in the request being cancelled.*/
401
	belle_sip_request_set_uri(req,(belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)belle_sip_request_get_uri((belle_sip_request_t*)orig)));
402 403 404 405 406
	belle_sip_util_copy_headers(orig,(belle_sip_message_t*)req,"via",FALSE);
	belle_sip_util_copy_headers(orig,(belle_sip_message_t*)req,"call-id",FALSE);
	belle_sip_util_copy_headers(orig,(belle_sip_message_t*)req,"from",FALSE);
	belle_sip_util_copy_headers(orig,(belle_sip_message_t*)req,"to",FALSE);
	belle_sip_util_copy_headers(orig,(belle_sip_message_t*)req,"route",TRUE);
jehan's avatar
jehan committed
407
	belle_sip_util_copy_headers(orig,(belle_sip_message_t*)req,BELLE_SIP_MAX_FORWARDS,FALSE);
408 409 410 411 412
	belle_sip_message_add_header((belle_sip_message_t*)req,
		(belle_sip_header_t*)belle_sip_header_cseq_create(
			belle_sip_header_cseq_get_seq_number((belle_sip_header_cseq_t*)belle_sip_message_get_header(orig,"cseq")),
		    "CANCEL"));
	return req;
413
}
Simon Morlat's avatar
Simon Morlat committed
414

415

416
int belle_sip_client_transaction_send_request(belle_sip_client_transaction_t *t){
417
	return belle_sip_client_transaction_send_request_to(t,NULL);
418

419
}
420

421
int belle_sip_client_transaction_send_request_to(belle_sip_client_transaction_t *t,belle_sip_uri_t* outbound_proxy) {
Simon Morlat's avatar
Simon Morlat committed
422
	belle_sip_channel_t *chan;
Simon Morlat's avatar
Simon Morlat committed
423
	belle_sip_provider_t *prov=t->base.provider;
424
	belle_sip_dialog_t *dialog=t->base.dialog;
425
	belle_sip_request_t *req=t->base.request;
jehan's avatar
jehan committed
426
	int result=-1;
427

Simon Morlat's avatar
Simon Morlat committed
428 429
	if (t->base.state!=BELLE_SIP_TRANSACTION_INIT){
		belle_sip_error("belle_sip_client_transaction_send_request: bad state.");
430
		return -1;
Simon Morlat's avatar
Simon Morlat committed
431
	}
432

jehan's avatar
jehan committed
433 434 435 436 437
	/*check uris components compliance*/
	if (!belle_sip_request_check_uris_components(t->base.request)) {
		belle_sip_error("belle_sip_client_transaction_send_request: bad request for transaction [%p]",t);
		return -1;
	}
Simon Morlat's avatar
Simon Morlat committed
438
	/*store preset route for future use by refresher*/
439 440 441 442
	if (outbound_proxy){
		t->preset_route=outbound_proxy;
		belle_sip_object_ref(t->preset_route);
	}
443

444 445 446 447 448 449
	if (t->base.sent_by_dialog_queue){
		
		/*it can be sent immediately, so update the request with latest cseq and route_set */
		/*update route and contact just in case they changed*/
		belle_sip_dialog_update_request(dialog,req);
	} else if (t->base.request->dialog_queued){
450
		/*this request was created by belle_sip_dialog_create_queued_request().*/
451 452 453 454 455 456 457 458 459
		
		if (dialog == NULL){
			belle_sip_error("belle_sip_client_transaction_send_request(): transaction [%p], cannot send"
				" request because it was created in the context of a dialog that appears to be "
				" no longer existing.", t);
			belle_sip_transaction_terminate(BELLE_SIP_TRANSACTION(t));
			return -1;
		}
		
460
		if (belle_sip_dialog_request_pending(dialog) || dialog->queued_ct!=NULL){
461
			/*it cannot be sent immediately, queue the transaction into dialog*/
462 463
			belle_sip_message("belle_sip_client_transaction_send_request(): transaction [%p], cannot send request now because dialog [%p] is busy"
			" or other transactions are queued, so queuing into dialog.",t, dialog);
464 465 466
			belle_sip_dialog_queue_client_transaction(dialog,t);
			return 0;
		}
467
		belle_sip_dialog_update_request(dialog,req);
468
	}
469

470 471 472
	if (dialog){
		belle_sip_dialog_update(dialog,(belle_sip_transaction_t*)t,BELLE_SIP_OBJECT_IS_INSTANCE_OF(t,belle_sip_server_transaction_t));
	}
473

474
	if (!t->next_hop) {
475 476
		if (t->preset_route) {
			t->next_hop=belle_sip_hop_new_from_uri(t->preset_route);
477
		} else {
Simon Morlat's avatar
Simon Morlat committed
478
			t->next_hop = belle_sip_stack_get_next_hop(prov->stack,t->base.request);
479
		}
Simon Morlat's avatar
Simon Morlat committed
480
		belle_sip_object_ref(t->next_hop);
481
	} else {
482
		/*next hop already preset, probably in case of CANCEL*/
483
	}
jehan's avatar
jehan committed
484
	belle_sip_provider_add_client_transaction(t->base.provider,t); /*add it in any case*/
485
	chan=belle_sip_provider_get_channel(prov,t->next_hop);
Simon Morlat's avatar
Simon Morlat committed
486
	if (chan){
Simon Morlat's avatar
Simon Morlat committed
487
		belle_sip_object_ref(chan);
Simon Morlat's avatar
Simon Morlat committed
488 489
		belle_sip_channel_add_listener(chan,BELLE_SIP_CHANNEL_LISTENER(t));
		t->base.channel=chan;
490
		if (belle_sip_channel_get_state(chan)==BELLE_SIP_CHANNEL_INIT){
Simon Morlat's avatar
Simon Morlat committed
491
			belle_sip_message("belle_sip_client_transaction_send_request(): waiting channel to be ready");
492 493
			belle_sip_channel_prepare(chan);
			/*the channel will notify us when it is ready*/
494
		} else if (belle_sip_channel_get_state(chan)==BELLE_SIP_CHANNEL_READY){
495
			/*otherwise we can send immediately*/
496
			BELLE_SIP_OBJECT_VPTR(t,belle_sip_client_transaction_t)->send_request(t);
Simon Morlat's avatar
Simon Morlat committed
497
		}
jehan's avatar
jehan committed
498 499 500 501 502 503 504
		result=0;
	}else {
		belle_sip_error("belle_sip_client_transaction_send_request(): no channel available");
		belle_sip_transaction_terminate(BELLE_SIP_TRANSACTION(t));
		result=-1;
	}
	return result;
Simon Morlat's avatar
Simon Morlat committed
505
}
506

jehan's avatar
jehan committed
507 508 509 510
static unsigned int should_dialog_be_created(belle_sip_client_transaction_t *t, belle_sip_response_t *resp){
	belle_sip_request_t* req = belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(t));
	const char* method = belle_sip_request_get_method(req);
	int status_code = belle_sip_response_get_status_code(resp);
511
	return status_code>=101 && status_code<300 && (strcmp(method,"INVITE")==0 || strcmp(method,"SUBSCRIBE")==0);
jehan's avatar
jehan committed
512
}
513

514
void belle_sip_client_transaction_notify_response(belle_sip_client_transaction_t *t, belle_sip_response_t *resp){
Simon Morlat's avatar
Simon Morlat committed
515
	belle_sip_transaction_t *base=(belle_sip_transaction_t*)t;
jehan's avatar
jehan committed
516 517
	belle_sip_request_t* req = belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(t));
	const char* method = belle_sip_request_get_method(req);
518
	belle_sip_response_event_t event;
Simon Morlat's avatar
Simon Morlat committed
519
	belle_sip_dialog_t *dialog=base->dialog;
520
	int status_code =  belle_sip_response_get_status_code(resp);
521 522
	if (base->last_response)
		belle_sip_object_unref(base->last_response);
jehan's avatar
jehan committed
523
	base->last_response=(belle_sip_response_t*)belle_sip_object_ref(resp);
524

Simon Morlat's avatar
Simon Morlat committed
525
	if (dialog){
526
		if (status_code>=101 && status_code<300
jehan's avatar
jehan committed
527 528
			&& strcmp(method,"INVITE")==0
			&& (dialog->state==BELLE_SIP_DIALOG_EARLY || dialog->state==BELLE_SIP_DIALOG_CONFIRMED)){
Simon Morlat's avatar
Simon Morlat committed
529 530
			/*make sure this response matches the current dialog, or creates a new one*/
			if (!belle_sip_dialog_match(dialog,(belle_sip_message_t*)resp,FALSE)){
531 532 533 534 535
				dialog=belle_sip_provider_find_dialog_from_message(t->base.provider,(belle_sip_message_t*)resp,FALSE);
				if (!dialog){
					dialog=belle_sip_provider_create_dialog_internal(t->base.provider,BELLE_SIP_TRANSACTION(t),FALSE);/*belle_sip_dialog_new(base);*/
					belle_sip_message("Handling response creating a new dialog !");
				}
Simon Morlat's avatar
Simon Morlat committed
536 537
			}
		}
jehan's avatar
jehan committed
538
	} else if (should_dialog_be_created(t,resp)) {
jehan's avatar
jehan committed
539
		dialog=belle_sip_provider_create_dialog_internal(t->base.provider,BELLE_SIP_TRANSACTION(t),FALSE);
Simon Morlat's avatar
Simon Morlat committed
540
	}
jehan's avatar
jehan committed
541

jehan's avatar
jehan committed
542
	if (dialog && belle_sip_dialog_update(dialog,BELLE_SIP_TRANSACTION(t),FALSE)) {
jehan's avatar
jehan committed
543
		/* retransmition, just return*/
544
		belle_sip_message("Response [%p] absorbed by dialog [%p], skipped from transaction layer.",resp,dialog);
jehan's avatar
jehan committed
545 546
		return;
	}
jehan's avatar
jehan committed
547

Simon Morlat's avatar
Simon Morlat committed
548
	event.source=(belle_sip_object_t*)base->provider;
549
	event.client_transaction=t;
Simon Morlat's avatar
Simon Morlat committed
550
	event.dialog=dialog;
551
	event.response=(belle_sip_response_t*)resp;
jehan's avatar
jehan committed
552
	BELLE_SIP_PROVIDER_INVOKE_LISTENERS_FOR_TRANSACTION(((belle_sip_transaction_t*)t),process_response_event,&event);
jehan's avatar
jehan committed
553
	/*check that 200Ok for INVITEs have been acknowledged by listener*/
554
	if (dialog && status_code>=200 && status_code<300 && strcmp(method,"INVITE")==0){
jehan's avatar
jehan committed
555
		belle_sip_dialog_check_ack_sent(dialog);
556 557 558 559 560
	}
	/*report a server having internal errors for REGISTER to the channel, in order to go to a fallback IP*/
	if (status_code == 500 && strcmp(method,"REGISTER") == 0){
		belle_sip_channel_notify_server_error(base->channel);
	}
561 562 563 564 565
}


void belle_sip_client_transaction_add_response(belle_sip_client_transaction_t *t, belle_sip_response_t *resp){
	BELLE_SIP_OBJECT_VPTR(t,belle_sip_client_transaction_t)->on_response(t,resp);
Simon Morlat's avatar
Simon Morlat committed
566 567
}

568 569 570 571
belle_sip_uri_t *belle_sip_client_transaction_get_route(belle_sip_client_transaction_t *t){
	return t->preset_route;
}

Simon Morlat's avatar
Simon Morlat committed
572
static void client_transaction_destroy(belle_sip_client_transaction_t *t ){
jehan's avatar
jehan committed
573
	if (t->preset_route) belle_sip_object_unref(t->preset_route);
Simon Morlat's avatar
Simon Morlat committed
574
	if (t->next_hop) belle_sip_object_unref(t->next_hop);
Simon Morlat's avatar
Simon Morlat committed
575 576
}

Simon Morlat's avatar
Simon Morlat committed
577

Simon Morlat's avatar
Simon Morlat committed
578

579
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_client_transaction_t);
580
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_client_transaction_t)
Simon Morlat's avatar
Simon Morlat committed
581
	{
Simon Morlat's avatar
Simon Morlat committed
582 583 584 585 586 587
		{
			BELLE_SIP_VPTR_INIT(belle_sip_client_transaction_t,belle_sip_transaction_t,FALSE),
			(belle_sip_object_destroy_t)client_transaction_destroy,
			NULL,
			NULL
		},
Simon Morlat's avatar
Simon Morlat committed
588 589 590 591
		NULL
	},
	NULL,
	NULL
592
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END
Simon Morlat's avatar
Simon Morlat committed
593

Simon Morlat's avatar
Simon Morlat committed
594
void belle_sip_client_transaction_init(belle_sip_client_transaction_t *obj, belle_sip_provider_t *prov, belle_sip_request_t *req){
Simon Morlat's avatar
Simon Morlat committed
595
	belle_sip_header_via_t *via=BELLE_SIP_HEADER_VIA(belle_sip_message_get_header((belle_sip_message_t*)req,"via"));
Simon Morlat's avatar
Simon Morlat committed
596
	char token[BELLE_SIP_BRANCH_ID_LENGTH];
597 598 599 600

	if (!via){
		belle_sip_fatal("belle_sip_client_transaction_init(): No via in request.");
	}
601

602 603
	if (strcmp(belle_sip_request_get_method(req),"CANCEL")!=0){
		obj->base.branch_id=belle_sip_strdup_printf(BELLE_SIP_BRANCH_MAGIC_COOKIE ".%s",belle_sip_random_token(token,sizeof(token)));
Simon Morlat's avatar
Simon Morlat committed
604 605
		belle_sip_header_via_set_branch(via,obj->base.branch_id);
	}else{
606
		obj->base.branch_id=belle_sip_strdup(belle_sip_header_via_get_branch(via));
Simon Morlat's avatar
Simon Morlat committed
607
	}
Simon Morlat's avatar
Simon Morlat committed
608
	belle_sip_transaction_init((belle_sip_transaction_t*)obj, prov,req);
609 610
}

jehan's avatar
jehan committed
611
belle_sip_refresher_t* belle_sip_client_transaction_create_refresher(belle_sip_client_transaction_t *t) {
612
	return belle_sip_refresher_new(t);
jehan's avatar
jehan committed
613
}
614

615
belle_sip_request_t* belle_sip_client_transaction_create_authenticated_request(belle_sip_client_transaction_t *t,belle_sip_list_t** auth_infos,const char* realm) {
616 617
	belle_sip_request_t* initial_request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(t));
	belle_sip_request_t* req=belle_sip_request_clone_with_body(initial_request);
jehan's avatar
jehan committed
618 619
	belle_sip_header_cseq_t* cseq=belle_sip_message_get_header_by_type(req,belle_sip_header_cseq_t);
	belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+1);
620 621
	if (belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(t)) != BELLE_SIP_TRANSACTION_COMPLETED
		&& belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(t)) != BELLE_SIP_TRANSACTION_TERMINATED) {
jehan's avatar
jehan committed
622
		belle_sip_error("Invalid state [%s] for transaction [%p], should be BELLE_SIP_TRANSACTION_COMPLETED | BELLE_SIP_TRANSACTION_TERMINATED"
jehan's avatar
jehan committed
623 624
					,belle_sip_transaction_state_to_string(belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(t)))
					,t);
625
		belle_sip_object_unref(req);
jehan's avatar
jehan committed
626 627 628 629 630
		return NULL;
	}
	/*remove auth headers*/
	belle_sip_message_remove_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_AUTHORIZATION);
	belle_sip_message_remove_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_PROXY_AUTHORIZATION);
631

jehan's avatar
jehan committed
632
	/*put auth header*/
633
	belle_sip_provider_add_authorization(t->base.provider,req,t->base.last_response,NULL,auth_infos,realm);
jehan's avatar
jehan committed
634 635
	return req;
}
636

637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687
/*
 rfc 3265
 3.3.4. Dialog creation and termination
 ...
 NOTIFY requests are matched to such SUBSCRIBE requests if they
 contain the same "Call-ID", a "To" header "tag" parameter which
 matches the "From" header "tag" parameter of the SUBSCRIBE, and the
 same "Event" header field.  Rules for comparisons of the "Event"
 headers are described in section 7.2.1.  If a matching NOTIFY request
 contains a "Subscription-State" of "active" or "pending", it creates
 a new subscription and a new dialog (unless they have already been
 created by a matching response, as described above).
 
 
 */

int belle_sip_client_transaction_is_notify_matching_pending_subscribe(belle_sip_client_transaction_t *trans
																	  , belle_sip_request_t *notify) {
	belle_sip_request_t *subscription;
	belle_sip_header_event_t *sub_event, *notif_event;
	belle_sip_header_call_id_t *sub_call_id, *notif_call_id;
	const char* sub_from_tag, *notif_to_tag;
	
	if (!belle_sip_transaction_state_is_transient(belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(trans)))
		|| strcmp("SUBSCRIBE", belle_sip_transaction_get_method(BELLE_SIP_TRANSACTION(trans)))!=0) return 0;
	
	
	if (strcmp("NOTIFY",belle_sip_request_get_method(notify)) != 0) {
		belle_sip_error("belle_sip_client_transaction_is_notify_matching_pending_subscribe for dialog [%p], requires a notify request",notify);
	}
	
	subscription = belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(trans));
	sub_event = belle_sip_message_get_header_by_type(subscription, belle_sip_header_event_t);
	if (!sub_event || !belle_sip_header_event_get_package_name(sub_event))
		return 0;
	
	notif_event = belle_sip_message_get_header_by_type(notify, belle_sip_header_event_t);
	if (!notif_event || !belle_sip_header_event_get_package_name(notif_event))
		return 0;
	
	sub_call_id = belle_sip_message_get_header_by_type(subscription, belle_sip_header_call_id_t);
	notif_call_id = belle_sip_message_get_header_by_type(notify, belle_sip_header_call_id_t);
	sub_from_tag = belle_sip_header_from_get_tag(belle_sip_message_get_header_by_type(subscription, belle_sip_header_from_t));
	notif_to_tag = belle_sip_header_to_get_tag(belle_sip_message_get_header_by_type(notify, belle_sip_header_to_t));
	
	return strcmp(belle_sip_header_call_id_get_call_id(sub_call_id),belle_sip_header_call_id_get_call_id(notif_call_id))==0
	&& sub_from_tag && notif_to_tag && strcmp(sub_from_tag,notif_to_tag)==0
	&& strcasecmp(belle_sip_header_event_get_package_name(sub_event),belle_sip_header_event_get_package_name(notif_event))==0;
	
}