transaction.c 26.6 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 140 141 142 143 144 145 146 147 148 149 150 151 152 153
void *belle_sip_transaction_get_application_data(const belle_sip_transaction_t *t){
	return t->appdata;
}

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

jehan's avatar
jehan committed
155 156 157 158 159 160 161 162 163 164 165
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;
	}
}
166

167
void belle_sip_transaction_terminate(belle_sip_transaction_t *t){
168
	if (belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(t))!=BELLE_SIP_TRANSACTION_TERMINATED) {
169
		int is_client=BELLE_SIP_OBJECT_IS_INSTANCE_OF(t,belle_sip_client_transaction_t);
170
		belle_sip_transaction_set_state(t,BELLE_SIP_TRANSACTION_TERMINATED);
171 172 173 174 175 176
		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":""
177 178 179
									,belle_sip_request_get_method(belle_sip_transaction_get_request(t))
									,t);
		BELLE_SIP_OBJECT_VPTR(t,belle_sip_transaction_t)->on_terminate(t);
180
		belle_sip_provider_set_transaction_terminated(t->provider,t);
181
	}
182 183
}

jehan's avatar
jehan committed
184
belle_sip_request_t *belle_sip_transaction_get_request(const belle_sip_transaction_t *t){
185 186
	return t->request;
}
187 188 189
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
190 191

void belle_sip_transaction_notify_timeout(belle_sip_transaction_t *t){
192
	/*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
193
	 * Otherwise it will report the error.
194
	 * We limit this dead channel reporting to REGISTER transactions, who are unlikely to be unresponded.
Simon Morlat's avatar
Simon Morlat committed
195
	**/
196
	belle_sip_object_ref(t);  /*take a ref in the case where the app calls belle_sip_transaction_terminate() within the timeout listener*/
197 198 199 200 201
	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;
		}
202 203 204 205
	}else {
		notify_timeout(t);
		belle_sip_transaction_terminate(t);
	}
206
	belle_sip_object_unref(t);
Simon Morlat's avatar
Simon Morlat committed
207 208
}

jehan's avatar
jehan committed
209 210
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
211 212
}

213 214 215 216 217
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
218
void belle_sip_transaction_set_dialog(belle_sip_transaction_t *t, belle_sip_dialog_t *dialog){
219
	if (t->dialog==dialog) return;
220 221
	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
222 223 224
	t->dialog=dialog;
}

225
/*
Simon Morlat's avatar
Simon Morlat committed
226 227
 * Server transaction
 */
228

229 230 231
static void server_transaction_destroy(belle_sip_server_transaction_t *t){
}

Simon Morlat's avatar
Simon Morlat committed
232

233
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_server_transaction_t);
234
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_server_transaction_t)
Simon Morlat's avatar
Simon Morlat committed
235
	{
Simon Morlat's avatar
Simon Morlat committed
236 237 238 239 240
		{
			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
241 242 243
		},
		NULL
	}
244
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END
Simon Morlat's avatar
Simon Morlat committed
245

246
void belle_sip_server_transaction_init(belle_sip_server_transaction_t *t, belle_sip_provider_t *prov,belle_sip_request_t *req){
247
	const char *branch;
248
	belle_sip_header_via_t *via=BELLE_SIP_HEADER_VIA(belle_sip_message_get_header((belle_sip_message_t*)req,"via"));
249
	branch=belle_sip_header_via_get_branch(via);
250
	if (branch==NULL || strncmp(branch,BELLE_SIP_BRANCH_MAGIC_COOKIE,strlen(BELLE_SIP_BRANCH_MAGIC_COOKIE))!=0){
251
		branch=req->rfc2543_branch;
252
		if (branch==NULL) belle_sip_fatal("No computed branch for RFC2543 style of message, this should never happen.");
253 254
	}
	t->base.branch_id=belle_sip_strdup(branch);
255
	belle_sip_transaction_init((belle_sip_transaction_t*)t,prov,req);
256
	belle_sip_random_token(t->to_tag,sizeof(t->to_tag));
257 258
}

Simon Morlat's avatar
Simon Morlat committed
259
void belle_sip_server_transaction_send_response(belle_sip_server_transaction_t *t, belle_sip_response_t *resp){
260
	belle_sip_transaction_t *base=(belle_sip_transaction_t*)t;
261
	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
262
	belle_sip_dialog_t *dialog=base->dialog;
Simon Morlat's avatar
Simon Morlat committed
263
	int status_code;
264

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

301 302 303
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
304
	event.source=(belle_sip_object_t*)t->base.provider;
305 306 307
	event.server_transaction=t;
	event.dialog=dialog;
	event.request=req;
jehan's avatar
jehan committed
308
	BELLE_SIP_PROVIDER_INVOKE_LISTENERS_FOR_TRANSACTION(((belle_sip_transaction_t*) t),process_request_event,&event);
309 310
}

