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;
}