transaction.c 27 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 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
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);
}

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:
98
			belle_sip_object_ref(t);  /*take a ref in the case where the app calls belle_sip_transaction_terminate() within the listener*/
99 100 101 102 103 104 105 106 107 108 109 110 111 112
			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);

			belle_sip_transaction_terminate(t);
113
			belle_sip_object_unref(t);
114 115 116 117 118 119 120 121 122 123 124 125 126 127
		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
128

129
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_transaction_t)
Simon Morlat's avatar
Simon Morlat committed
130
	{
Simon Morlat's avatar
Simon Morlat committed
131 132 133
		BELLE_SIP_VPTR_INIT(belle_sip_transaction_t,belle_sip_object_t,FALSE),
		(belle_sip_object_destroy_t) transaction_destroy,
		NULL,/*no clone*/
134
		NULL,/*no marshal*/
Simon Morlat's avatar
Simon Morlat committed
135 136
	},
	NULL /*on_terminate*/
137
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END
Simon Morlat's avatar
Simon Morlat committed
138

139
void *belle_sip_transaction_get_application_data_internal(const belle_sip_transaction_t *t){
140 141 142
	return t->appdata;
}

143 144 145 146 147 148 149 150 151
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);
	};
}

152 153 154 155 156 157 158 159 160 161 162
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;
}
163

jehan's avatar
jehan committed
164 165 166 167 168 169 170 171 172 173 174
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;
	}
}
175

176
void belle_sip_transaction_terminate(belle_sip_transaction_t *t){
177
	if (belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(t))!=BELLE_SIP_TRANSACTION_TERMINATED) {
178
		int is_client=BELLE_SIP_OBJECT_IS_INSTANCE_OF(t,belle_sip_client_transaction_t);
179
		belle_sip_transaction_set_state(t,BELLE_SIP_TRANSACTION_TERMINATED);
180 181 182 183 184 185
		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":""
186 187 188
									,belle_sip_request_get_method(belle_sip_transaction_get_request(t))
									,t);
		BELLE_SIP_OBJECT_VPTR(t,belle_sip_transaction_t)->on_terminate(t);
189
		belle_sip_provider_set_transaction_terminated(t->provider,t);
190
	}
191 192
}

jehan's avatar
jehan committed
193
belle_sip_request_t *belle_sip_transaction_get_request(const belle_sip_transaction_t *t){
194 195
	return t->request;
}
196 197 198
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
199 200

void belle_sip_transaction_notify_timeout(belle_sip_transaction_t *t){
201
	/*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
202
	 * Otherwise it will report the error.
203
	 * We limit this dead channel reporting to REGISTER transactions, who are unlikely to be unresponded.
Simon Morlat's avatar
Simon Morlat committed
204
	**/
205
	belle_sip_object_ref(t);  /*take a ref in the case where the app calls belle_sip_transaction_terminate() within the timeout listener*/
206 207 208 209 210
	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;
		}
211 212 213 214
	}else {
		notify_timeout(t);
		belle_sip_transaction_terminate(t);
	}
215
	belle_sip_object_unref(t);
Simon Morlat's avatar
Simon Morlat committed
216 217
}

jehan's avatar
jehan committed
218 219
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
220 221
}

222 223 224 225 226
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
227
void belle_sip_transaction_set_dialog(belle_sip_transaction_t *t, belle_sip_dialog_t *dialog){
228
	if (t->dialog==dialog) return;
229 230
	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
231 232 233
	t->dialog=dialog;
}

234
/*
Simon Morlat's avatar
Simon Morlat committed
235 236
 * Server transaction
 */
237

238 239 240
static void server_transaction_destroy(belle_sip_server_transaction_t *t){
}

Simon Morlat's avatar
Simon Morlat committed
241

242
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_server_transaction_t);
243
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_server_transaction_t)
Simon Morlat's avatar
Simon Morlat committed
244
	{
Simon Morlat's avatar
Simon Morlat committed
245 246 247 248 249
		{
			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
250 251 252
		},
		NULL
	}
253
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END
Simon Morlat's avatar
Simon Morlat committed
254

255
void belle_sip_server_transaction_init(belle_sip_server_transaction_t *t, belle_sip_provider_t *prov,belle_sip_request_t *req){
256
	const char *branch;
257
	belle_sip_header_via_t *via=BELLE_SIP_HEADER_VIA(belle_sip_message_get_header((belle_sip_message_t*)req,"via"));
258
	branch=belle_sip_header_via_get_branch(via);
259
	if (branch==NULL || strncmp(branch,BELLE_SIP_BRANCH_MAGIC_COOKIE,strlen(BELLE_SIP_BRANCH_MAGIC_COOKIE))!=0){
260
		branch=req->rfc2543_branch;
261
		if (branch==NULL) belle_sip_fatal("No computed branch for RFC2543 style of message, this should never happen.");
262 263
	}
	t->base.branch_id=belle_sip_strdup(branch);
264
	belle_sip_transaction_init((belle_sip_transaction_t*)t,prov,req);
265
	belle_sip_random_token(t->to_tag,sizeof(t->to_tag));
266 267
}

