transaction.c 29.1 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
	t->provider=prov;
}

static void transaction_destroy(belle_sip_transaction_t *t){
64 65 66 67 68
	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;
	}
69
	if (t->request) belle_sip_object_unref(t->request);
70
	if (t->last_response) belle_sip_object_unref(t->last_response);
Simon Morlat's avatar
Simon Morlat committed
71
	if (t->channel) belle_sip_object_unref(t->channel);
72
	if (t->branch_id) belle_sip_free(t->branch_id);
73
	belle_sip_transaction_set_dialog(t,NULL);
74
	belle_sip_message("Transaction [%p] deleted",t);
jehan's avatar
jehan committed
75

76
}
77

78 79 80 81 82 83 84 85
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);
}

86 87 88 89 90
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;
}

91 92 93 94 95 96
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;
}

97 98 99
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;
100
	const belle_sip_timer_config_t *timercfg;
101 102 103 104 105 106 107 108 109 110 111 112 113 114
	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:
115
			belle_sip_object_ref(t);  /*take a ref in the case where the app calls belle_sip_transaction_terminate() within the listener*/
116 117 118 119 120 121 122 123 124 125
			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);
			}
126
			if (t->timed_out) {
127
				notify_timeout((belle_sip_transaction_t*)t);
128
			} else {
129 130 131 132 133 134
				if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(t, belle_sip_ist_t) || BELLE_SIP_OBJECT_IS_INSTANCE_OF(t, belle_sip_ict_t)) {
					timercfg = belle_sip_transaction_get_timer_config(t);
					if (t->call_repair_timer) {
						belle_sip_transaction_stop_timer(t, t->call_repair_timer);
						belle_sip_object_unref(t->call_repair_timer);
					}
135 136
				}
			}
137

138
			if (!t->timed_out && BELLE_SIP_OBJECT_IS_INSTANCE_OF(t, belle_sip_ist_t)) {
139
				t->call_repair_timer = belle_sip_timeout_source_new((belle_sip_source_func_t)server_transaction_on_call_repair_timer, t, 32 * timercfg->T1);
140
				belle_sip_transaction_start_timer(t, t->call_repair_timer);
141
			} else if (!t->timed_out && BELLE_SIP_OBJECT_IS_INSTANCE_OF(t, belle_sip_ict_t)) {
142
				t->call_repair_timer = belle_sip_timeout_source_new((belle_sip_source_func_t)client_transaction_on_call_repair_timer, t, 32 * timercfg->T1);
143
				belle_sip_transaction_start_timer(t, t->call_repair_timer);
144 145 146
			} else {
				belle_sip_transaction_terminate(t);
			}
147
			belle_sip_object_unref(t);
148 149
			belle_sip_object_unref(((belle_sip_transaction_t*)t)->channel);
			((belle_sip_transaction_t*)t)->channel = NULL;
150 151 152 153 154 155 156 157 158
		break;
		default:
			/*ignored*/
		break;
	}
}

BELLE_SIP_IMPLEMENT_INTERFACE_BEGIN(belle_sip_transaction_t,belle_sip_channel_listener_t)
on_channel_state_changed,
159 160 161 162
NULL, /* on_message_headers */
NULL, /* on_message */
NULL, /* on_sending */
NULL /* on_auth_requested */
163 164 165
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
166

167
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_transaction_t)
Simon Morlat's avatar
Simon Morlat committed
168
	{
Simon Morlat's avatar
Simon Morlat committed
169 170 171
		BELLE_SIP_VPTR_INIT(belle_sip_transaction_t,belle_sip_object_t,FALSE),
		(belle_sip_object_destroy_t) transaction_destroy,
		NULL,/*no clone*/
172
		NULL,/*no marshal*/
173
		BELLE_SIP_DEFAULT_BUFSIZE_HINT
Simon Morlat's avatar
Simon Morlat committed
174 175
	},
	NULL /*on_terminate*/
176
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END
Simon Morlat's avatar
Simon Morlat committed
177

178
void *belle_sip_transaction_get_application_data_internal(const belle_sip_transaction_t *t){
179 180 181
	return t->appdata;
}

182 183 184 185 186 187 188 189 190
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);
	};
}

191 192 193 194 195 196 197 198 199 200 201
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;
}
202

jehan's avatar
jehan committed
203 204 205 206 207 208 209 210 211 212 213
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;
	}
}
214

