ict.c 7.55 KB
Newer Older
Simon Morlat's avatar
Simon Morlat committed
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
Simon Morlat's avatar
Simon Morlat committed
8 9 10 11 12 13 14 15 16 17 18
    (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/>.
*/

19 20 21
/** 
 * INVITE client transaction implementation.
**/
Simon Morlat's avatar
Simon Morlat committed
22 23 24 25

#include "belle_sip_internal.h"


Simon Morlat's avatar
Simon Morlat committed
26
static void on_ict_terminate(belle_sip_ict_t *obj){
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
	belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj;
	if (obj->timer_A){
		belle_sip_transaction_stop_timer(base,obj->timer_A);
		belle_sip_object_unref(obj->timer_A);
		obj->timer_A=NULL;
	}
	if (obj->timer_B){
		belle_sip_transaction_stop_timer(base,obj->timer_B);
		belle_sip_object_unref(obj->timer_B);
		obj->timer_B=NULL;
	}
	if (obj->timer_D){
		belle_sip_transaction_stop_timer(base,obj->timer_D);
		belle_sip_object_unref(obj->timer_D);
		obj->timer_D=NULL;
	}
43 44 45 46 47
	if (obj->timer_M){
		belle_sip_transaction_stop_timer(base,obj->timer_M);
		belle_sip_object_unref(obj->timer_M);
		obj->timer_M=NULL;
	}
48 49 50 51 52 53
	if (obj->ack){
		belle_sip_object_unref(obj->ack);
		obj->ack=NULL;
	}
}

54 55 56 57
static void ict_destroy(belle_sip_ict_t *obj){
	on_ict_terminate(obj);
}

58 59 60 61
static belle_sip_request_t *make_ack(belle_sip_ict_t *obj, belle_sip_response_t *resp){
	belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj;
	if (obj->ack==NULL){
		obj->ack=belle_sip_request_new();
62
		belle_sip_object_ref(obj->ack);
63 64
		belle_sip_request_set_method(obj->ack,"ACK");
		belle_sip_request_set_uri(obj->ack,belle_sip_request_get_uri(base->request));
jehan's avatar
fix tag  
jehan committed
65 66 67 68 69 70
		belle_sip_util_copy_headers((belle_sip_message_t*)base->request,(belle_sip_message_t*)obj->ack,BELLE_SIP_VIA,FALSE);
		belle_sip_util_copy_headers((belle_sip_message_t*)base->request,(belle_sip_message_t*)obj->ack,BELLE_SIP_CALL_ID,FALSE);
		belle_sip_util_copy_headers((belle_sip_message_t*)base->request,(belle_sip_message_t*)obj->ack,BELLE_SIP_FROM,FALSE);
		belle_sip_util_copy_headers((belle_sip_message_t*)resp,(belle_sip_message_t*)obj->ack,BELLE_SIP_TO,FALSE);
		belle_sip_util_copy_headers((belle_sip_message_t*)base->request,(belle_sip_message_t*)obj->ack,BELLE_SIP_CONTACT,TRUE);
		belle_sip_util_copy_headers((belle_sip_message_t*)base->request,(belle_sip_message_t*)obj->ack,BELLE_SIP_ROUTE,TRUE);
71
		belle_sip_util_copy_headers((belle_sip_message_t*)base->request,(belle_sip_message_t*)obj->ack,BELLE_SIP_MAX_FORWARDS,FALSE);
72 73
		belle_sip_message_add_header((belle_sip_message_t*)obj->ack,
		(belle_sip_header_t*)belle_sip_header_cseq_create(
jehan's avatar
fix tag  
jehan committed
74
			belle_sip_header_cseq_get_seq_number((belle_sip_header_cseq_t*)belle_sip_message_get_header((belle_sip_message_t*)base->request,BELLE_SIP_CSEQ)),
Simon Morlat's avatar
Simon Morlat committed
75
		    "ACK"));
76
	}
jehan's avatar
fix tag  
jehan committed
77

78 79 80 81 82 83 84 85 86 87 88
	return obj->ack;
}

static int ict_on_timer_D(belle_sip_ict_t *obj){
	belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj;
	if (base->state==BELLE_SIP_TRANSACTION_COMPLETED){
		belle_sip_transaction_terminate(base);
	}
	return BELLE_SIP_STOP;
}

89 90 91 92 93 94 95 96
static int ict_on_timer_M(belle_sip_ict_t *obj){
	belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj;
	if (base->state==BELLE_SIP_TRANSACTION_ACCEPTED){
		belle_sip_transaction_terminate(base);
	}
	return BELLE_SIP_STOP;
}

97 98 99
static void ict_on_response(belle_sip_ict_t *obj, belle_sip_response_t *resp){
	belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj;
	int code=belle_sip_response_get_status_code(resp);
100
	const belle_sip_timer_config_t *cfg=belle_sip_transaction_get_timer_config(base);
101 102 103

	switch (base->state){
		case BELLE_SIP_TRANSACTION_CALLING:
jehan's avatar
jehan committed
104
			belle_sip_transaction_set_state(base,BELLE_SIP_TRANSACTION_PROCEEDING);
105 106 107
			/* no break*/
		case BELLE_SIP_TRANSACTION_PROCEEDING:
			if (code>=300){
jehan's avatar
jehan committed
108
				belle_sip_transaction_set_state(base,BELLE_SIP_TRANSACTION_COMPLETED);
109
				belle_sip_channel_queue_message(base->channel,(belle_sip_message_t*)make_ack(obj,resp));
jehan's avatar
jehan committed
110
				belle_sip_client_transaction_notify_response((belle_sip_client_transaction_t*)obj,resp);
111
				obj->timer_D=belle_sip_timeout_source_new((belle_sip_source_func_t)ict_on_timer_D,obj,cfg->T1*64);
112 113
				belle_sip_transaction_start_timer(base,obj->timer_D);
			}else if (code>=200){
114 115
				obj->timer_M=belle_sip_timeout_source_new((belle_sip_source_func_t)ict_on_timer_M,obj,cfg->T1*64);
				belle_sip_transaction_start_timer(base,obj->timer_M);
jehan's avatar
jehan committed
116
				belle_sip_transaction_set_state(base,BELLE_SIP_TRANSACTION_ACCEPTED);
117
				belle_sip_client_transaction_notify_response((belle_sip_client_transaction_t*)obj,resp);
Simon Morlat's avatar
Simon Morlat committed
118 119
			}else if (code>=100){
				belle_sip_client_transaction_notify_response((belle_sip_client_transaction_t*)obj,resp);
120 121
			}
		break;
122 123 124 125 126
		case BELLE_SIP_TRANSACTION_ACCEPTED:
			if (code>=200 && code<300){
				belle_sip_client_transaction_notify_response((belle_sip_client_transaction_t*)obj,resp);
			}
		break;
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
		case BELLE_SIP_TRANSACTION_COMPLETED:
			if (code>=300 && obj->ack){
				belle_sip_channel_queue_message(base->channel,(belle_sip_message_t*)obj->ack);
			}
		break;
		default:
		break;
	}
}

static int ict_on_timer_A(belle_sip_ict_t *obj){
	belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj;

	switch(base->state){
		case BELLE_SIP_TRANSACTION_CALLING:
		{
			/*reset the timer to twice the previous value, and retransmit */
			unsigned int prev_timeout=belle_sip_source_get_timeout(obj->timer_A);
			belle_sip_source_set_timeout(obj->timer_A,2*prev_timeout);
			belle_sip_channel_queue_message(base->channel,(belle_sip_message_t*)base->request);
		}
		break;
		default:
		break;
	}
	
	return BELLE_SIP_CONTINUE;
Simon Morlat's avatar
Simon Morlat committed
154 155
}

156 157 158 159 160 161 162 163 164 165
static int ict_on_timer_B(belle_sip_ict_t *obj){
	belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj;
	switch (base->state){
		case BELLE_SIP_TRANSACTION_CALLING:
			belle_sip_transaction_notify_timeout(base);
		break;
		default:
		break;
	}
	return BELLE_SIP_STOP;
Simon Morlat's avatar
Simon Morlat committed
166 167
}

168

Simon Morlat's avatar
Simon Morlat committed
169 170
static void ict_send_request(belle_sip_ict_t *obj){
	belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj;
171 172
	const belle_sip_timer_config_t *cfg=belle_sip_transaction_get_timer_config(base);

jehan's avatar
jehan committed
173
	belle_sip_transaction_set_state(base,BELLE_SIP_TRANSACTION_CALLING);
174 175 176 177 178 179 180 181
	
	if (!belle_sip_channel_is_reliable(base->channel)){
		obj->timer_A=belle_sip_timeout_source_new((belle_sip_source_func_t)ict_on_timer_A,obj,cfg->T1);
		belle_sip_transaction_start_timer(base,obj->timer_A);
	}

	obj->timer_B=belle_sip_timeout_source_new((belle_sip_source_func_t)ict_on_timer_B,obj,cfg->T1*64);
	belle_sip_transaction_start_timer(base,obj->timer_B);
Simon Morlat's avatar
Simon Morlat committed
182
	
Simon Morlat's avatar
Simon Morlat committed
183
	belle_sip_channel_queue_message(base->channel,(belle_sip_message_t*)base->request);
Simon Morlat's avatar
Simon Morlat committed
184 185 186 187
}

BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_ict_t);