Simon Morlat's avatar
Simon Morlat committed
268
void belle_sip_server_transaction_send_response(belle_sip_server_transaction_t *t, belle_sip_response_t *resp){
269
	belle_sip_transaction_t *base=(belle_sip_transaction_t*)t;
270
	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
271
	belle_sip_dialog_t *dialog=base->dialog;
Simon Morlat's avatar
Simon Morlat committed
272
	int status_code;
273

274 275
	belle_sip_object_ref(resp);
	if (!base->last_response){
jehan's avatar
jehan committed
276
		belle_sip_hop_t* hop=belle_sip_response_get_return_hop(resp);
277
		base->channel=belle_sip_provider_get_channel(base->provider,hop);
jehan's avatar
jehan committed
278
		belle_sip_object_unref(hop);
279 280 281 282 283
		if (!base->channel){
			belle_sip_error("Transaction [%p]: No channel available for sending response.",t);
			return;
		}
		belle_sip_object_ref(base->channel);
284
		belle_sip_channel_add_listener(base->channel, BELLE_SIP_CHANNEL_LISTENER(t));
285
	}
Simon Morlat's avatar
Simon Morlat committed
286 287 288 289 290 291
	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
292 293 294 295 296 297
		/*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
298 299
			belle_sip_response_fill_for_dialog(resp,base->request);
		}
300
	}
301 302 303 304 305
	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
306
	if (dialog)
jehan's avatar
jehan committed
307
		belle_sip_dialog_update(dialog,BELLE_SIP_TRANSACTION(t),TRUE);
308 309
}

310 311 312
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
313
	event.source=(belle_sip_object_t*)t->base.provider;
314 315 316
	event.server_transaction=t;
	event.dialog=dialog;
	event.request=req;
jehan's avatar
jehan committed
317
	BELLE_SIP_PROVIDER_INVOKE_LISTENERS_FOR_TRANSACTION(((belle_sip_transaction_t*) t),process_request_event,&event);
318 319
}

Simon Morlat's avatar
Simon Morlat committed
320 321 322
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){
323 324 325
		/*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;
326 327
			if (belle_sip_ist_process_ack(ist,(belle_sip_message_t*)req)==0){
				belle_sip_dialog_t *dialog=t->base.dialog;
328 329 330 331
				if (dialog && belle_sip_dialog_handle_ack(dialog,req)==0)
					server_transaction_notify(t,req,dialog);
				/*else nothing to do because retransmission of ACK*/

332
			}
333 334 335
		}else{
			belle_sip_warning("ACK received for non-invite server transaction ?");
		}
Simon Morlat's avatar
Simon Morlat committed
336
	}else if (strcmp(method,"CANCEL")==0){
337
		server_transaction_notify(t,req,t->base.dialog);
Simon Morlat's avatar
Simon Morlat committed
338 339
	}else
		BELLE_SIP_OBJECT_VPTR(t,belle_sip_server_transaction_t)->on_request_retransmission(t);
Simon Morlat's avatar
Simon Morlat committed
340
}
341

Simon Morlat's avatar
Simon Morlat committed
342 343 344 345
/*
 * client transaction
 */

346

347

348
belle_sip_request_t * belle_sip_client_transaction_create_cancel(belle_sip_client_transaction_t *t){
349 350 351 352 353 354 355
	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;
	}
356
	if (t->base.state!=BELLE_SIP_TRANSACTION_PROCEEDING){
357 358
		belle_sip_error("belle_sip_client_transaction_create_cancel() can only be used in state BELLE_SIP_TRANSACTION_PROCEEDING"
		               " but current transaction state is %s",belle_sip_transaction_state_to_string(t->base.state));
359
		return NULL;
360 361 362
	}
	req=belle_sip_request_new();
	belle_sip_request_set_method(req,"CANCEL");
363 364 365 366 367 368 369 370 371 372
/*	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.*/
373
	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)));
374 375 376 377 378
	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
379
	belle_sip_util_copy_headers(orig,(belle_sip_message_t*)req,BELLE_SIP_MAX_FORWARDS,FALSE);
380 381 382 383 384
	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;
385
}
Simon Morlat's avatar
Simon Morlat committed
386

387

388
int belle_sip_client_transaction_send_request(belle_sip_client_transaction_t *t){
389
	return belle_sip_client_transaction_send_request_to(t,NULL);
390

391
}
392

393
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
394
	belle_sip_channel_t *chan;
