http-provider.c 10.9 KB
Newer Older
Simon Morlat's avatar
Simon Morlat committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/*
	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/>.
*/


#include "belle_sip_internal.h"

Simon Morlat's avatar
Simon Morlat committed
22 23 24 25
typedef struct belle_http_channel_context belle_http_channel_context_t;

#define BELLE_HTTP_CHANNEL_CONTEXT(obj) BELLE_SIP_CAST(obj,belle_http_channel_context_t)

Simon Morlat's avatar
Simon Morlat committed
26 27
static void provider_remove_channel(belle_http_provider_t *obj, belle_sip_channel_t *chan);

Simon Morlat's avatar
Simon Morlat committed
28 29
struct belle_http_channel_context{
	belle_sip_object_t base;
Simon Morlat's avatar
Simon Morlat committed
30
	belle_http_provider_t *provider;
Simon Morlat's avatar
Simon Morlat committed
31 32
	belle_sip_list_t *pending_requests;
};
Simon Morlat's avatar
Simon Morlat committed
33 34

struct belle_http_provider{
Simon Morlat's avatar
Simon Morlat committed
35
	belle_sip_object_t base;
Simon Morlat's avatar
Simon Morlat committed
36
	belle_sip_stack_t *stack;
Simon Morlat's avatar
Simon Morlat committed
37
	char *bind_ip;
Simon Morlat's avatar
Simon Morlat committed
38
	int ai_family;
Simon Morlat's avatar
Simon Morlat committed
39 40
	belle_sip_list_t *tcp_channels;
	belle_sip_list_t *tls_channels;
Simon Morlat's avatar
Simon Morlat committed
41
	belle_tls_verify_policy_t *verify_ctx;
Simon Morlat's avatar
Simon Morlat committed
42 43
};

Simon Morlat's avatar
Simon Morlat committed
44 45 46
#define BELLE_HTTP_REQUEST_INVOKE_LISTENER(obj,method,arg) \
	obj->listener ? BELLE_SIP_INVOKE_LISTENER_ARG(obj->listener,belle_http_request_listener_t,method,arg) : 0

Simon Morlat's avatar
Simon Morlat committed
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 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
static int http_channel_context_handle_authentication(belle_http_channel_context_t *ctx, belle_http_request_t *req){
	const char *realm=NULL;
	belle_sip_auth_event_t *ev=NULL;
	belle_http_response_t *resp=belle_http_request_get_response(req);
	const char *username=NULL;
	const char *passwd=NULL;
	int ret=0;
	
	(void)resp;
	
	/*find if username, passwd were already supplied in original request uri*/
	if (req->orig_uri){
		username=belle_generic_uri_get_user(req->orig_uri);
		passwd=belle_generic_uri_get_user_password(req->orig_uri);
	}
	
	if (username==NULL || passwd==NULL){
		/*TODO find the realm from the Authentication header*/
		
		ev=belle_sip_auth_event_create((belle_sip_object_t*)ctx->provider,realm,NULL);
		BELLE_HTTP_REQUEST_INVOKE_LISTENER(req,process_auth_requested,ev);
		username=ev->username;
		passwd=ev->passwd;
	}
	
	if (username && passwd){
		/*TODO resubmit the request to the provider with authentication added*/
		
		belle_http_provider_send_request(ctx->provider,req,NULL);
	}else ret=-1;
	
	if (ev) belle_sip_auth_event_destroy(ev);
	return ret;
}
	
static void http_channel_context_handle_response(belle_http_channel_context_t *ctx , belle_http_response_t *response){
	belle_http_request_t *req=NULL;
	belle_http_response_event_t ev={0};
	int code;
	/*pop the request matching this response*/
	ctx->pending_requests=belle_sip_list_pop_front(ctx->pending_requests,(void**)&req);
	if (req==NULL){
		belle_sip_error("Receiving http response not matching any request.");
		return;
	}
	belle_http_request_set_response(req,response);
	code=belle_http_response_get_status_code(response);
	if ((code==401 || code==407) && http_channel_context_handle_authentication(ctx,req)==0 ){
		/*nothing to do, the request has been resubmitted with authentication*/
	}else{
		/*else notify the app about the response received*/
		ev.source=(belle_sip_object_t*)ctx->provider;
		ev.request=req;
		ev.response=response;
		BELLE_HTTP_REQUEST_INVOKE_LISTENER(req,process_response,&ev);
	}
	belle_sip_object_unref(req);
}

