listeningpoint.c 7.96 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/*
	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
    the Free Software Foundation, either version 3 of the License, or
    (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/>.
*/

Simon Morlat's avatar
Simon Morlat committed
19
#include "belle_sip_internal.h"
20 21


jehan's avatar
jehan committed
22
void belle_sip_listening_point_init(belle_sip_listening_point_t *lp, belle_sip_stack_t *s, const char *address, int port){
Simon Morlat's avatar
Simon Morlat committed
23
	belle_sip_init_sockets();
24
	lp->stack=s;
jehan's avatar
jehan committed
25
	lp->listening_uri=belle_sip_uri_create(NULL,address);
26
	belle_sip_object_ref(lp->listening_uri);
jehan's avatar
jehan committed
27 28
	belle_sip_uri_set_port(lp->listening_uri,port);
	belle_sip_uri_set_transport_param(lp->listening_uri,BELLE_SIP_OBJECT_VPTR(lp,belle_sip_listening_point_t)->transport);
29 30 31
}

static void belle_sip_listening_point_uninit(belle_sip_listening_point_t *lp){
Simon Morlat's avatar
Simon Morlat committed
32
	
33
	belle_sip_listening_point_clean_channels(lp);
jehan's avatar
jehan committed
34
	belle_sip_message("Listening point [%p] on [%s://%s:%i] destroyed"	,lp
35 36 37
															,belle_sip_uri_get_transport_param(BELLE_SIP_LISTENING_POINT(lp)->listening_uri)
															,belle_sip_uri_get_host(BELLE_SIP_LISTENING_POINT(lp)->listening_uri)
															,belle_sip_uri_get_port(BELLE_SIP_LISTENING_POINT(lp)->listening_uri));
jehan's avatar
jehan committed
38
	belle_sip_object_unref(lp->listening_uri);
jehan's avatar
jehan committed
39
	lp->channel_listener=NULL; /*does not unref provider*/
Simon Morlat's avatar
Simon Morlat committed
40
	belle_sip_uninit_sockets();
jehan's avatar
jehan committed
41
	belle_sip_listening_point_set_keep_alive(lp,-1);
42 43
}

44

jehan's avatar
jehan committed
45
void belle_sip_listening_point_add_channel(belle_sip_listening_point_t *lp, belle_sip_channel_t *chan){
jehan's avatar
jehan committed
46
	lp->channels=belle_sip_list_append(lp->channels,chan);/*channel is already owned*/
47 48 49 50 51
}

belle_sip_channel_t *belle_sip_listening_point_create_channel(belle_sip_listening_point_t *obj, const char *dest, int port){
	belle_sip_channel_t *chan=BELLE_SIP_OBJECT_VPTR(obj,belle_sip_listening_point_t)->create_channel(obj,dest,port);
	if (chan){
Simon Morlat's avatar
wip  
Simon Morlat committed
52
		chan->lp=obj;
jehan's avatar
jehan committed
53
		belle_sip_channel_add_listener(chan,obj->channel_listener);
54 55 56
		belle_sip_listening_point_add_channel(obj,chan);
	}
	return chan;
57 58
}

Simon Morlat's avatar
wip  
Simon Morlat committed
59 60

void belle_sip_listening_point_remove_channel(belle_sip_listening_point_t *lp, belle_sip_channel_t *chan){
61
	lp->channels=belle_sip_list_remove(lp->channels,chan);
62
	belle_sip_object_unref(chan);
63
}
Simon Morlat's avatar
wip  
Simon Morlat committed
64

65

66 67
void belle_sip_listening_point_clean_channels(belle_sip_listening_point_t *lp){
	int existing_channels;
68
	belle_sip_list_t* iterator;
jehan's avatar
jehan committed
69
	belle_sip_list_t* channels=belle_sip_list_copy(lp->channels);
70 71 72
	if ((existing_channels=belle_sip_list_size(lp->channels)) > 0) {
		belle_sip_warning("Listening point destroying [%i] channels",existing_channels);
	}
jehan's avatar
jehan committed
73 74 75 76
	for (iterator=channels;iterator!=NULL;iterator=iterator->next) {
		/*first, every existing channel must be set to error*/
		channel_set_state((belle_sip_channel_t*)(iterator->data),BELLE_SIP_CHANNEL_DISCONNECTED);
		belle_sip_channel_close((belle_sip_channel_t*)(iterator->data));
77
	}
jehan's avatar
jehan committed
78 79
	belle_sip_list_free(channels);

80
	lp->channels=belle_sip_list_free_with_data(lp->channels,(void (*)(void*))belle_sip_object_unref);
81 82
}

83

84
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_listening_point_t);
85 86
BELLE_SIP_INSTANCIATE_CUSTOM_VPTR(belle_sip_listening_point_t)={
	{ 
Simon Morlat's avatar
Simon Morlat committed
87
		BELLE_SIP_VPTR_INIT(belle_sip_listening_point_t, belle_sip_object_t,FALSE),
88 89 90 91 92 93 94
		(belle_sip_object_destroy_t)belle_sip_listening_point_uninit,
		NULL,
		NULL
	},
	NULL,
	NULL
};
Simon Morlat's avatar
Simon Morlat committed
95

96
const char *belle_sip_listening_point_get_ip_address(const belle_sip_listening_point_t *lp){
jehan's avatar
jehan committed
97
	return belle_sip_uri_get_host(lp->listening_uri);
98 99 100
}

int belle_sip_listening_point_get_port(const belle_sip_listening_point_t *lp){
jehan's avatar
jehan committed
101
	return belle_sip_uri_get_listening_port(lp->listening_uri);
102 103 104
}

