transaction.c 23.8 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);
jehan's avatar
jehan committed
69

70
}
71

72
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_transaction_t);
Simon Morlat's avatar
Simon Morlat committed
73

74
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_transaction_t)
Simon Morlat's avatar
Simon Morlat committed
75
	{
Simon Morlat's avatar
Simon Morlat committed
76 77 78
		BELLE_SIP_VPTR_INIT(belle_sip_transaction_t,belle_sip_object_t,FALSE),
		(belle_sip_object_destroy_t) transaction_destroy,
		NULL,/*no clone*/
79
		NULL,/*no marshal*/
Simon Morlat's avatar
Simon Morlat committed
80 81
	},
	NULL /*on_terminate*/
82
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END
Simon Morlat's avatar
Simon Morlat committed
83

84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
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;
}
99

jehan's avatar
jehan committed
100 101 102 103 104 105 106 107 108 109 110
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;
	}
}
111

112
void belle_sip_transaction_terminate(belle_sip_transaction_t *t){
113 114 115 116 117 118 119
	if (belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(t))!=BELLE_SIP_TRANSACTION_TERMINATED) {
		belle_sip_transaction_set_state(t,BELLE_SIP_TRANSACTION_TERMINATED);
		belle_sip_message("%s%s %s transaction [%p] terminated"	,BELLE_SIP_OBJECT_IS_INSTANCE_OF(t,belle_sip_client_transaction_t)?"Client":"Server"
									,t->is_internal?" internal":""
									,belle_sip_request_get_method(belle_sip_transaction_get_request(t))
									,t);
		BELLE_SIP_OBJECT_VPTR(t,belle_sip_transaction_t)->on_terminate(t);
120
		belle_sip_provider_set_transaction_terminated(t->provider,t);
121
	}
122 123
}

jehan's avatar
jehan committed
124
belle_sip_request_t *belle_sip_transaction_get_request(const belle_sip_transaction_t *t){
125 126
	return t->request;
}
127 128 129
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
130 131

static void notify_timeout(belle_sip_transaction_t *t){
Simon Morlat's avatar
Simon Morlat committed
132
	belle_sip_timeout_event_t ev;
Simon Morlat's avatar
Simon Morlat committed
133
	ev.source=(belle_sip_object_t*)t->provider;
Simon Morlat's avatar
Simon Morlat committed
134 135
	ev.transaction=t;
	ev.is_server_transaction=BELLE_SIP_OBJECT_IS_INSTANCE_OF(t,belle_sip_server_transaction_t);
jehan's avatar
jehan committed
136 137 138
	BELLE_SIP_PROVIDER_INVOKE_LISTENERS_FOR_TRANSACTION(t,process_timeout,&ev);
}

Simon Morlat's avatar
Simon Morlat committed
139
void belle_sip_transaction_notify_timeout(belle_sip_transaction_t *t){
140
	/*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
141
	 * Otherwise it will report the error.
142
	 * We limit this dead channel reporting to REGISTER transactions, who are unlikely to be unresponded.
Simon Morlat's avatar
Simon Morlat committed
143
	**/
144

145

146 147 148 149 150
	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;
		}
151 152 153 154
	}else {
		notify_timeout(t);
		belle_sip_transaction_terminate(t);
	}
Simon Morlat's avatar
Simon Morlat committed
155 156
}

jehan's avatar
jehan committed
157 158
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
159 160
}

161 162 163 164 165
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
166
void belle_sip_transaction_set_dialog(belle_sip_transaction_t *t, belle_sip_dialog_t *dialog){
167
	if (t->dialog==dialog) return;
168 169
	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
170 171 172
	t->dialog=dialog;
}

173
/*
Simon Morlat's avatar
Simon Morlat committed
174 175
 * Server transaction
 */
176

177 178 179
static void server_transaction_destroy(belle_sip_server_transaction_t *t){
}

Simon Morlat's avatar
Simon Morlat committed
180

181
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_server_transaction_t);
182
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_server_transaction_t)
Simon Morlat's avatar
Simon Morlat committed
183
	{
Simon Morlat's avatar
Simon Morlat committed
184 185 186 187 188
		{
			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
189 190 191
		},
		NULL
	}
192
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END
Simon Morlat's avatar
Simon Morlat committed
193