Simon Morlat's avatar
Simon Morlat committed
311 312 313
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){
314 315 316
		/*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;
317 318
			if (belle_sip_ist_process_ack(ist,(belle_sip_message_t*)req)==0){
				belle_sip_dialog_t *dialog=t->base.dialog;
319 320 321 322
				if (dialog && belle_sip_dialog_handle_ack(dialog,req)==0)
					server_transaction_notify(t,req,dialog);
				/*else nothing to do because retransmission of ACK*/

323
			}
324 325 326
		}else{
			belle_sip_warning("ACK received for non-invite server transaction ?");
		}
Simon Morlat's avatar
Simon Morlat committed
327
	}else if (strcmp(method,"CANCEL")==0){
328
		server_transaction_notify(t,req,t->base.dialog);
Simon Morlat's avatar
Simon Morlat committed
329 330
	}else
		BELLE_SIP_OBJECT_VPTR(t,belle_sip_server_transaction_t)->on_request_retransmission(t);
Simon Morlat's avatar
Simon Morlat committed
331
}
332

Simon Morlat's avatar
Simon Morlat committed
333 334 335 336
/*
 * client transaction
 */

337

338

339
belle_sip_request_t * belle_sip_client_transaction_create_cancel(belle_sip_client_transaction_t *t){
340 341 342 343 344 345 346
	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;
	}
347
	if (t->base.state!=BELLE_SIP_TRANSACTION_PROCEEDING){
348 349
		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));
350
		return NULL;
351 352 353
	}
	req=belle_sip_request_new();
	belle_sip_request_set_method(req,"CANCEL");
354 355 356 357 358 359 360 361 362 363
/*	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.*/
364
	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)));
365 366 367 368 369
	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
370
	belle_sip_util_copy_headers(orig,(belle_sip_message_t*)req,BELLE_SIP_MAX_FORWARDS,FALSE);
371 372 373 374 375
	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;
376
}
Simon Morlat's avatar
Simon Morlat committed
377

378

379
int belle_sip_client_transaction_send_request(belle_sip_client_transaction_t *t){
380
	return belle_sip_client_transaction_send_request_to(t,NULL);
381

382
}
383

384
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
385
	belle_sip_channel_t *chan;
Simon Morlat's avatar
Simon Morlat committed
386
	belle_sip_provider_t *prov=t->base.provider;
387
	belle_sip_dialog_t *dialog=t->base.dialog;
388
	belle_sip_request_t *req=t->base.request;
jehan's avatar
jehan committed
389
	int result=-1;
390

Simon Morlat's avatar
Simon Morlat committed
391 392
	if (t->base.state!=BELLE_SIP_TRANSACTION_INIT){
		belle_sip_error("belle_sip_client_transaction_send_request: bad state.");
393
		return -1;
Simon Morlat's avatar
Simon Morlat committed
394
	}
395

jehan's avatar
jehan committed
396 397 398 399 400
	/*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
401
	/*store preset route for future use by refresher*/
402 403 404 405
	if (outbound_proxy){
		t->preset_route=outbound_proxy;
		belle_sip_object_ref(t->preset_route);
	}
406

407 408 409 410 411 412
	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){
413
		/*this request was created by belle_sip_dialog_create_queued_request().*/
414 415 416 417 418 419 420 421 422
		
		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;
		}
		
423
		if (belle_sip_dialog_request_pending(dialog) || dialog->queued_ct!=NULL){
424
			/*it cannot be sent immediately, queue the transaction into dialog*/
425 426
			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);
427 428 429
			belle_sip_dialog_queue_client_transaction(dialog,t);
			return 0;
		}
430
		belle_sip_dialog_update_request(dialog,req);
431
	}
432

433 434 435
	if (dialog){
		belle_sip_dialog_update(dialog,(belle_sip_transaction_t*)t,BELLE_SIP_OBJECT_IS_INSTANCE_OF(t,belle_sip_server_transaction_t));
	}
436

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

jehan's avatar
jehan committed
470 471 472 473
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);
474
	return status_code>=101 && status_code<300 && (strcmp(method,"INVITE")==0 || strcmp(method,"SUBSCRIBE")==0);
jehan's avatar
jehan committed
475
}
476

477
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
478
	belle_sip_transaction_t *base=(belle_sip_transaction_t*)t;
jehan's avatar
jehan committed
479 480
	belle_sip_request_t* req = belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(t));
	const char* method = belle_sip_request_get_method(req);
481
	belle_sip_response_event_t event;
Simon Morlat's avatar
Simon Morlat committed
482
	belle_sip_dialog_t *dialog=base->dialog;
483
	int status_code =  belle_sip_response_get_status_code(resp);
484 485
	if (base->last_response)
		belle_sip_object_unref(base->last_response);
jehan's avatar
jehan committed
486
	base->last_response=(belle_sip_response_t*)belle_sip_object_ref(resp);
487