const char *belle_sip_listening_point_get_transport(const belle_sip_listening_point_t *lp){
jehan's avatar
jehan committed
105
	return belle_sip_uri_get_transport_param(lp->listening_uri);
106 107
}

jehan's avatar
jehan committed
108 109 110
const belle_sip_uri_t* belle_sip_listening_point_get_uri(const  belle_sip_listening_point_t *lp) {
	return lp->listening_uri;
}
111 112 113 114 115 116 117
int belle_sip_listening_point_get_well_known_port(const char *transport){
	if (strcasecmp(transport,"UDP")==0 || strcasecmp(transport,"TCP")==0 ) return 5060;
	if (strcasecmp(transport,"DTLS")==0 || strcasecmp(transport,"TLS")==0 ) return 5061;
	belle_sip_error("No well known port for transport %s", transport);
	return -1;
}

jehan's avatar
jehan committed
118
belle_sip_channel_t *_belle_sip_listening_point_get_channel(belle_sip_listening_point_t *lp,const char *peer_name, int peer_port, const struct addrinfo *addr){
119
	belle_sip_list_t *elem;
120
	belle_sip_channel_t *chan;
Simon Morlat's avatar
Simon Morlat committed
121 122 123 124 125 126 127 128 129 130 131
	
	for(elem=lp->channels;elem!=NULL;elem=elem->next){
		chan=(belle_sip_channel_t*)elem->data;
		if (belle_sip_channel_matches(chan,peer_name,peer_port,addr)){
			return chan;
		}
	}
	return NULL;
}

belle_sip_channel_t *belle_sip_listening_point_get_channel(belle_sip_listening_point_t *lp,const char *peer_name, int peer_port){
132 133 134
	struct addrinfo *res=NULL;
	struct addrinfo hints={0};
	char portstr[20];
Simon Morlat's avatar
Simon Morlat committed
135
	belle_sip_channel_t *chan;
136 137 138 139

	hints.ai_flags=AI_NUMERICHOST|AI_NUMERICSERV;
	snprintf(portstr,sizeof(portstr),"%i",peer_port);
	getaddrinfo(peer_name,portstr,&hints,&res);
Simon Morlat's avatar
Simon Morlat committed
140
	chan=_belle_sip_listening_point_get_channel(lp,peer_name,peer_port,res);
141
	if (res) freeaddrinfo(res);
Simon Morlat's avatar
Simon Morlat committed
142
	return chan;
143 144
}

jehan's avatar
jehan committed
145 146 147
void belle_sip_listener_set_channel_listener(belle_sip_listening_point_t *lp,belle_sip_channel_listener_t* channel_listener) {
	lp->channel_listener=channel_listener;
}
148

jehan's avatar
jehan committed
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
static int send_keep_alive(belle_sip_channel_t* obj) {
	/*keep alive*/
			const char* crlfcrlf = "\r\n\r\n";
			int size=strlen(crlfcrlf);
			if (belle_sip_channel_send(obj,crlfcrlf,size)<0){
				belle_sip_error("channel [%p]: could not send [%i] bytes of keep alive from [%s://%s:%i]  to [%s:%i]"	,obj
																										,size
																										,belle_sip_channel_get_transport_name(obj)
																										,obj->local_ip
																										,obj->local_port
																										,obj->peer_name
																										,obj->peer_port);

				return -1;
			}else{
				belle_sip_message("channel [%p]: keep alive sent to [%s://%s:%i]"
									,obj
									,belle_sip_channel_get_transport_name(obj)
									,obj->peer_name
									,obj->peer_port);
				return 0;
			}
}
static int keep_alive_timer_func(void *user_data, unsigned int events) {
	belle_sip_listening_point_t* lp=(belle_sip_listening_point_t*)user_data;
	belle_sip_list_t* iterator;
	belle_sip_channel_t* channel;
176 177 178 179 180 181 182 183 184
		/*list is copied to make sure it is not altered in case of error*/
	for (iterator=belle_sip_list_copy(lp->channels);iterator!=NULL;iterator=iterator->next) {
		channel=(belle_sip_channel_t*)iterator->data;
		belle_sip_object_ref(channel); /*to make sure channels are still valid even if error is reported*/
		if (channel->state == BELLE_SIP_CHANNEL_READY && send_keep_alive(channel)) { /*only send keep alive if ready*/
			channel_set_state(channel,BELLE_SIP_CHANNEL_ERROR);
			belle_sip_channel_close(channel);
		}
		belle_sip_object_unref(channel);
jehan's avatar
jehan committed
185
	}
186
	belle_sip_list_free(iterator);
jehan's avatar
jehan committed
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
	return BELLE_SIP_CONTINUE;
}
void belle_sip_listening_point_set_keep_alive(belle_sip_listening_point_t *lp,int ms) {

	if (ms <=0) {
		if(lp->keep_alive_timer) {
			belle_sip_main_loop_remove_source(lp->stack->ml,lp->keep_alive_timer);
			belle_sip_object_unref(lp->keep_alive_timer);
			lp->keep_alive_timer=NULL;
		}
		return;
	}

	if (!lp->keep_alive_timer) {
		lp->keep_alive_timer = belle_sip_main_loop_create_timeout(lp->stack->ml
																, keep_alive_timer_func
																, lp
																, ms
																,"keep alive") ;
	} else {
		belle_sip_source_set_timeout(lp->keep_alive_timer,ms);
	}

	return;

}

int belle_sip_listening_point_get_keep_alive(const belle_sip_listening_point_t *lp) {
	return lp->keep_alive_timer?belle_sip_source_get_timeout(lp->keep_alive_timer):-1;

}
218