215
void belle_sip_transaction_terminate(belle_sip_transaction_t *t){
216
	if (belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(t))!=BELLE_SIP_TRANSACTION_TERMINATED) {
217
		int is_client=BELLE_SIP_OBJECT_IS_INSTANCE_OF(t,belle_sip_client_transaction_t);
218
		belle_sip_transaction_set_state(t,BELLE_SIP_TRANSACTION_TERMINATED);
219 220 221 222 223 224
		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":""
225 226 227
									,belle_sip_request_get_method(belle_sip_transaction_get_request(t))
									,t);
		BELLE_SIP_OBJECT_VPTR(t,belle_sip_transaction_t)->on_terminate(t);
228
		belle_sip_provider_set_transaction_terminated(t->provider,t);
229
	}
230 231 232 233 234
	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;
	}
235 236
}

jehan's avatar
jehan committed
237
belle_sip_request_t *belle_sip_transaction_get_request(const belle_sip_transaction_t *t){
238 239
	return t->request;
}
240 241 242
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
243 244

void belle_sip_transaction_notify_timeout(belle_sip_transaction_t *t){
245
	/*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
246
	 * Otherwise it will report the error.
247
	 * We limit this dead channel reporting to REGISTER transactions, who are unlikely to be unresponded.
Simon Morlat's avatar
Simon Morlat committed
248
	**/
249
	belle_sip_object_ref(t);  /*take a ref in the case where the app calls belle_sip_transaction_terminate() within the timeout listener*/
250 251 252 253 254
	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;
		}
255 256 257 258
	}else {
		notify_timeout(t);
		belle_sip_transaction_terminate(t);
	}
259
	belle_sip_object_unref(t);
Simon Morlat's avatar
Simon Morlat committed
260 261
}

jehan's avatar
jehan committed
262 263
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
264 265
}

266 267 268 269 270
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
271
void belle_sip_transaction_set_dialog(belle_sip_transaction_t *t, belle_sip_dialog_t *dialog){
272
	if (t->dialog==dialog) return;
273 274
	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
275 276 277
	t->dialog=dialog;
}

278
/*
Simon Morlat's avatar
Simon Morlat committed
279 280
 * Server transaction
 */
281

282 283 284
static void server_transaction_destroy(belle_sip_server_transaction_t *t){
}

Simon Morlat's avatar
Simon Morlat committed
285

286
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_server_transaction_t);
287
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_server_transaction_t)
Simon Morlat's avatar
Simon Morlat committed
288
	{
Simon Morlat's avatar
Simon Morlat committed
289 290 291 292
		{
			BELLE_SIP_VPTR_INIT(belle_sip_server_transaction_t,belle_sip_transaction_t,FALSE),
			(belle_sip_object_destroy_t) server_transaction_destroy,
			NULL,
293 294
			NULL,
			BELLE_SIP_DEFAULT_BUFSIZE_HINT
Simon Morlat's avatar
Simon Morlat committed
295 296
		},
		NULL
297 298 299
	},
	NULL, /* send_new_response */
	NULL /* on_request_retransmission */
300
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END
Simon Morlat's avatar
Simon Morlat committed
301

302
void belle_sip_server_transaction_init(belle_sip_server_transaction_t *t, belle_sip_provider_t *prov,belle_sip_request_t *req){
303
	const char *branch;
304
	belle_sip_header_via_t *via=BELLE_SIP_HEADER_VIA(belle_sip_message_get_header((belle_sip_message_t*)req,"via"));
305
	branch=belle_sip_header_via_get_branch(via);
306
	if (branch==NULL || strncmp(branch,BELLE_SIP_BRANCH_MAGIC_COOKIE,strlen(BELLE_SIP_BRANCH_MAGIC_COOKIE))!=0){
307
		branch=req->rfc2543_branch;
308
		if (branch==NULL) belle_sip_fatal("No computed branch for RFC2543 style of message, this should never happen.");
309 310
	}
	t->base.branch_id=belle_sip_strdup(branch);
311
	belle_sip_transaction_init((belle_sip_transaction_t*)t,prov,req);
312
	belle_sip_random_token(t->to_tag,sizeof(t->to_tag));
313 314
}