194
void belle_sip_server_transaction_init(belle_sip_server_transaction_t *t, belle_sip_provider_t *prov,belle_sip_request_t *req){
195
	const char *branch;
196
	belle_sip_header_via_t *via=BELLE_SIP_HEADER_VIA(belle_sip_message_get_header((belle_sip_message_t*)req,"via"));
197
	branch=belle_sip_header_via_get_branch(via);
198
	if (branch==NULL || strncmp(branch,BELLE_SIP_BRANCH_MAGIC_COOKIE,strlen(BELLE_SIP_BRANCH_MAGIC_COOKIE))!=0){
199
		branch=req->rfc2543_branch;
200
		if (branch==NULL) belle_sip_fatal("No computed branch for RFC2543 style of message, this should never happen.");
201 202
	}
	t->base.branch_id=belle_sip_strdup(branch);
203
	belle_sip_transaction_init((belle_sip_transaction_t*)t,prov,req);
204
	belle_sip_random_token(t->to_tag,sizeof(t->to_tag));
205 206
}

Simon Morlat's avatar
Simon Morlat committed
207
void belle_sip_server_transaction_send_response(belle_sip_server_transaction_t *t, belle_sip_response_t *resp){
208
	belle_sip_transaction_t *base=(belle_sip_transaction_t*)t;
209
	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
210
	belle_sip_dialog_t *dialog=base->dialog;
Simon Morlat's avatar
Simon Morlat committed
211
	int status_code;
212

213 214
	belle_sip_object_ref(resp);
	if (!base->last_response){
jehan's avatar
jehan committed
215
		belle_sip_hop_t* hop=belle_sip_response_get_return_hop(resp);
216
		base->channel=belle_sip_provider_get_channel(base->provider,hop);
jehan's avatar
jehan committed
217
		belle_sip_object_unref(hop);
218 219 220 221 222
		if (!base->channel){
			belle_sip_error("Transaction [%p]: No channel available for sending response.",t);
			return;
		}
		belle_sip_object_ref(base->channel);
223
	}
Simon Morlat's avatar
Simon Morlat committed
224 225 226 227 228 229
	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
230 231 232 233 234 235
		/*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
236 237
			belle_sip_response_fill_for_dialog(resp,base->request);
		}
238
	}
239 240 241 242 243
	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
244
	if (dialog)
jehan's avatar
jehan committed
245
		belle_sip_dialog_update(dialog,BELLE_SIP_TRANSACTION(t),TRUE);
246 247
}

248 249 250
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
251
	event.source=(belle_sip_object_t*)t->base.provider;
252 253 254
	event.server_transaction=t;
	event.dialog=dialog;
	event.request=req;
jehan's avatar
jehan committed
255
	BELLE_SIP_PROVIDER_INVOKE_LISTENERS_FOR_TRANSACTION(((belle_sip_transaction_t*) t),process_request_event,&event);
256 257
}

Simon Morlat's avatar
Simon Morlat committed
258 259 260
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){
261 262 263
		/*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;
264 265
			if (belle_sip_ist_process_ack(ist,(belle_sip_message_t*)req)==0){
				belle_sip_dialog_t *dialog=t->base.dialog;
266 267 268 269
				if (dialog && belle_sip_dialog_handle_ack(dialog,req)==0)
					server_transaction_notify(t,req,dialog);
				/*else nothing to do because retransmission of ACK*/

270
			}
271 272 273
		}else{
			belle_sip_warning("ACK received for non-invite server transaction ?");
		}
Simon Morlat's avatar
Simon Morlat committed
274
	}else if (strcmp(method,"CANCEL")==0){
275
		server_transaction_notify(t,req,t->base.dialog);
Simon Morlat's avatar
Simon Morlat committed
276 277
	}else
		BELLE_SIP_OBJECT_VPTR(t,belle_sip_server_transaction_t)->on_request_retransmission(t);
Simon Morlat's avatar
Simon Morlat committed
278
}
279

Simon Morlat's avatar
Simon Morlat committed
280 281 282 283
/*
 * client transaction
 */

284

285

286
belle_sip_request_t * belle_sip_client_transaction_create_cancel(belle_sip_client_transaction_t *t){
287 288 289 290 291 292 293
	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;
	}
294
	if (t->base.state!=BELLE_SIP_TRANSACTION_PROCEEDING){
295 296
		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));
297
		return NULL;
298 299 300
	}
	req=belle_sip_request_new();
	belle_sip_request_set_method(req,"CANCEL");
301 302 303 304 305 306 307 308 309 310
/*	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.*/
311
	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)));