Simon Morlat's avatar
Simon Morlat committed
395
	belle_sip_provider_t *prov=t->base.provider;
396
	belle_sip_dialog_t *dialog=t->base.dialog;
397
	belle_sip_request_t *req=t->base.request;
jehan's avatar
jehan committed
398
	int result=-1;
399

Simon Morlat's avatar
Simon Morlat committed
400 401
	if (t->base.state!=BELLE_SIP_TRANSACTION_INIT){
		belle_sip_error("belle_sip_client_transaction_send_request: bad state.");
402
		return -1;
Simon Morlat's avatar
Simon Morlat committed
403
	}
404

jehan's avatar
jehan committed
405 406 407 408 409
	/*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
410
	/*store preset route for future use by refresher*/
411 412 413 414
	if (outbound_proxy){
		t->preset_route=outbound_proxy;
		belle_sip_object_ref(t->preset_route);
	}
415

416 417 418 419 420 421
	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){
422
		/*this request was created by belle_sip_dialog_create_queued_request().*/
423 424 425 426 427 428 429 430 431
		
		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;
		}
		
432
		if (belle_sip_dialog_request_pending(dialog) || dialog->queued_ct!=NULL){
433
			/*it cannot be sent immediately, queue the transaction into dialog*/
434 435
			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);
436 437 438
			belle_sip_dialog_queue_client_transaction(dialog,t);
			return 0;
		}
439
		belle_sip_dialog_update_request(dialog,req);
440
	}
441

442 443 444
	if (dialog){
		belle_sip_dialog_update(dialog,(belle_sip_transaction_t*)t,BELLE_SIP_OBJECT_IS_INSTANCE_OF(t,belle_sip_server_transaction_t));
	}
445

446
	if (!t->next_hop) {
447 448
		if (t->preset_route) {
			t->next_hop=belle_sip_hop_new_from_uri(t->preset_route);
449
		} else {
Simon Morlat's avatar
Simon Morlat committed
450
			t->next_hop = belle_sip_stack_get_next_hop(prov->stack,t->base.request);
451
		}
Simon Morlat's avatar
Simon Morlat committed
452
		belle_sip_object_ref(t->next_hop);
453
	} else {
454
		/*next hop already preset, probably in case of CANCEL*/
455
	}
jehan's avatar
jehan committed
456
	belle_sip_provider_add_client_transaction(t->base.provider,t); /*add it in any case*/
457
	chan=belle_sip_provider_get_channel(prov,t->next_hop);
Simon Morlat's avatar
Simon Morlat committed
458
	if (chan){
Simon Morlat's avatar
Simon Morlat committed
459
		belle_sip_object_ref(chan);
Simon Morlat's avatar
Simon Morlat committed
460 461
		belle_sip_channel_add_listener(chan,BELLE_SIP_CHANNEL_LISTENER(t));
		t->base.channel=chan;
462
		if (belle_sip_channel_get_state(chan)==BELLE_SIP_CHANNEL_INIT){
Simon Morlat's avatar
Simon Morlat committed
463
			belle_sip_message("belle_sip_client_transaction_send_request(): waiting channel to be ready");
464 465
			belle_sip_channel_prepare(chan);
			/*the channel will notify us when it is ready*/
466
		} else if (belle_sip_channel_get_state(chan)==BELLE_SIP_CHANNEL_READY){
467
			/*otherwise we can send immediately*/
468
			BELLE_SIP_OBJECT_VPTR(t,belle_sip_client_transaction_t)->send_request(t);
Simon Morlat's avatar
Simon Morlat committed
469
		}
jehan's avatar
jehan committed
470 471 472 473 474 475 476
		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
477
}
478

jehan's avatar
jehan committed
479 480 481 482
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);
483
	return status_code>=101 && status_code<300 && (strcmp(method,"INVITE")==0 || strcmp(method,"SUBSCRIBE")==0);
jehan's avatar
jehan committed
484
}
485

486
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
487
	belle_sip_transaction_t *base=(belle_sip_transaction_t*)t;
jehan's avatar
jehan committed
488 489
	belle_sip_request_t* req = belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(t));
	const char* method = belle_sip_request_get_method(req);
490
	belle_sip_response_event_t event;
Simon Morlat's avatar
Simon Morlat committed
491
	belle_sip_dialog_t *dialog=base->dialog;
492
	int status_code =  belle_sip_response_get_status_code(resp);
493 494
	if (base->last_response)
		belle_sip_object_unref(base->last_response);
jehan's avatar
jehan committed
495
	base->last_response=(belle_sip_response_t*)belle_sip_object_ref(resp);
496