Simon Morlat's avatar
Simon Morlat committed
315
void belle_sip_server_transaction_send_response(belle_sip_server_transaction_t *t, belle_sip_response_t *resp){
316
	belle_sip_transaction_t *base=(belle_sip_transaction_t*)t;
317
	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
318
	belle_sip_dialog_t *dialog=base->dialog;
Simon Morlat's avatar
Simon Morlat committed
319
	int status_code;
320

321
	belle_sip_object_ref(resp);
322
	if (!base->last_response || !base->channel){
jehan's avatar
jehan committed
323
		belle_sip_hop_t* hop=belle_sip_response_get_return_hop(resp);
324
		base->channel=belle_sip_provider_get_channel(base->provider,hop);
jehan's avatar
jehan committed
325
		belle_sip_object_unref(hop);
326 327 328 329 330
		if (!base->channel){
			belle_sip_error("Transaction [%p]: No channel available for sending response.",t);
			return;
		}
		belle_sip_object_ref(base->channel);
331
		belle_sip_channel_add_listener(base->channel, BELLE_SIP_CHANNEL_LISTENER(t));
332
	}
Simon Morlat's avatar
Simon Morlat committed
333 334 335 336 337 338
	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
339 340 341 342 343 344
		/*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
345 346
			belle_sip_response_fill_for_dialog(resp,base->request);
		}
347
	}
348 349 350 351 352
	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
353
	if (dialog)
jehan's avatar
jehan committed
354
		belle_sip_dialog_update(dialog,BELLE_SIP_TRANSACTION(t),TRUE);
355 356
}

357 358 359
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
360
	event.source=(belle_sip_object_t*)t->base.provider;
361 362 363
	event.server_transaction=t;
	event.dialog=dialog;
	event.request=req;
jehan's avatar
jehan committed
364
	BELLE_SIP_PROVIDER_INVOKE_LISTENERS_FOR_TRANSACTION(((belle_sip_transaction_t*) t),process_request_event,&event);
365 366
}

Simon Morlat's avatar
Simon Morlat committed
367 368 369
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){
370 371 372
		/*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;
373 374
			if (belle_sip_ist_process_ack(ist,(belle_sip_message_t*)req)==0){
				belle_sip_dialog_t *dialog=t->base.dialog;
375 376 377 378
				if (dialog && belle_sip_dialog_handle_ack(dialog,req)==0)
					server_transaction_notify(t,req,dialog);
				/*else nothing to do because retransmission of ACK*/

379
			}
380 381 382
		}else{
			belle_sip_warning("ACK received for non-invite server transaction ?");
		}
Simon Morlat's avatar
Simon Morlat committed
383
	}else if (strcmp(method,"CANCEL")==0){
384
		server_transaction_notify(t,req,t->base.dialog);
Simon Morlat's avatar
Simon Morlat committed
385 386
	}else
		BELLE_SIP_OBJECT_VPTR(t,belle_sip_server_transaction_t)->on_request_retransmission(t);
Simon Morlat's avatar
Simon Morlat committed
387
}
388

Simon Morlat's avatar
Simon Morlat committed
389 390 391 392
/*
 * client transaction
 */

393

394

395
belle_sip_request_t * belle_sip_client_transaction_create_cancel(belle_sip_client_transaction_t *t){
396 397 398 399 400 401 402
	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;
	}
403 404
	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"
405
		               " but current transaction state is %s",belle_sip_transaction_state_to_string(t->base.state));
406
		return NULL;
407 408 409
	}
	req=belle_sip_request_new();
	belle_sip_request_set_method(req,"CANCEL");
410 411 412 413 414 415 416 417 418 419
/*	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.*/
420
	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)));
421 422 423 424 425
	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
426
	belle_sip_util_copy_headers(orig,(belle_sip_message_t*)req,BELLE_SIP_MAX_FORWARDS,FALSE);
427 428 429 430 431
	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;
432
}
Simon Morlat's avatar
Simon Morlat committed
433

434

435
int belle_sip_client_transaction_send_request(belle_sip_client_transaction_t *t){
436
	return belle_sip_client_transaction_send_request_to(t,NULL);
437

438
}
439

440
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
441
	belle_sip_channel_t *chan;
Simon Morlat's avatar
Simon Morlat committed
442
	belle_sip_provider_t *prov=t->base.provider;
443
	belle_sip_dialog_t *dialog=t->base.dialog;
444
	belle_sip_request_t *req=t->base.request;
jehan's avatar
jehan committed
445
	int result=-1;
446

Simon Morlat's avatar
Simon Morlat committed
447 448
	if (t->base.state!=BELLE_SIP_TRANSACTION_INIT){
		belle_sip_error("belle_sip_client_transaction_send_request: bad state.");
449
		return -1;
Simon Morlat's avatar
Simon Morlat committed
450
	}
451

jehan's avatar
jehan committed
452 453 454 455 456
	/*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
457
	/*store preset route for future use by refresher*/
458 459 460 461
	if (outbound_proxy){
		t->preset_route=outbound_proxy;
		belle_sip_object_ref(t->preset_route);
	}