312 313 314 315 316
	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
317
	belle_sip_util_copy_headers(orig,(belle_sip_message_t*)req,BELLE_SIP_MAX_FORWARDS,FALSE);
318 319 320 321 322
	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;
323
}
Simon Morlat's avatar
Simon Morlat committed
324

325

326
int belle_sip_client_transaction_send_request(belle_sip_client_transaction_t *t){
327 328
	return belle_sip_client_transaction_send_request_to(t,NULL);
}
329

330
int belle_sip_client_transaction_send_request_to(belle_sip_client_transaction_t *t,belle_sip_uri_t* outbound_proxy) {
331 332 333
	return belle_sip_client_transaction_send_request_to_using_queue(t,NULL,TRUE);
}
int belle_sip_client_transaction_send_request_to_using_queue(belle_sip_client_transaction_t *t,belle_sip_uri_t* outbound_proxy,int use_queue) {
Simon Morlat's avatar
Simon Morlat committed
334
	belle_sip_channel_t *chan;
Simon Morlat's avatar
Simon Morlat committed
335
	belle_sip_provider_t *prov=t->base.provider;
336
	belle_sip_dialog_t *dialog=t->base.dialog;
jehan's avatar
jehan committed
337
	int result=-1;
338

Simon Morlat's avatar
Simon Morlat committed
339 340
	if (t->base.state!=BELLE_SIP_TRANSACTION_INIT){
		belle_sip_error("belle_sip_client_transaction_send_request: bad state.");
341
		return -1;
Simon Morlat's avatar
Simon Morlat committed
342
	}
343

jehan's avatar
jehan committed
344 345 346 347 348
	/*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
349
	/*store preset route for future use by refresher*/
350 351 352 353
	if (outbound_proxy){
		t->preset_route=outbound_proxy;
		belle_sip_object_ref(t->preset_route);
	}
354

355 356 357 358
	if (t->base.request->dialog_queued){
		/*this request was created by belle_sip_dialog_create_queued_request().*/
		if (belle_sip_dialog_request_pending(dialog)){
			/*it cannot be sent immediately, queue the transaction into dialog*/
359 360
			belle_sip_message("belle_sip_client_transaction_send_request(): transaction [%p], cannot send "
				"request now because dialog is busy, so queuing into dialog.",t);
361 362
			belle_sip_dialog_queue_client_transaction(dialog,t);
			return 0;
363 364 365 366 367 368 369 370 371 372 373
		/*queue is not empty, so we should NOT break order and go before queue events; take the latest request
		and store the current one. However when sending request from the queue itself, we should not
		check this again because it will reverse requests order. (eg. r1 is being sent (pending) and r2 is coming,
		thus we store it using upon test. then r3 is coming, and we store it again. then r1 is done, so dialog will
		try to unqueue earliest request, and if we do this check, it will revert order and send r3 instead of r3
		which is not the expected behavior and will actually break order.*/
		}else if (use_queue&&dialog->queued_ct != NULL) {
			belle_sip_message("belle_sip_client_transaction_send_request(): transaction [%p], cannot send current"
				" request now because there are already queued requests, so queuing this and sending the oldest one.",t);
			belle_sip_dialog_queue_client_transaction(dialog,t);
			dialog->queued_ct=belle_sip_list_pop_front(dialog->queued_ct,(void**)&t);
374
		}
375 376 377 378 379

		belle_sip_request_t *req=t->base.request;
		/*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);
380
	}
381

382 383 384
	if (dialog){
		belle_sip_dialog_update(dialog,(belle_sip_transaction_t*)t,BELLE_SIP_OBJECT_IS_INSTANCE_OF(t,belle_sip_server_transaction_t));
	}
385

386
	if (!t->next_hop) {
387 388
		if (t->preset_route) {
			t->next_hop=belle_sip_hop_new_from_uri(t->preset_route);
389
		} else {
Simon Morlat's avatar
Simon Morlat committed
390
			t->next_hop = belle_sip_stack_get_next_hop(prov->stack,t->base.request);
391
		}
Simon Morlat's avatar
Simon Morlat committed
392
		belle_sip_object_ref(t->next_hop);
393
	} else {
394
		/*next hop already preset, probably in case of CANCEL*/
395
	}
jehan's avatar
jehan committed
396
	belle_sip_provider_add_client_transaction(t->base.provider,t); /*add it in any case*/
397
	chan=belle_sip_provider_get_channel(prov,t->next_hop);
Simon Morlat's avatar
Simon Morlat committed
398
	if (chan){
Simon Morlat's avatar
Simon Morlat committed
399
		belle_sip_object_ref(chan);
Simon Morlat's avatar
Simon Morlat committed
400 401
		belle_sip_channel_add_listener(chan,BELLE_SIP_CHANNEL_LISTENER(t));
		t->base.channel=chan;
402
		if (belle_sip_channel_get_state(chan)==BELLE_SIP_CHANNEL_INIT){
Simon Morlat's avatar
Simon Morlat committed
403
			belle_sip_message("belle_sip_client_transaction_send_request(): waiting channel to be ready");
404 405
			belle_sip_channel_prepare(chan);
			/*the channel will notify us when it is ready*/
406
		} else if (belle_sip_channel_get_state(chan)==BELLE_SIP_CHANNEL_READY){
407
			/*otherwise we can send immediately*/
408
			BELLE_SIP_OBJECT_VPTR(t,belle_sip_client_transaction_t)->send_request(t);
Simon Morlat's avatar
Simon Morlat committed
409
		}
jehan's avatar
jehan committed
410 411 412 413 414 415 416
		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
417
}
418

jehan's avatar
jehan committed
419 420 421 422
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);
423
	return status_code>=101 && status_code<300 && (strcmp(method,"INVITE")==0 || strcmp(method,"SUBSCRIBE")==0);