Simon Morlat's avatar
Simon Morlat committed
106
static int channel_on_event(belle_sip_channel_listener_t *obj, belle_sip_channel_t *chan, unsigned int revents){
Simon Morlat's avatar
Simon Morlat committed
107
	belle_http_channel_context_t *ctx=BELLE_HTTP_CHANNEL_CONTEXT(obj);
Simon Morlat's avatar
Simon Morlat committed
108
	if (revents & BELLE_SIP_EVENT_READ){
Simon Morlat's avatar
Simon Morlat committed
109 110 111
		belle_sip_message_t *msg;
		while((msg=belle_sip_channel_pick_message(chan))!=NULL){
			if (msg && BELLE_SIP_OBJECT_IS_INSTANCE_OF(msg,belle_http_response_t)){
Simon Morlat's avatar
Simon Morlat committed
112
				http_channel_context_handle_response(ctx,(belle_http_response_t*)msg);
Simon Morlat's avatar
Simon Morlat committed
113 114 115
			}
			belle_sip_object_unref(msg);
		}
Simon Morlat's avatar
Simon Morlat committed
116 117 118 119 120
	}
	return 0;
}

static int channel_on_auth_requested(belle_sip_channel_listener_t *obj, belle_sip_channel_t *chan, const char* distinguished_name){
Simon Morlat's avatar
Simon Morlat committed
121
	belle_http_channel_context_t *ctx=BELLE_HTTP_CHANNEL_CONTEXT(obj);
Simon Morlat's avatar
Simon Morlat committed
122
	if (BELLE_SIP_IS_INSTANCE_OF(chan,belle_sip_tls_channel_t)) {
Simon Morlat's avatar
Simon Morlat committed
123
		belle_sip_auth_event_t* auth_event = belle_sip_auth_event_create((belle_sip_object_t*)ctx->provider,NULL,NULL);
Simon Morlat's avatar
Simon Morlat committed
124
		belle_sip_tls_channel_t *tls_chan=BELLE_SIP_TLS_CHANNEL(chan);
Simon Morlat's avatar
Simon Morlat committed
125
		belle_http_request_t *req=(belle_http_request_t*)ctx->pending_requests->data;
Simon Morlat's avatar
Simon Morlat committed
126 127
		auth_event->mode=BELLE_SIP_AUTH_MODE_TLS;
		belle_sip_auth_event_set_distinguished_name(auth_event,distinguished_name);
Simon Morlat's avatar
Simon Morlat committed
128
		
Simon Morlat's avatar
Simon Morlat committed
129
		BELLE_HTTP_REQUEST_INVOKE_LISTENER(req,process_auth_requested,auth_event);
Simon Morlat's avatar
Simon Morlat committed
130 131 132 133 134 135 136 137
		belle_sip_tls_channel_set_client_certificates_chain(tls_chan,auth_event->cert);
		belle_sip_tls_channel_set_client_certificate_key(tls_chan,auth_event->key);
		belle_sip_auth_event_destroy(auth_event);
	}
	return 0;
}

static void channel_on_sending(belle_sip_channel_listener_t *obj, belle_sip_channel_t *chan, belle_sip_message_t *msg){
Simon Morlat's avatar
Simon Morlat committed
138
	belle_http_channel_context_t *ctx=BELLE_HTTP_CHANNEL_CONTEXT(obj);
Simon Morlat's avatar
Simon Morlat committed
139
	ctx->pending_requests=belle_sip_list_append(ctx->pending_requests,belle_sip_object_ref(msg));
Simon Morlat's avatar
Simon Morlat committed
140 141 142
}

static void channel_state_changed(belle_sip_channel_listener_t *obj, belle_sip_channel_t *chan, belle_sip_channel_state_t state){
Simon Morlat's avatar
Simon Morlat committed
143
	belle_http_channel_context_t *ctx=BELLE_HTTP_CHANNEL_CONTEXT(obj);
Simon Morlat's avatar
Simon Morlat committed
144 145 146 147 148 149 150 151 152 153
	switch(state){
		case BELLE_SIP_CHANNEL_INIT:
		case BELLE_SIP_CHANNEL_RES_IN_PROGRESS:
		case BELLE_SIP_CHANNEL_RES_DONE:
		case BELLE_SIP_CHANNEL_CONNECTING:
		case BELLE_SIP_CHANNEL_READY:
		case BELLE_SIP_CHANNEL_RETRY:
			break;
		case BELLE_SIP_CHANNEL_ERROR:
		case BELLE_SIP_CHANNEL_DISCONNECTED:
Simon Morlat's avatar
Simon Morlat committed
154
			if (!chan->force_close) provider_remove_channel(ctx->provider,chan);
Simon Morlat's avatar
Simon Morlat committed
155 156
			break;
	}
Simon Morlat's avatar
Simon Morlat committed
157 158
}

Simon Morlat's avatar
Simon Morlat committed
159
static void belle_http_channel_context_uninit(belle_http_channel_context_t *obj){
Simon Morlat's avatar
Simon Morlat committed
160
	belle_sip_list_free_with_data(obj->pending_requests,belle_sip_object_unref);
Simon Morlat's avatar
Simon Morlat committed
161 162
}