Simon Morlat's avatar
Simon Morlat committed
488
	if (dialog){
489
		if (status_code>=101 && status_code<300
jehan's avatar
jehan committed
490 491
			&& strcmp(method,"INVITE")==0
			&& (dialog->state==BELLE_SIP_DIALOG_EARLY || dialog->state==BELLE_SIP_DIALOG_CONFIRMED)){
Simon Morlat's avatar
Simon Morlat committed
492 493
			/*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)){
494 495 496 497 498
				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
499 500
			}
		}
jehan's avatar
jehan committed
501
	} else if (should_dialog_be_created(t,resp)) {
jehan's avatar
jehan committed
502
		dialog=belle_sip_provider_create_dialog_internal(t->base.provider,BELLE_SIP_TRANSACTION(t),FALSE);
Simon Morlat's avatar
Simon Morlat committed
503
	}
jehan's avatar
jehan committed
504

jehan's avatar
jehan committed
505
	if (dialog && belle_sip_dialog_update(dialog,BELLE_SIP_TRANSACTION(t),FALSE)) {
jehan's avatar
jehan committed
506
		/* retransmition, just return*/
507
		belle_sip_message("Response [%p] absorbed by dialog [%p], skipped from transaction layer.",resp,dialog);
jehan's avatar
jehan committed
508 509
		return;
	}
jehan's avatar
jehan committed
510

Simon Morlat's avatar
Simon Morlat committed
511
	event.source=(belle_sip_object_t*)base->provider;
512
	event.client_transaction=t;
Simon Morlat's avatar
Simon Morlat committed
513
	event.dialog=dialog;
514
	event.response=(belle_sip_response_t*)resp;
jehan's avatar
jehan committed
515
	BELLE_SIP_PROVIDER_INVOKE_LISTENERS_FOR_TRANSACTION(((belle_sip_transaction_t*)t),process_response_event,&event);
jehan's avatar
jehan committed
516
	/*check that 200Ok for INVITEs have been acknowledged by listener*/
517
	if (dialog && status_code>=200 && status_code<300 && strcmp(method,"INVITE")==0){
jehan's avatar
jehan committed
518
		belle_sip_dialog_check_ack_sent(dialog);
519 520 521 522 523
	}
	/*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);
	}
524 525 526 527 528
}


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
529 530
}

531 532 533 534
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
535
static void client_transaction_destroy(belle_sip_client_transaction_t *t ){
jehan's avatar
jehan committed
536
	if (t->preset_route) belle_sip_object_unref(t->preset_route);
Simon Morlat's avatar
Simon Morlat committed
537
	if (t->next_hop) belle_sip_object_unref(t->next_hop);
Simon Morlat's avatar
Simon Morlat committed
538 539
}

Simon Morlat's avatar
Simon Morlat committed
540

Simon Morlat's avatar
Simon Morlat committed
541

542
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_client_transaction_t);
543
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_client_transaction_t)
Simon Morlat's avatar
Simon Morlat committed
544
	{
Simon Morlat's avatar
Simon Morlat committed
545 546 547 548 549 550
		{
			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
551 552 553 554
		NULL
	},
	NULL,
	NULL
555
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END
Simon Morlat's avatar
Simon Morlat committed
556

Simon Morlat's avatar
Simon Morlat committed
557
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
558
	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
559
	char token[BELLE_SIP_BRANCH_ID_LENGTH];
560 561 562 563

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

565 566
	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
567 568
		belle_sip_header_via_set_branch(via,obj->base.branch_id);
	}else{
569
		obj->base.branch_id=belle_sip_strdup(belle_sip_header_via_get_branch(via));
Simon Morlat's avatar
Simon Morlat committed
570
	}
Simon Morlat's avatar
Simon Morlat committed
571
	belle_sip_transaction_init((belle_sip_transaction_t*)obj, prov,req);
572 573
}

jehan's avatar
jehan committed
574
belle_sip_refresher_t* belle_sip_client_transaction_create_refresher(belle_sip_client_transaction_t *t) {
575
	return belle_sip_refresher_new(t);
jehan's avatar
jehan committed
576
}
577

578
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) {
579 580
	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
581 582
	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);
583 584
	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
585
		belle_sip_error("Invalid state [%s] for transaction [%p], should be BELLE_SIP_TRANSACTION_COMPLETED | BELLE_SIP_TRANSACTION_TERMINATED"
jehan's avatar
jehan committed
586 587
					,belle_sip_transaction_state_to_string(belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(t)))
					,t);
588
		belle_sip_object_unref(req);
jehan's avatar
jehan committed
589 590 591 592 593
		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);
594

jehan's avatar
jehan committed
595
	/*put auth header*/
596
	belle_sip_provider_add_authorization(t->base.provider,req,t->base.last_response,NULL,auth_infos,realm);
jehan's avatar
jehan committed
597 598
	return req;
}
599

600 601 602 603 604 605 606 607 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
/*
 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;
	
}