jehan's avatar
jehan committed
424
}
425

426
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
427
	belle_sip_transaction_t *base=(belle_sip_transaction_t*)t;
jehan's avatar
jehan committed
428 429
	belle_sip_request_t* req = belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(t));
	const char* method = belle_sip_request_get_method(req);
430
	belle_sip_response_event_t event;
Simon Morlat's avatar
Simon Morlat committed
431
	belle_sip_dialog_t *dialog=base->dialog;
432
	int status_code =  belle_sip_response_get_status_code(resp);
433 434
	if (base->last_response)
		belle_sip_object_unref(base->last_response);
jehan's avatar
jehan committed
435
	base->last_response=(belle_sip_response_t*)belle_sip_object_ref(resp);
436

Simon Morlat's avatar
Simon Morlat committed
437
	if (dialog){
438
		if (status_code>=101 && status_code<300
jehan's avatar
jehan committed
439 440
			&& strcmp(method,"INVITE")==0
			&& (dialog->state==BELLE_SIP_DIALOG_EARLY || dialog->state==BELLE_SIP_DIALOG_CONFIRMED)){
Simon Morlat's avatar
Simon Morlat committed
441 442
			/*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)){
443 444 445 446 447
				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
448 449
			}
		}
jehan's avatar
jehan committed
450
	} else if (should_dialog_be_created(t,resp)) {
jehan's avatar
jehan committed
451
		dialog=belle_sip_provider_create_dialog_internal(t->base.provider,BELLE_SIP_TRANSACTION(t),FALSE);
Simon Morlat's avatar
Simon Morlat committed
452
	}
jehan's avatar
jehan committed
453

jehan's avatar
jehan committed
454
	if (dialog && belle_sip_dialog_update(dialog,BELLE_SIP_TRANSACTION(t),FALSE)) {
jehan's avatar
jehan committed
455
		/* retransmition, just return*/
456
		belle_sip_message("[%p] is a 200 ok retransmition on dialog [%p], skiping",resp,dialog);
jehan's avatar
jehan committed
457 458
		return;
	}
jehan's avatar
jehan committed
459

Simon Morlat's avatar
Simon Morlat committed
460
	event.source=(belle_sip_object_t*)base->provider;
461
	event.client_transaction=t;
Simon Morlat's avatar
Simon Morlat committed
462
	event.dialog=dialog;
463
	event.response=(belle_sip_response_t*)resp;
jehan's avatar
jehan committed
464
	BELLE_SIP_PROVIDER_INVOKE_LISTENERS_FOR_TRANSACTION(((belle_sip_transaction_t*)t),process_response_event,&event);
jehan's avatar
jehan committed
465 466 467
	/*check that 200Ok for INVITEs have been acknowledged by listener*/
	if (dialog && strcmp(method,"INVITE")==0)
		belle_sip_dialog_check_ack_sent(dialog);
468 469 470 471 472
}


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
473 474
}

