http-provider.c 8.44 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 35

struct belle_http_provider{
	belle_sip_stack_t *stack;
Simon Morlat's avatar
Simon Morlat committed
36
	char *bind_ip;
Simon Morlat's avatar
Simon Morlat committed
37
	int ai_family;
Simon Morlat's avatar
Simon Morlat committed
38 39 40 41
	belle_sip_list_t *tcp_channels;
	belle_sip_list_t *tls_channels;
};

Simon Morlat's avatar
Simon Morlat committed
42 43 44
#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
45
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
46
	belle_http_channel_context_t *ctx=BELLE_HTTP_CHANNEL_CONTEXT(obj);
Simon Morlat's avatar
Simon Morlat committed
47
	if (revents & BELLE_SIP_EVENT_READ){
Simon Morlat's avatar
Simon Morlat committed
48 49 50 51 52 53 54 55 56 57 58 59 60 61
		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)){
				belle_http_request_t *req=NULL;
				belle_http_response_event_t ev={0};
				/*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 0;
				}
				ev.provider=NULL;
				ev.request=req;
				ev.response=(belle_http_response_t*)msg;
Simon Morlat's avatar
Simon Morlat committed
62
				BELLE_HTTP_REQUEST_INVOKE_LISTENER(req,process_response,&ev);
Simon Morlat's avatar
Simon Morlat committed
63 64 65 66
				belle_sip_object_unref(req);
			}
			belle_sip_object_unref(msg);
		}
Simon Morlat's avatar
Simon Morlat committed
67 68 69 70 71 72
	}
	return 0;
}

static int channel_on_auth_requested(belle_sip_channel_listener_t *obj, belle_sip_channel_t *chan, const char* distinguished_name){
	if (BELLE_SIP_IS_INSTANCE_OF(chan,belle_sip_tls_channel_t)) {
Simon Morlat's avatar
Simon Morlat committed
73 74
		/*
		belle_http_provider_t *prov=BELLE_SIP_HTTP_PROVIDER(obj);
Simon Morlat's avatar
Simon Morlat committed
75 76 77 78
		belle_sip_auth_event_t* auth_event = belle_sip_auth_event_create(NULL,NULL);
		belle_sip_tls_channel_t *tls_chan=BELLE_SIP_TLS_CHANNEL(chan);
		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
79
		
Simon Morlat's avatar
Simon Morlat committed
80 81 82 83 84 85 86 87 88 89
		BELLE_SIP_PROVIDER_INVOKE_LISTENERS(prov->listeners,process_auth_requested,auth_event);
		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
90
	belle_http_channel_context_t *ctx=BELLE_HTTP_CHANNEL_CONTEXT(obj);
Simon Morlat's avatar
Simon Morlat committed
91
	ctx->pending_requests=belle_sip_list_append(ctx->pending_requests,belle_sip_object_ref(msg));
Simon Morlat's avatar
Simon Morlat committed
92 93 94
}

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
95
	belle_http_channel_context_t *ctx=BELLE_HTTP_CHANNEL_CONTEXT(obj);
Simon Morlat's avatar
Simon Morlat committed
96 97 98 99 100 101 102 103 104 105
	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
106
			if (!chan->force_close) provider_remove_channel(ctx->provider,chan);
Simon Morlat's avatar
Simon Morlat committed
107 108
			break;
	}
Simon Morlat's avatar
Simon Morlat committed
109 110
}

Simon Morlat's avatar
Simon Morlat committed
111
static void belle_http_channel_context_uninit(belle_http_channel_context_t *obj){
Simon Morlat's avatar
Simon Morlat committed
112
	belle_sip_list_free_with_data(obj->pending_requests,belle_sip_object_unref);
Simon Morlat's avatar
Simon Morlat committed
113 114
}

Simon Morlat's avatar
Simon Morlat committed
115 116 117 118 119 120 121 122 123 124
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
125
	belle_http_channel_context_t *obj=belle_sip_object_new(belle_http_channel_context_t);
Simon Morlat's avatar
Simon Morlat committed
126
	obj->provider=prov;
Simon Morlat's avatar
Simon Morlat committed
127
	belle_sip_channel_add_listener(chan,(belle_sip_channel_listener_t*)obj);
Simon Morlat's avatar
Simon Morlat committed
128
	belle_sip_object_weak_ref(chan,(belle_sip_object_destroy_notify_t)on_channel_destroyed,obj);
Simon Morlat's avatar
Simon Morlat committed
129 130
	return obj;
}
Simon Morlat's avatar
Simon Morlat committed
131

Simon Morlat's avatar
Simon Morlat committed
132
BELLE_SIP_IMPLEMENT_INTERFACE_BEGIN(belle_http_channel_context_t,belle_sip_channel_listener_t)
Simon Morlat's avatar
Simon Morlat committed
133 134 135 136 137 138
	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
139 140
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
141 142

static void http_provider_uninit(belle_http_provider_t *obj){
Simon Morlat's avatar
Simon Morlat committed
143 144 145 146
	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
147 148
}

Simon Morlat's avatar
Simon Morlat committed
149
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_http_provider_t);
Simon Morlat's avatar
Simon Morlat committed
150 151
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
152
belle_http_provider_t *belle_http_provider_new(belle_sip_stack_t *s, const char *bind_ip){
Simon Morlat's avatar
Simon Morlat committed
153
	belle_http_provider_t *p=belle_sip_object_new(belle_http_provider_t);
Simon Morlat's avatar
Simon Morlat committed
154
	p->stack=s;
Simon Morlat's avatar
Simon Morlat committed
155
	p->bind_ip=belle_sip_strdup(bind_ip);
Simon Morlat's avatar
Simon Morlat committed
156
	p->ai_family=strchr(p->bind_ip,':') ? AF_INET6 : AF_INET;
Simon Morlat's avatar
Simon Morlat committed
157 158
	return p;
}
Simon Morlat's avatar
Simon Morlat committed
159

Simon Morlat's avatar
Simon Morlat committed
160 161 162
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
163 164
	char *host_value;
	
Simon Morlat's avatar
Simon Morlat committed
165
	belle_generic_uri_set_path(new_uri,belle_generic_uri_get_path(uri));
Simon Morlat's avatar
Simon Morlat committed
166 167 168 169 170 171
	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
172 173 174 175 176 177
	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
178
	else{
Simon Morlat's avatar
Simon Morlat committed
179 180
		belle_sip_error("belle_http_provider_send_request(): unsupported transport %s",transport_name);
		return NULL;
Simon Morlat's avatar
Simon Morlat committed
181
	}
Simon Morlat's avatar
Simon Morlat committed
182 183 184 185 186 187 188 189 190 191 192 193
}

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);
	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
194
	
Simon Morlat's avatar
Simon Morlat committed
195 196
	belle_http_request_set_listener(req,listener);
	
Simon Morlat's avatar
Simon Morlat committed
197
	chan=belle_sip_channel_find_from_list(*channels,obj->ai_family, hop);
Simon Morlat's avatar
Simon Morlat committed
198 199 200
	
	if (!chan){
		chan=belle_sip_stream_channel_new_client(obj->stack,obj->bind_ip,0,hop->cname,hop->host,hop->port);
Simon Morlat's avatar
Simon Morlat committed
201
		belle_http_channel_context_new(chan,obj);
Simon Morlat's avatar
Simon Morlat committed
202 203 204
		*channels=belle_sip_list_prepend(*channels,chan);
	}
	belle_sip_object_unref(hop);
Simon Morlat's avatar
Simon Morlat committed
205
	split_request_url(req);
Simon Morlat's avatar
Simon Morlat committed
206 207
	belle_sip_channel_queue_message(chan,BELLE_SIP_MESSAGE(req));
	return 0;
Simon Morlat's avatar
Simon Morlat committed
208 209
}