462

463 464 465 466 467 468
	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){
469
		/*this request was created by belle_sip_dialog_create_queued_request().*/
470 471 472 473 474 475 476 477 478
		
		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;
		}
		
479
		if (belle_sip_dialog_request_pending(dialog) || dialog->queued_ct!=NULL){
480
			/*it cannot be sent immediately, queue the transaction into dialog*/
481 482
			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);
483 484 485
			belle_sip_dialog_queue_client_transaction(dialog,t);
			return 0;
		}
486
		belle_sip_dialog_update_request(dialog,req);
487
	}
488

489 490 491
	if (dialog){
		belle_sip_dialog_update(dialog,(belle_sip_transaction_t*)t,BELLE_SIP_OBJECT_IS_INSTANCE_OF(t,belle_sip_server_transaction_t));
	}
492

493
	if (!t->next_hop) {
494 495
		if (t->preset_route) {
			t->next_hop=belle_sip_hop_new_from_uri(t->preset_route);
496
		} else {
Simon Morlat's avatar
Simon Morlat committed
497
			t->next_hop = belle_sip_stack_get_next_hop(prov->stack,t->base.request);
498
		}
Simon Morlat's avatar
Simon Morlat committed
499
		belle_sip_object_ref(t->next_hop);
500
	} else {
501
		/*next hop already preset, probably in case of CANCEL*/
502
	}
jehan's avatar
jehan committed
503
	belle_sip_provider_add_client_transaction(t->base.provider,t); /*add it in any case*/
504
	chan=belle_sip_provider_get_channel(prov,t->next_hop);
Simon Morlat's avatar
Simon Morlat committed
505
	if (chan){
Simon Morlat's avatar
Simon Morlat committed
506
		belle_sip_object_ref(chan);
Simon Morlat's avatar
Simon Morlat committed
507 508
		belle_sip_channel_add_listener(chan,BELLE_SIP_CHANNEL_LISTENER(t));
		t->base.channel=chan;
509
		if (belle_sip_channel_get_state(chan)==BELLE_SIP_CHANNEL_INIT){
Simon Morlat's avatar
Simon Morlat committed
510
			belle_sip_message("belle_sip_client_transaction_send_request(): waiting channel to be ready");
511 512
			belle_sip_channel_prepare(chan);
			/*the channel will notify us when it is ready*/
513
		} else if (belle_sip_channel_get_state(chan)==BELLE_SIP_CHANNEL_READY){
514
			/*otherwise we can send immediately*/
515
			BELLE_SIP_OBJECT_VPTR(t,belle_sip_client_transaction_t)->send_request(t);
Simon Morlat's avatar
Simon Morlat committed
516
		}
jehan's avatar
jehan committed
517 518 519 520 521 522 523
		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
524
}
525

jehan's avatar
jehan committed
526 527 528 529
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);
530
	return status_code>=101 && status_code<300 && (strcmp(method,"INVITE")==0 || strcmp(method,"SUBSCRIBE")==0);
jehan's avatar
jehan committed
531
}
532

533
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
534
	belle_sip_transaction_t *base=(belle_sip_transaction_t*)t;
jehan's avatar
jehan committed
535 536
	belle_sip_request_t* req = belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(t));
	const char* method = belle_sip_request_get_method(req);
537
	belle_sip_response_event_t event;
Simon Morlat's avatar
Simon Morlat committed
538
	belle_sip_dialog_t *dialog=base->dialog;
539
	int status_code =  belle_sip_response_get_status_code(resp);
540 541
	if (base->last_response)
		belle_sip_object_unref(base->last_response);
jehan's avatar
jehan committed
542
	base->last_response=(belle_sip_response_t*)belle_sip_object_ref(resp);
543