Simon Morlat's avatar
Simon Morlat committed
163 164 165 166 167 168 169 170 171 172
static void on_channel_destroyed(belle_http_channel_context_t *obj, belle_sip_channel_t *chan_being_destroyed){
	belle_sip_channel_remove_listener(chan_being_destroyed,BELLE_SIP_CHANNEL_LISTENER(obj));
	belle_sip_object_unref(obj);
}

/*
 * The http channel context stores pending requests so that they can be matched with response received.
 * It is associated with the channel when the channel is created, and automatically destroyed when the channel is destroyed.
**/
belle_http_channel_context_t * belle_http_channel_context_new(belle_sip_channel_t *chan, belle_http_provider_t *prov){
Simon Morlat's avatar
Simon Morlat committed
173
	belle_http_channel_context_t *obj=belle_sip_object_new(belle_http_channel_context_t);
Simon Morlat's avatar
Simon Morlat committed
174
	obj->provider=prov;
Simon Morlat's avatar
Simon Morlat committed
175
	belle_sip_channel_add_listener(chan,(belle_sip_channel_listener_t*)obj);
Simon Morlat's avatar
Simon Morlat committed
176
	belle_sip_object_weak_ref(chan,(belle_sip_object_destroy_notify_t)on_channel_destroyed,obj);
Simon Morlat's avatar
Simon Morlat committed
177 178
	return obj;
}
Simon Morlat's avatar
Simon Morlat committed
179

Simon Morlat's avatar
Simon Morlat committed
180
BELLE_SIP_IMPLEMENT_INTERFACE_BEGIN(belle_http_channel_context_t,belle_sip_channel_listener_t)
Simon Morlat's avatar
Simon Morlat committed
181 182 183 184 185 186
	channel_state_changed,
	channel_on_event,
	channel_on_sending,
	channel_on_auth_requested
BELLE_SIP_IMPLEMENT_INTERFACE_END

Simon Morlat's avatar
Simon Morlat committed
187 188
BELLE_SIP_DECLARE_IMPLEMENTED_INTERFACES_1(belle_http_channel_context_t,belle_sip_channel_listener_t);
BELLE_SIP_INSTANCIATE_VPTR(belle_http_channel_context_t,belle_sip_object_t,belle_http_channel_context_uninit,NULL,NULL,FALSE);
Simon Morlat's avatar
Simon Morlat committed
189 190

static void http_provider_uninit(belle_http_provider_t *obj){
Simon Morlat's avatar
Simon Morlat committed
191
	belle_sip_message("http provider destroyed.");
Simon Morlat's avatar
Simon Morlat committed
192
	belle_sip_free(obj->bind_ip);
Simon Morlat's avatar
Simon Morlat committed
193 194 195 196
	belle_sip_list_for_each(obj->tcp_channels,(void (*)(void*))belle_sip_channel_force_close);
	belle_sip_list_free_with_data(obj->tcp_channels,belle_sip_object_unref);
	belle_sip_list_for_each(obj->tls_channels,(void (*)(void*))belle_sip_channel_force_close);
	belle_sip_list_free_with_data(obj->tls_channels,belle_sip_object_unref);
Simon Morlat's avatar
Simon Morlat committed
197
	belle_sip_object_unref(obj->verify_ctx);
Simon Morlat's avatar
Simon Morlat committed
198 199
}

Simon Morlat's avatar
Simon Morlat committed
200
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_http_provider_t);
Simon Morlat's avatar
Simon Morlat committed
201 202
BELLE_SIP_INSTANCIATE_VPTR(belle_http_provider_t,belle_sip_object_t,http_provider_uninit,NULL,NULL,FALSE);

Simon Morlat's avatar
Simon Morlat committed
203
belle_http_provider_t *belle_http_provider_new(belle_sip_stack_t *s, const char *bind_ip){
Simon Morlat's avatar
Simon Morlat committed
204
	belle_http_provider_t *p=belle_sip_object_new(belle_http_provider_t);
Simon Morlat's avatar
Simon Morlat committed
205
	p->stack=s;
Simon Morlat's avatar
Simon Morlat committed
206
	p->bind_ip=belle_sip_strdup(bind_ip);
Simon Morlat's avatar
Simon Morlat committed
207
	p->ai_family=strchr(p->bind_ip,':') ? AF_INET6 : AF_INET;
Simon Morlat's avatar
Simon Morlat committed
208
	p->verify_ctx=belle_tls_verify_policy_new();
Simon Morlat's avatar
Simon Morlat committed
209 210
	return p;
}
Simon Morlat's avatar
Simon Morlat committed
211