475 476 477 478
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
479
static void client_transaction_destroy(belle_sip_client_transaction_t *t ){
jehan's avatar
jehan committed
480
	if (t->preset_route) belle_sip_object_unref(t->preset_route);
Simon Morlat's avatar
Simon Morlat committed
481
	if (t->next_hop) belle_sip_object_unref(t->next_hop);
Simon Morlat's avatar
Simon Morlat committed
482 483
}

Simon Morlat's avatar
Simon Morlat committed
484 485
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_client_transaction_t *t=(belle_sip_client_transaction_t*)l;
486
	belle_sip_io_error_event_t ev;
487
	belle_sip_transaction_state_t tr_state=belle_sip_transaction_get_state((belle_sip_transaction_t*)t);
488

jehan's avatar
jehan committed
489 490 491
	belle_sip_message("transaction [%p] channel state changed to [%s]"
						,t
						,belle_sip_channel_state_to_string(state));
Simon Morlat's avatar
Simon Morlat committed
492 493
	switch(state){
		case BELLE_SIP_CHANNEL_READY:
494 495 496
			if (tr_state==BELLE_SIP_TRANSACTION_INIT){
				BELLE_SIP_OBJECT_VPTR(t,belle_sip_client_transaction_t)->send_request(t);
			}
Simon Morlat's avatar
Simon Morlat committed
497
		break;
498 499 500 501 502 503
		case BELLE_SIP_CHANNEL_DISCONNECTED:
		case BELLE_SIP_CHANNEL_ERROR:
			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;
504 505 506 507
			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) {
jehan's avatar
jehan committed
508 509
				BELLE_SIP_PROVIDER_INVOKE_LISTENERS_FOR_TRANSACTION(((belle_sip_transaction_t*)t),process_io_error,&ev);
			}
Simon Morlat's avatar
Simon Morlat committed
510 511
			if (t->base.timed_out)
				notify_timeout((belle_sip_transaction_t*)t);
512

513
			belle_sip_transaction_terminate(BELLE_SIP_TRANSACTION(t));
514
		break;
Simon Morlat's avatar
Simon Morlat committed
515 516 517 518
		default:
			/*ignored*/
		break;
	}
Simon Morlat's avatar
Simon Morlat committed
519 520
}

Simon Morlat's avatar
Simon Morlat committed
521 522 523 524 525 526 527
BELLE_SIP_IMPLEMENT_INTERFACE_BEGIN(belle_sip_client_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_client_transaction_t, belle_sip_channel_listener_t);
528
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_client_transaction_t)
Simon Morlat's avatar
Simon Morlat committed
529
	{
Simon Morlat's avatar
Simon Morlat committed
530 531 532 533 534 535
		{
			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
536 537 538 539
		NULL
	},
	NULL,
	NULL
540
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END
Simon Morlat's avatar
Simon Morlat committed
541

Simon Morlat's avatar
Simon Morlat committed
542
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
543
	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
544
	char token[BELLE_SIP_BRANCH_ID_LENGTH];
545 546 547 548

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

550 551
	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
552 553
		belle_sip_header_via_set_branch(via,obj->base.branch_id);
	}else{
554
		obj->base.branch_id=belle_sip_strdup(belle_sip_header_via_get_branch(via));
Simon Morlat's avatar
Simon Morlat committed
555
	}
Simon Morlat's avatar
Simon Morlat committed
556
	belle_sip_transaction_init((belle_sip_transaction_t*)obj, prov,req);
557 558
}

jehan's avatar
jehan committed
559
belle_sip_refresher_t* belle_sip_client_transaction_create_refresher(belle_sip_client_transaction_t *t) {
560
	return belle_sip_refresher_new(t);
jehan's avatar
jehan committed
561
}
562

563
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) {
564 565
	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
566 567
	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);
568 569
	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
570
		belle_sip_error("Invalid state [%s] for transaction [%p], should be BELLE_SIP_TRANSACTION_COMPLETED | BELLE_SIP_TRANSACTION_TERMINATED"
jehan's avatar
jehan committed
571 572
					,belle_sip_transaction_state_to_string(belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(t)))
					,t);
573
		belle_sip_object_unref(req);
jehan's avatar
jehan committed
574 575 576 577 578
		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);
579

jehan's avatar
jehan committed
580
	/*put auth header*/
581
	belle_sip_provider_add_authorization(t->base.provider,req,t->base.last_response,NULL,auth_infos,realm);
jehan's avatar
jehan committed
582 583
	return req;
}
584