Simon Morlat's avatar
Simon Morlat committed
497
	if (dialog){
498
		if (status_code>=101 && status_code<300
jehan's avatar
jehan committed
499 500
			&& strcmp(method,"INVITE")==0
			&& (dialog->state==BELLE_SIP_DIALOG_EARLY || dialog->state==BELLE_SIP_DIALOG_CONFIRMED)){
Simon Morlat's avatar
Simon Morlat committed
501 502
			/*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)){
503 504 505 506 507
				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
508 509
			}
		}
jehan's avatar
jehan committed
510
	} else if (should_dialog_be_created(t,resp)) {
jehan's avatar
jehan committed
511
		dialog=belle_sip_provider_create_dialog_internal(t->base.provider,BELLE_SIP_TRANSACTION(t),FALSE);
Simon Morlat's avatar
Simon Morlat committed
512
	}
jehan's avatar
jehan committed
513

jehan's avatar
jehan committed
514
	if (dialog && belle_sip_dialog_update(dialog,BELLE_SIP_TRANSACTION(t),FALSE)) {
jehan's avatar
jehan committed
515
		/* retransmition, just return*/
516
		belle_sip_message("Response [%p] absorbed by dialog [%p], skipped from transaction layer.",resp,dialog);
jehan's avatar
jehan committed
517 518
		return;
	}
jehan's avatar
jehan committed
519

Simon Morlat's avatar
Simon Morlat committed
520
	event.source=(belle_sip_object_t*)base->provider;
521
	event.client_transaction=t;
Simon Morlat's avatar
Simon Morlat committed
522
	event.dialog=dialog;
523
	event.response=(belle_sip_response_t*)resp;
jehan's avatar
jehan committed
524
	BELLE_SIP_PROVIDER_INVOKE_LISTENERS_FOR_TRANSACTION(((belle_sip_transaction_t*)t),process_response_event,&event);
jehan's avatar
jehan committed
525
	/*check that 200Ok for INVITEs have been acknowledged by listener*/
526
	if (dialog && status_code>=200 && status_code<300 && strcmp(method,"INVITE")==0){
jehan's avatar
jehan committed
527
		belle_sip_dialog_check_ack_sent(dialog);
528 529 530 531 532
	}
	/*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);
	}
533 534 535 536 537
}


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
538 539
}

540 541 542 543
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
544
static void client_transaction_destroy(belle_sip_client_transaction_t *t ){
jehan's avatar
jehan committed
545
	if (t->preset_route) belle_sip_object_unref(t->preset_route);
Simon Morlat's avatar
Simon Morlat committed
546
	if (t->next_hop) belle_sip_object_unref(t->next_hop);
Simon Morlat's avatar
Simon Morlat committed
547 548
}

Simon Morlat's avatar
Simon Morlat committed
549

Simon Morlat's avatar
Simon Morlat committed
550

551
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_client_transaction_t);
552
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_client_transaction_t)
Simon Morlat's avatar
Simon Morlat committed
553
	{
Simon Morlat's avatar
Simon Morlat committed
554 555 556 557 558 559
		{
			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
560 561 562 563
		NULL
	},
	NULL,
	NULL
564
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END
Simon Morlat's avatar
Simon Morlat committed
565

Simon Morlat's avatar
Simon Morlat committed
566
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
567
	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
568
	char token[BELLE_SIP_BRANCH_ID_LENGTH];
569 570 571 572

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

574 575
	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
576 577
		belle_sip_header_via_set_branch(via,obj->base.branch_id);
	}else{
578
		obj->base.branch_id=belle_sip_strdup(belle_sip_header_via_get_branch(via));
Simon Morlat's avatar
Simon Morlat committed
579
	}
Simon Morlat's avatar
Simon Morlat committed
580
	belle_sip_transaction_init((belle_sip_transaction_t*)obj, prov,req);
581 582
}

jehan's avatar
jehan committed
583
belle_sip_refresher_t* belle_sip_client_transaction_create_refresher(belle_sip_client_transaction_t *t) {
584
	return belle_sip_refresher_new(t);
jehan's avatar
jehan committed
585
}
586

587
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) {
588 589
	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
590 591
	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);
592 593
	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
594
		belle_sip_error("Invalid state [%s] for transaction [%p], should be BELLE_SIP_TRANSACTION_COMPLETED | BELLE_SIP_TRANSACTION_TERMINATED"
jehan's avatar
jehan committed
595 596
					,belle_sip_transaction_state_to_string(belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(t)))
					,t);
597
		belle_sip_object_unref(req);
jehan's avatar
jehan committed
598 599 600 601 602
		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);
603

jehan's avatar
jehan committed
604
	/*put auth header*/
605
	belle_sip_provider_add_authorization(t->base.provider,req,t->base.last_response,NULL,auth_infos,realm);
jehan's avatar
jehan committed
606 607
	return req;
}
608

609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659
/*
 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;
	
}