Simon Morlat's avatar
Simon Morlat committed
544
	if (dialog){
545
		if (status_code>=101 && status_code<300
jehan's avatar
jehan committed
546 547
			&& strcmp(method,"INVITE")==0
			&& (dialog->state==BELLE_SIP_DIALOG_EARLY || dialog->state==BELLE_SIP_DIALOG_CONFIRMED)){
Simon Morlat's avatar
Simon Morlat committed
548 549
			/*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)){
550 551 552 553 554
				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
555 556
			}
		}
jehan's avatar
jehan committed
557
	} else if (should_dialog_be_created(t,resp)) {
jehan's avatar
jehan committed
558
		dialog=belle_sip_provider_create_dialog_internal(t->base.provider,BELLE_SIP_TRANSACTION(t),FALSE);
Simon Morlat's avatar
Simon Morlat committed
559
	}
jehan's avatar
jehan committed
560

jehan's avatar
jehan committed
561
	if (dialog && belle_sip_dialog_update(dialog,BELLE_SIP_TRANSACTION(t),FALSE)) {
jehan's avatar
jehan committed
562
		/* retransmition, just return*/
563
		belle_sip_message("Response [%p] absorbed by dialog [%p], skipped from transaction layer.",resp,dialog);
jehan's avatar
jehan committed
564 565
		return;
	}
jehan's avatar
jehan committed
566

Simon Morlat's avatar
Simon Morlat committed
567
	event.source=(belle_sip_object_t*)base->provider;
568
	event.client_transaction=t;
Simon Morlat's avatar
Simon Morlat committed
569
	event.dialog=dialog;
570
	event.response=(belle_sip_response_t*)resp;
jehan's avatar
jehan committed
571
	BELLE_SIP_PROVIDER_INVOKE_LISTENERS_FOR_TRANSACTION(((belle_sip_transaction_t*)t),process_response_event,&event);
jehan's avatar
jehan committed
572
	/*check that 200Ok for INVITEs have been acknowledged by listener*/
573
	if (dialog && status_code>=200 && status_code<300 && strcmp(method,"INVITE")==0){
jehan's avatar
jehan committed
574
		belle_sip_dialog_check_ack_sent(dialog);
575 576 577 578 579
	}
	/*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);
	}
580 581 582 583 584
}


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
585 586
}

587 588 589 590
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
591
static void client_transaction_destroy(belle_sip_client_transaction_t *t ){
jehan's avatar
jehan committed
592
	if (t->preset_route) belle_sip_object_unref(t->preset_route);
Simon Morlat's avatar
Simon Morlat committed
593
	if (t->next_hop) belle_sip_object_unref(t->next_hop);
Simon Morlat's avatar
Simon Morlat committed
594 595
}

Simon Morlat's avatar
Simon Morlat committed
596

Simon Morlat's avatar
Simon Morlat committed
597

598
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_client_transaction_t);
599
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_client_transaction_t)
Simon Morlat's avatar
Simon Morlat committed
600
	{
Simon Morlat's avatar
Simon Morlat committed
601 602 603 604
		{
			BELLE_SIP_VPTR_INIT(belle_sip_client_transaction_t,belle_sip_transaction_t,FALSE),
			(belle_sip_object_destroy_t)client_transaction_destroy,
			NULL,
605 606
			NULL,
			BELLE_SIP_DEFAULT_BUFSIZE_HINT
Simon Morlat's avatar
Simon Morlat committed
607
		},
Simon Morlat's avatar
Simon Morlat committed
608 609 610 611
		NULL
	},
	NULL,
	NULL
612
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END
Simon Morlat's avatar
Simon Morlat committed
613

Simon Morlat's avatar
Simon Morlat committed
614
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
615
	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
616
	char token[BELLE_SIP_BRANCH_ID_LENGTH];
617 618 619 620

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

622 623
	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
624 625
		belle_sip_header_via_set_branch(via,obj->base.branch_id);
	}else{
626
		obj->base.branch_id=belle_sip_strdup(belle_sip_header_via_get_branch(via));
Simon Morlat's avatar
Simon Morlat committed
627
	}
Simon Morlat's avatar
Simon Morlat committed
628
	belle_sip_transaction_init((belle_sip_transaction_t*)obj, prov,req);
629 630
}

jehan's avatar
jehan committed
631
belle_sip_refresher_t* belle_sip_client_transaction_create_refresher(belle_sip_client_transaction_t *t) {
632
	return belle_sip_refresher_new(t);
jehan's avatar
jehan committed
633
}
634

635
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) {
636 637
	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
638 639
	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);
640 641
	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
642
		belle_sip_error("Invalid state [%s] for transaction [%p], should be BELLE_SIP_TRANSACTION_COMPLETED | BELLE_SIP_TRANSACTION_TERMINATED"
jehan's avatar
jehan committed
643 644
					,belle_sip_transaction_state_to_string(belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(t)))
					,t);
645
		belle_sip_object_unref(req);
jehan's avatar
jehan committed
646 647 648 649 650
		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);
651

jehan's avatar
jehan committed
652
	/*put auth header*/
653
	belle_sip_provider_add_authorization(t->base.provider,req,t->base.last_response,NULL,auth_infos,realm);
jehan's avatar
jehan committed
654 655
	return req;
}
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 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707
/*
 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;
	
}