188
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_ict_t)
Simon Morlat's avatar
Simon Morlat committed
189 190
	{
		{
Simon Morlat's avatar
Simon Morlat committed
191
			{
192
				BELLE_SIP_VPTR_INIT(belle_sip_ict_t,belle_sip_client_transaction_t,TRUE),
Simon Morlat's avatar
Simon Morlat committed
193 194 195 196 197
				(belle_sip_object_destroy_t)ict_destroy,
				NULL,
				NULL
			},
			(void (*)(belle_sip_transaction_t*))on_ict_terminate
Simon Morlat's avatar
Simon Morlat committed
198 199
		},
		(void (*)(belle_sip_client_transaction_t*))ict_send_request,
200
		(void (*)(belle_sip_client_transaction_t*,belle_sip_response_t*))ict_on_response
Simon Morlat's avatar
Simon Morlat committed
201
	}
202
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END
Simon Morlat's avatar
Simon Morlat committed
203 204 205 206 207 208 209 210


belle_sip_ict_t *belle_sip_ict_new(belle_sip_provider_t *prov, belle_sip_request_t *req){
	belle_sip_ict_t *obj=belle_sip_object_new(belle_sip_ict_t);
	belle_sip_client_transaction_init((belle_sip_client_transaction_t*)obj,prov,req);
	return obj;
}