Simon Morlat's avatar
Simon Morlat committed
212 213 214
static void split_request_url(belle_http_request_t *req){
	belle_generic_uri_t *uri=belle_http_request_get_uri(req);
	belle_generic_uri_t *new_uri=belle_generic_uri_new();
Simon Morlat's avatar
Simon Morlat committed
215 216
	char *host_value;
	
Simon Morlat's avatar
Simon Morlat committed
217
	belle_sip_message("Path is: %s",belle_generic_uri_get_path(uri));
Simon Morlat's avatar
Simon Morlat committed
218
	belle_generic_uri_set_path(new_uri,belle_generic_uri_get_path(uri));
Simon Morlat's avatar
Simon Morlat committed
219 220 221 222 223 224
	if (belle_generic_uri_get_port(uri)>0)
		host_value=belle_sip_strdup_printf("%s:%i",belle_generic_uri_get_host(uri),belle_generic_uri_get_port(uri));
	else 
		host_value=belle_sip_strdup(belle_generic_uri_get_host(uri));
	belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Host",host_value));
	belle_sip_free(host_value);
Simon Morlat's avatar
Simon Morlat committed
225
	SET_OBJECT_PROPERTY(req,orig_uri,uri);
Simon Morlat's avatar
Simon Morlat committed
226 227 228 229 230 231
	belle_http_request_set_uri(req,new_uri);
}

static belle_sip_list_t **provider_get_channels(belle_http_provider_t *obj, const char *transport_name){
	if (strcasecmp(transport_name,"tcp")==0) return &obj->tcp_channels;
	else if (strcasecmp(transport_name,"tls")==0) return &obj->tls_channels;
Simon Morlat's avatar
Simon Morlat committed
232
	else{
Simon Morlat's avatar
Simon Morlat committed
233 234
		belle_sip_error("belle_http_provider_send_request(): unsupported transport %s",transport_name);
		return NULL;
Simon Morlat's avatar
Simon Morlat committed
235
	}
Simon Morlat's avatar
Simon Morlat committed
236 237 238 239 240
}

static void provider_remove_channel(belle_http_provider_t *obj, belle_sip_channel_t *chan){
	belle_sip_list_t **channels=provider_get_channels(obj,belle_sip_channel_get_transport_name(chan));
	*channels=belle_sip_list_remove(*channels,chan);
Simon Morlat's avatar
Simon Morlat committed
241
	belle_sip_message("channel [%p] removed from http provider.",obj);
Simon Morlat's avatar
Simon Morlat committed
242 243 244 245 246 247 248
	belle_sip_object_unref(chan);
}

int belle_http_provider_send_request(belle_http_provider_t *obj, belle_http_request_t *req, belle_http_request_listener_t *listener){
	belle_sip_channel_t *chan;
	belle_sip_hop_t *hop=belle_sip_hop_new_from_generic_uri(belle_http_request_get_uri(req));
	belle_sip_list_t **channels=provider_get_channels(obj,hop->transport);
Simon Morlat's avatar
Simon Morlat committed
249
	
Simon Morlat's avatar
Simon Morlat committed
250
	if (listener) belle_http_request_set_listener(req,listener);
Simon Morlat's avatar
Simon Morlat committed
251
	
Simon Morlat's avatar
Simon Morlat committed
252
	chan=belle_sip_channel_find_from_list(*channels,obj->ai_family, hop);
Simon Morlat's avatar
Simon Morlat committed
253 254
	
	if (!chan){
Simon Morlat's avatar
Simon Morlat committed
255 256 257 258 259
		if (strcasecmp(hop->transport,"tcp")==0){
			chan=belle_sip_stream_channel_new_client(obj->stack,obj->bind_ip,0,hop->cname,hop->host,hop->port);
		}else if (strcasecmp(hop->transport,"tls")==0){
			chan=belle_sip_channel_new_tls(obj->stack,obj->verify_ctx,obj->bind_ip,0,hop->cname,hop->host,hop->port);
		}
Simon Morlat's avatar
Simon Morlat committed
260
		belle_http_channel_context_new(chan,obj);
Simon Morlat's avatar
Simon Morlat committed
261 262 263
		*channels=belle_sip_list_prepend(*channels,chan);
	}
	belle_sip_object_unref(hop);
Simon Morlat's avatar
Simon Morlat committed
264
	split_request_url(req);
Simon Morlat's avatar
Simon Morlat committed
265 266
	belle_sip_channel_queue_message(chan,BELLE_SIP_MESSAGE(req));
	return 0;
Simon Morlat's avatar
Simon Morlat committed
267 268
}

Simon Morlat's avatar
Simon Morlat committed
269 270 271 272 273 274
int belle_http_provider_set_tls_verify_policy(belle_http_provider_t *obj, belle_tls_verify_policy_t *verify_ctx){
	SET_OBJECT_PROPERTY(obj,verify_ctx,verify_ctx);
	return 0;
}