doubango/trunk/tinySIP/src/transports/tsip_transport.c

369 lines
10 KiB
C

/*
* Copyright (C) 2009 Mamadou Diop.
*
* Contact: Mamadou Diop <diopmamadou@yahoo.fr>
*
* This file is part of Open Source Doubango Framework.
*
* DOUBANGO 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.
*
* DOUBANGO 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 DOUBANGO.
*
*/
/**@file tsip_transport.c
* @brief SIP transport.
*
* @author Mamadou Diop <diopmamadou(at)yahoo.fr>
*
* @date Created: Sat Nov 8 16:54:58 2009 mdiop
*/
#include "tinySIP/transports/tsip_transport.h"
#include "tinySIP/transports/tsip_transport_ipsec.h"
#include "tinySIP/parsers/tsip_parser_uri.h"
#include "tsk_string.h"
#include "tsk_buffer.h"
#include "tsk_debug.h"
int tsip_transport_addvia(const tsip_transport_t* self, const char *branch, tsip_message_t *msg)
{
tnet_ip_t ip;
tnet_port_t port;
if(tsip_transport_get_ip_n_port(self, &ip, &port))
{
return -1;
}
if(!msg->firstVia)
{
/* RFC 3261 - 18.1.1 Sending Requests
Before a request is sent, the client transport MUST insert a value of
the "sent-by" field into the Via header field. This field contains
an IP address or host name, and port. The usage of an FQDN is
RECOMMENDED. This field is used for sending responses under certain
conditions, described below. If the port is absent, the default
value depends on the transport. It is 5060 for UDP, TCP and SCTP,
5061 for TLS.
*/
msg->firstVia = TSIP_HEADER_VIA_CREATE(TSIP_HEADER_VIA_PROTO_NAME_DEFAULT, TSIP_HEADER_VIA_PROTO_VERSION_DEFAULT,
self->via_protocol, ip, port);
TSIP_HEADER_ADD_PARAM(TSIP_HEADER(msg->firstVia), "rport", 0);
}
tsk_strupdate(&msg->firstVia->branch, branch);
if(0)
{
/* RFC 3261 - 18.1.1 Sending Requests (FIXME)
A client that sends a request to a multicast address MUST add the
"maddr" parameter to its Via header field value containing the
destination multicast address, and for IPv4, SHOULD add the "ttl"
parameter with a value of 1. Usage of IPv6 multicast is not defined
in this specification, and will be a subject of future
standardization when the need arises.
*/
}
/*
* comp=sigcomp; sigcomp-id=
*/
return 0;
}
int tsip_transport_msg_update(const tsip_transport_t* self, tsip_message_t *msg)
{
tnet_ip_t ip;
tnet_port_t port;
int ret = 0;
if(!msg->update){
return 0;
}
if(tsip_transport_get_ip_n_port(self, &ip, &port)){
return -1;
}
/* Host and port */
if(msg->Contact && msg->Contact->uri){
tsk_strupdate(&(msg->Contact->uri->scheme), self->scheme);
tsk_strupdate(&(msg->Contact->uri->host), ip);
msg->Contact->uri->port = port;
msg->Contact->uri->host_type = TNET_SOCKET_TYPE_IS_IPV6(self->type) ? host_ipv6 : host_ipv4;
tsk_params_add_param(&msg->Contact->uri->params, "transport", self->protocol);
}
/* IPSec headers */
if(TNET_SOCKET_TYPE_IS_IPSEC(self->type)){
ret = tsip_transport_ipsec_updateMSG(TSIP_TRANSPORT_IPSEC(self), msg);
}
/* SigComp */
msg->update = 0; /* To avoid update of retrans. msg */
return ret;
}
int tsip_transport_set_tlscerts(tsip_transport_t *self, const char* ca, const char* pbk, const char* pvk)
{
tnet_transport_t *transport = self->net_transport;
if(!self || !transport){
return -1;
}
tsk_strupdate(&transport->tls.ca, ca);
tsk_strupdate(&transport->tls.pvk, pvk);
tsk_strupdate(&transport->tls.pbk, pbk);
return 0;
}
size_t tsip_transport_send(const tsip_transport_t* self, const char *branch, tsip_message_t *msg, const char* destIP, int32_t destPort)
{
int ret = -1;
if(self)
{
tsk_buffer_t *buffer = 0;
/* Add Via */
if(TSIP_MESSAGE_IS_REQUEST(msg) && !TSIP_REQUEST_IS_CANCEL(msg)){
tsip_transport_addvia(self, branch, msg);
tsip_transport_msg_update(self, msg);
}
else if(TSIP_MESSAGE_IS_RESPONSE(msg)){
/* RFC 3581 - 4. Server Behavior
When a server compliant to this specification (which can be a proxy
or UAS) receives a request, it examines the topmost Via header field
value. If this Via header field value contains an "rport" parameter
with no value, it MUST set the value of the parameter to the source
port of the request.
*/
if(msg->firstVia->rport == 0){
/* As the response message has been built from the request ...then it's first via is the same as
the request's first via.
*/
msg->firstVia->rport = msg->firstVia->port;
}
}
buffer = TSK_BUFFER_CREATE_NULL();
if(buffer)
{
tsip_message_tostring(msg, buffer);
if(buffer->size >1300){
/* RFC 3261 - 18.1.1 Sending Requests (FIXME)
If a request is within 200 bytes of the path MTU, or if it is larger
than 1300 bytes and the path MTU is unknown, the request MUST be sent
using an RFC 2914 [43] congestion controlled transport protocol, such
as TCP. If this causes a change in the transport protocol from the
one indicated in the top Via, the value in the top Via MUST be
changed. This prevents fragmentation of messages over UDP and
provides congestion control for larger messages. However,
implementations MUST be able to handle messages up to the maximum
datagram packet size. For UDP, this size is 65,535 bytes, including
IP and UDP headers.
*/
}
if(TNET_SOCKET_TYPE_IS_IPSEC(self->type)){
tnet_fd_t fd = tsip_transport_ipsec_getFD(TSIP_TRANSPORT_IPSEC(self), TSIP_MESSAGE_IS_REQUEST(msg));
if(fd != TNET_INVALID_FD){
//struct sockaddr_storage to;
//tnet_sockaddr_init("2001:5c0:1502:1800::225", 4060, self->type, &to);
//tnet_sockfd_sendto(fd, (const struct sockaddr *)&to, buffer->data, buffer->size);
ret = tnet_sockfd_send(fd, buffer->data, buffer->size, 0);
}
}
else{
/*if(destIP && destPort)
{
struct sockaddr_storage to;
if(tnet_sockaddr_init(destIP, destPort, tsip_transport_get_socket_type(self), &to))
{
goto bail;
}
if(tnet_transport_sendto(self->net_transport, self->connectedFD, &to, buffer->data, buffer->size))
{
ret = 0;
}
}
else*/
{
if(tnet_transport_send(self->net_transport, self->connectedFD, buffer->data, buffer->size)){
ret = 0;
}
}
}
//bail:
TSK_OBJECT_SAFE_FREE(buffer);
}
}
return ret;
}
tsip_uri_t* tsip_transport_get_uri(const tsip_transport_t *self, int lr)
{
if(self)
{
tnet_ip_t ip;
tnet_port_t port;
tsip_uri_t* uri = 0;
if(!tnet_get_ip_n_port(self->connectedFD, &ip, &port))
{
char* uristring = 0;
int ipv6 = TNET_SOCKET_TYPE_IS_IPV6(self->type);
tsk_sprintf(&uristring, "%s:%s%s%s:%d;%s;transport=%s",
self->scheme,
ipv6 ? "[" : "",
ip,
ipv6 ? "]" : "",
port,
lr ? "lr" : "",
self->protocol);
if(uristring){
if((uri = tsip_uri_parse(uristring, strlen(uristring)))){
uri->host_type = ipv6 ? host_ipv6 : host_ipv4;
}
TSK_FREE(uristring);
}
}
return uri;
}
return 0;
}
int tsip_transport_init(tsip_transport_t* self, tnet_socket_type_t type, const tsip_stack_handle_t *stack, const char *host, tnet_port_t port, const char* description)
{
if(!self || self->initialized){
return -1;
}
self->stack = stack;
self->type = type;
self->net_transport = TNET_TRANSPORT_CREATE(host, port, type, description);
self->scheme = TNET_SOCKET_TYPE_IS_TLS(type) ? "sips" : "sip";
if(TNET_SOCKET_TYPE_IS_STREAM(type)){
self->protocol = "tcp";
self->via_protocol = "TCP";
self->service = "SIP+D2T";
if(TNET_SOCKET_TYPE_IS_TLS(type)){
self->via_protocol = "TLS";
self->service = "SIPS+D2T";
}
/* Stream buffer */
self->buff_stream = TSK_BUFFER_CREATE_NULL();
}
else{
self->protocol = "udp";
self->via_protocol = "UDP";
self->service = "SIP+D2U";
}
self->connectedFD = TNET_INVALID_FD;
self->initialized = 1;
return 0;
}
int tsip_transport_deinit(tsip_transport_t* self)
{
if(!self || !self->initialized){
return -1;
}
TSK_OBJECT_SAFE_FREE(self->net_transport);
TSK_OBJECT_SAFE_FREE(self->buff_stream);
self->initialized = 0;
return 0;
}
//========================================================
// SIP transport object definition
//
static void* tsip_transport_create(void * self, va_list * app)
{
tsip_transport_t *transport = self;
if(transport)
{
const tsip_stack_handle_t *stack = va_arg(*app, const tsip_stack_handle_t*);
const char *host = va_arg(*app, const char*);
#if defined(__GNUC__)
tnet_port_t port = (tnet_port_t)va_arg(*app, unsigned);
#else
tnet_port_t port = va_arg(*app, tnet_port_t);
#endif
tnet_socket_type_t type = va_arg(*app, tnet_socket_type_t);
const char *description = va_arg(*app, const char*);
if(tsip_transport_init(transport, type, stack, host, port, description)){
// Print error?
}
}
return self;
}
static void* tsip_transport_destroy(void * self)
{
tsip_transport_t *transport = self;
if(transport)
{
tsip_transport_deinit(transport);
}
return self;
}
static int tsip_transport_cmp(const void *obj1, const void *obj2)
{
const tsip_transport_t *transport1 = obj1;
const tsip_transport_t *transport2 = obj2;
if(transport1 && transport2)
{
const char* desc1 = tsip_transport_get_description(transport1);
const char* desc2 = tsip_transport_get_description(transport2);
return tsk_stricmp(desc1, desc2);
}
return -1;
}
static const tsk_object_def_t tsip_transport_def_s =
{
sizeof(tsip_transport_t),
tsip_transport_create,
tsip_transport_destroy,
tsip_transport_cmp,
};
const void *tsip_transport_def_t = &tsip_transport_def_s;