nict.c 5.89 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 19
    (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/>.
*/


20 21 22 23
/** 
 * non-INVITE client transaction implementation.
**/

Simon Morlat's avatar
Simon Morlat committed
24 25 26 27 28 29 30
#include "belle_sip_internal.h"

static int nict_on_timer_K(belle_sip_nict_t *obj){
	belle_sip_transaction_terminate((belle_sip_transaction_t*)obj);
	return BELLE_SIP_STOP;
}

31
static void nict_set_completed(belle_sip_nict_t *obj, belle_sip_response_t *resp){
Simon Morlat's avatar
Simon Morlat committed
32 33
	belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj;
	const belle_sip_timer_config_t *cfg=belle_sip_transaction_get_timer_config(base);
34
	belle_sip_transaction_set_state(base,BELLE_SIP_TRANSACTION_COMPLETED);
Simon Morlat's avatar
Simon Morlat committed
35
	if (obj->timer_K) belle_sip_fatal("Should never happen.");
36 37 38 39 40

	belle_sip_client_transaction_notify_response((belle_sip_client_transaction_t*)obj,resp);

	if (!belle_sip_channel_is_reliable(base->channel)){
		obj->timer_K=belle_sip_timeout_source_new((belle_sip_source_func_t)nict_on_timer_K,obj,cfg->T4);
41
		belle_sip_object_set_name((belle_sip_object_t*)obj->timer_K,"timer_K");
42 43
		belle_sip_transaction_start_timer(base,obj->timer_K);
	}else belle_sip_transaction_terminate(base);
Simon Morlat's avatar
Simon Morlat committed
44 45
}

46
static void nict_on_response(belle_sip_nict_t *obj, belle_sip_response_t *resp){
Simon Morlat's avatar
Simon Morlat committed
47 48 49 50 51 52
	belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj;
	int code=belle_sip_response_get_status_code(resp);
	
	switch(base->state){
		case BELLE_SIP_TRANSACTION_TRYING:
			if (code<200){
53
				belle_sip_transaction_set_state(base,BELLE_SIP_TRANSACTION_PROCEEDING);
54
				belle_sip_client_transaction_notify_response((belle_sip_client_transaction_t*)obj,resp);
Simon Morlat's avatar
Simon Morlat committed
55 56
			}
			else {
57
				nict_set_completed(obj,resp);
Simon Morlat's avatar
Simon Morlat committed
58 59 60 61
			}
		break;
		case BELLE_SIP_TRANSACTION_PROCEEDING:
			if (code>=200){
62
				nict_set_completed(obj,resp);
Simon Morlat's avatar
Simon Morlat committed
63 64 65 66 67 68 69 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 98 99 100 101 102 103 104 105 106 107 108 109 110
			}
		break;
		default:
		break;
	}
}

static void nict_on_terminate(belle_sip_nict_t *obj){
	belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj;
	if (obj->timer_F){
		belle_sip_transaction_stop_timer(base,obj->timer_F);
		belle_sip_object_unref(obj->timer_F);
		obj->timer_F=NULL;
	}
	if (obj->timer_E){
		belle_sip_transaction_stop_timer(base,obj->timer_E);
		belle_sip_object_unref(obj->timer_E);
		obj->timer_E=NULL;
	}
	if (obj->timer_K){
		belle_sip_transaction_stop_timer(base,obj->timer_K);
		belle_sip_object_unref(obj->timer_K);
		obj->timer_K=NULL;
	}
}

static int nict_on_timer_F(belle_sip_nict_t *obj){
	belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj;
	switch (base->state){
		case BELLE_SIP_TRANSACTION_TRYING:
		case BELLE_SIP_TRANSACTION_PROCEEDING:
			belle_sip_transaction_notify_timeout(base);
		break;
		default:
		break;
	}
	return BELLE_SIP_STOP;
}

static int nict_on_timer_E(belle_sip_nict_t *obj){
	belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj;
	const belle_sip_timer_config_t *cfg=belle_sip_transaction_get_timer_config(base);

	switch(base->state){
		case BELLE_SIP_TRANSACTION_TRYING:
		{
			/*reset the timer */
			unsigned int prev_timeout=belle_sip_source_get_timeout(obj->timer_E);
111
			belle_sip_source_set_timeout(obj->timer_E,MIN(2*prev_timeout,(unsigned int)cfg->T2));
112
			belle_sip_message("nict_on_timer_E: sending retransmission");
Simon Morlat's avatar
Simon Morlat committed
113 114 115 116 117
			belle_sip_channel_queue_message(base->channel,(belle_sip_message_t*)base->request);
		}
		break;
		case BELLE_SIP_TRANSACTION_PROCEEDING:
			belle_sip_source_set_timeout(obj->timer_E,cfg->T2);
118
			belle_sip_message("nict_on_timer_E: sending retransmission");
Simon Morlat's avatar
Simon Morlat committed
119 120 121
			belle_sip_channel_queue_message(base->channel,(belle_sip_message_t*)base->request);
		break;
		default:
122 123
			/*if we are not in these cases, timer_E does nothing, so remove it*/
			return BELLE_SIP_STOP;
Simon Morlat's avatar
Simon Morlat committed
124 125 126 127 128 129 130 131 132
		break;
	}
	return BELLE_SIP_CONTINUE;
}

static void nict_send_request(belle_sip_nict_t *obj){
	belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj;
	const belle_sip_timer_config_t *cfg=belle_sip_transaction_get_timer_config(base);
	
133
	belle_sip_transaction_set_state(base,BELLE_SIP_TRANSACTION_TRYING);
Simon Morlat's avatar
Simon Morlat committed
134
	obj->timer_F=belle_sip_timeout_source_new((belle_sip_source_func_t)nict_on_timer_F,obj,cfg->T1*64);
135
	belle_sip_object_set_name((belle_sip_object_t*)obj->timer_F,"timer_F");
Simon Morlat's avatar
Simon Morlat committed
136 137 138 139
	belle_sip_transaction_start_timer(base,obj->timer_F);
	
	if (!belle_sip_channel_is_reliable(base->channel)){
		obj->timer_E=belle_sip_timeout_source_new((belle_sip_source_func_t)nict_on_timer_E,obj,cfg->T1);
140
		belle_sip_object_set_name((belle_sip_object_t*)obj->timer_E,"timer_E");
Simon Morlat's avatar
Simon Morlat committed
141 142
		belle_sip_transaction_start_timer(base,obj->timer_E);
	}
Simon Morlat's avatar
Simon Morlat committed
143 144
	
	belle_sip_channel_queue_message(base->channel,(belle_sip_message_t*)base->request);
Simon Morlat's avatar
Simon Morlat committed
145 146
}

147 148 149 150
static void nict_destroy(belle_sip_nict_t *obj){
	nict_on_terminate(obj);
}

Simon Morlat's avatar
Simon Morlat committed
151 152
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_nict_t);

153
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_nict_t)
Simon Morlat's avatar
Simon Morlat committed
154 155 156
	{
		{
			{
157
				BELLE_SIP_VPTR_INIT(belle_sip_nict_t,belle_sip_client_transaction_t,TRUE),
Simon Morlat's avatar
Simon Morlat committed
158 159 160 161 162 163 164
				(belle_sip_object_destroy_t)nict_destroy,
				NULL,
				NULL
			},
			(void (*)(belle_sip_transaction_t *))nict_on_terminate
		},
		(void (*)(belle_sip_client_transaction_t*))nict_send_request,
165
		(void (*)(belle_sip_client_transaction_t*,belle_sip_response_t*))nict_on_response
Simon Morlat's avatar
Simon Morlat committed
166
	}
167
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END
Simon Morlat's avatar
Simon Morlat committed
168 169 170 171 172 173 174 175


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