Commit 1cbb4291 authored by Tristan Matthews's avatar Tristan Matthews

Merge branch 'master' of...

Merge branch 'master' of git+ssh://git.sflphone.org/var/repos/sflphone/git/sflphone into video_preview
parents 85a0ab37 c524e9c9
......@@ -99,6 +99,7 @@ SIPAccount::SIPAccount(const std::string& accountID)
, keepAliveTimer_()
, link_(SIPVoIPLink::instance())
, receivedParameter_()
, rPort_(-1)
{}
void SIPAccount::serialize(Conf::YamlEmitter &emitter)
......@@ -813,7 +814,7 @@ void SIPAccount::setContactHeader(std::string address, std::string port)
std::string SIPAccount::getContactHeader() const
{
if (transport_ == NULL)
ERROR("Transport not created yet");
ERROR("SipAccount: Transport not created yet");
// The transport type must be specified, in our case START_OTHER refers to stun transport
pjsip_transport_type_e transportType = transportType_;
......@@ -826,8 +827,18 @@ std::string SIPAccount::getContactHeader() const
// Else we determine this infor based on transport information
std::string address, port;
std::ostringstream portstr;
link_->sipTransport.findLocalAddressFromTransport(transport_, transportType, address, port);
if (!receivedParameter_.empty())
address = receivedParameter_;
if (rPort_ != -1) {
portstr << rPort_;
port = portstr.str();
}
// UDP does not require the transport specification
std::string scheme;
std::string transport;
......
......@@ -505,13 +505,26 @@ class SIPAccount : public Account {
return receivedParameter_;
}
int getRPort() const {
if (rPort_ == -1)
return localPort_;
else
return rPort_;
}
void setRPort(int rPort) { rPort_ = rPort; }
/**
* Timer used to periodically send re-register request based
* on the "Expire" sip header (or the "expire" Contact parameter)
*/
static void keepAliveRegistrationCb(pj_timer_heap_t *th, pj_timer_entry *te);
/**
* Pointer to the transport used by this acccount
*/
pjsip_transport* transport_;
private:
NON_COPYABLE(SIPAccount);
......@@ -730,9 +743,14 @@ class SIPAccount : public Account {
SIPVoIPLink* link_;
/**
* Received via parameters
* Optional: "received" parameter from VIA header
*/
std::string receivedParameter_;
/**
* Optional: "rport" parameter from VIA header
*/
int rPort_;
};
#endif
......@@ -54,6 +54,7 @@
#include "sipaccount.h"
#include "pjsip/sip_types.h"
#include "dbus/dbusmanager.h"
#include "dbus/configurationmanager.h"
......@@ -428,6 +429,9 @@ SipTransport::createUdpTransport(const std::string &interface, unsigned int port
pj_sockaddr_parse(pj_AF_UNSPEC(), 0, &udpString, &boundAddr);
pj_status_t status;
pjsip_transport *transport = NULL;
if (boundAddr.addr.sa_family == pj_AF_INET()) {
status = pjsip_udp_transport_start(endpt_, &boundAddr.ipv4, NULL, 1, &transport);
if (status != PJ_SUCCESS) {
......@@ -448,6 +452,54 @@ SipTransport::createUdpTransport(const std::string &interface, unsigned int port
return transport;
}
pjsip_transport *
SipTransport::createUdpTransport(const std::string &interface, unsigned int port, const std::string &publicAddr, unsigned int publicPort)
{
// init socket to bind this transport to
pj_uint16_t listeningPort = (pj_uint16_t) port;
pjsip_transport *transport = NULL;
DEBUG("SipTransport: Update UDP transport on %s:%d with public addr %s:%d",
interface.c_str(), port, publicAddr.c_str(), publicPort);
// determine the ip address for this transport
std::string listeningAddress;
if (interface == DEFAULT_INTERFACE)
listeningAddress = getSIPLocalIP();
else
listeningAddress = getInterfaceAddrFromName(interface);
if (listeningAddress.empty()) {
ERROR("SipTransport: Could not determine ip address for this transport");
return NULL;
}
std::ostringstream fullAddress;
fullAddress << listeningAddress << ":" << listeningPort;
pj_str_t udpString;
std::string fullAddressStr(fullAddress.str());
pj_cstr(&udpString, fullAddressStr.c_str());
pj_sockaddr boundAddr;
pj_sockaddr_parse(pj_AF_UNSPEC(), 0, &udpString, &boundAddr);
pj_str_t public_addr = pj_str((char *) publicAddr.c_str());
pjsip_host_port hostPort;
hostPort.host = public_addr;
hostPort.port = publicPort;
pj_status_t status;
// status = pjsip_udp_transport_restart(transport, PJSIP_UDP_TRANSPORT_DESTROY_SOCKET, PJ_INVALID_SOCKET, &boundAddr.ipv4, &hostPort);
status = pjsip_udp_transport_start(endpt_, &boundAddr.ipv4, &hostPort, 1, &transport);
if (status != PJ_SUCCESS) {
ERROR("SipTransport: Could not start new transport with address %s:%d, error code %d", publicAddr.c_str(), publicPort, status);
}
// dump debug information to stdout
pjsip_tpmgr_dump_transports(pjsip_endpt_get_tpmgr(endpt_));
return transport;
}
pjsip_tpselector *SipTransport::initTransportSelector(pjsip_transport *transport, pj_pool_t *tp_pool) const
{
if (!transport) {
......
......@@ -101,6 +101,10 @@ class SipTransport {
*/
void createSipTransport(SIPAccount &account);
/**
* Create the default sip transport on 5060. In case this port is already used
* increme
*/
void createDefaultSipUdpTransport();
/**
......@@ -126,6 +130,18 @@ class SipTransport {
*/
void findLocalAddressFromTransport(pjsip_transport *transport, pjsip_transport_type_e transportType, std::string &address, std::string &port) const;
/**
* Create a new udp transport specifying the bound address AND the published address.
* The published address is the address to appears in the sip VIA header. This is used
* essentially when the client is behind a trafic routing device.
*
* @param The interface to bind this transport with
* @param The requested udp port number
* @param The public address for this transport
* @param The public port for this transport
*/
pjsip_transport *createUdpTransport(const std::string &interface, unsigned int port, const std::string &publicAddr, unsigned int publicPort);
private:
NON_COPYABLE(SipTransport);
......
......@@ -498,6 +498,7 @@ bool SIPVoIPLink::getEvent()
void SIPVoIPLink::sendRegister(Account *a)
{
SIPAccount *account = dynamic_cast<SIPAccount*>(a);
if (!account)
throw VoipLinkException("SipVoipLink: Account is not SIPAccount");
sipTransport.createSipTransport(*account);
......@@ -520,10 +521,24 @@ void SIPVoIPLink::sendRegister(Account *a)
std::string from(account->getFromUri());
pj_str_t pjFrom = pj_str((char*) from.c_str());
// Get the contact header for this account
std::string contact(account->getContactHeader());
// Get the received header
std::string received(account->getReceivedParameter());
// Get the contact header
std::string contact = account->getContactHeader();
pj_str_t pjContact = pj_str((char*) contact.c_str());
if (!received.empty()) {
// Set received parameter string to empty in order to avoid creating new transport for each register
account->setReceivedParameter("");
// Explicitely set the bound address port to 0 so that pjsip determine a random port by itself
account->transport_= sipTransport.createUdpTransport(account->getLocalInterface(), 0, received, account->getRPort());
account->setRPort(-1);
if(account->transport_ == NULL) {
ERROR("UserAgent: Could not create new udp transport with public address: %s:%d", received.c_str(), account->getLocalPort());
}
}
if (pjsip_regc_init(regc, &pjSrv, &pjFrom, &pjFrom, 1, &pjContact, account->getRegistrationExpire()) != PJ_SUCCESS)
throw VoipLinkException("Unable to initialize account registration structure");
......@@ -542,7 +557,6 @@ void SIPVoIPLink::sendRegister(Account *a)
pj_list_push_back(&hdr_list, (pjsip_hdr*) h);
pjsip_regc_add_headers(regc, &hdr_list);
pjsip_tx_data *tdata;
if (pjsip_regc_register(regc, PJ_TRUE, &tdata) != PJ_SUCCESS)
......@@ -1641,6 +1655,8 @@ void lookForReceivedParameter(pjsip_regc_cbparam *param, SIPAccount *account)
DEBUG("Cool received received parameter... uhhh?, the value is %s", publicIpFromReceived.c_str());
account->setReceivedParameter(publicIpFromReceived);
}
account->setRPort(param->rdata->msg_info.via->rport_param);
}
void registration_cb(pjsip_regc_cbparam *param)
......@@ -1657,6 +1673,11 @@ void registration_cb(pjsip_regc_cbparam *param)
return;
}
if(param->code == 200) {
account->setRegister(true);
account->setRegistrationState(Registered);
}
if (account->isContactUpdateEnabled())
update_contact_header(param, account);
......@@ -1674,7 +1695,6 @@ void registration_cb(pjsip_regc_cbparam *param)
if (param->status != PJ_SUCCESS) {
account->setRegistrationState(ErrorAuth);
account->setRegister(false);
SIPVoIPLink::instance()->sipTransport.shutdownSipTransport(*account);
return;
}
......@@ -1684,34 +1704,39 @@ void registration_cb(pjsip_regc_cbparam *param)
case PJSIP_SC_NOT_ACCEPTABLE_ANYWHERE:
lookForReceivedParameter(param, account);
account->setRegistrationState(ErrorNotAcceptable);
SIPVoIPLink::instance()->sendRegister(account);
break;
case PJSIP_SC_SERVICE_UNAVAILABLE:
case PJSIP_SC_REQUEST_TIMEOUT:
account->setRegistrationState(ErrorHost);
account->setRegister(false);
SIPVoIPLink::instance()->sipTransport.shutdownSipTransport(*account);
break;
case PJSIP_SC_UNAUTHORIZED:
case PJSIP_SC_FORBIDDEN:
case PJSIP_SC_NOT_FOUND:
account->setRegistrationState(ErrorAuth);
account->setRegister(false);
SIPVoIPLink::instance()->sipTransport.shutdownSipTransport(*account);
break;
case PJSIP_SC_INTERVAL_TOO_BRIEF:
// Expiration Interval Too Brief
account->doubleRegistrationExpire();
account->registerVoIPLink();
account->setRegister(false);
SIPVoIPLink::instance()->sipTransport.shutdownSipTransport(*account);
break;
default:
account->setRegistrationState(Error);
account->setRegister(false);
SIPVoIPLink::instance()->sipTransport.shutdownSipTransport(*account);
break;
}
account->setRegister(false);
SIPVoIPLink::instance()->sipTransport.shutdownSipTransport(*account);
} else {
if (account->isRegistered())
account->setRegistrationState(Registered);
......
......@@ -505,8 +505,7 @@ static void use_sip_tls_cb(GtkWidget *widget, gpointer data)
gtk_widget_set_sensitive(use_stun_check_box, FALSE);
gtk_widget_set_sensitive(same_as_local_radio_button, TRUE);
gtk_widget_set_sensitive(published_addr_radio_button, TRUE);
gtk_widget_hide(stun_server_label);
gtk_widget_hide(stun_server_entry);
gtk_widget_set_sensitive(stun_server_entry, FALSE);
if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(same_as_local_radio_button))) {
gtk_widget_show(published_address_entry);
......@@ -523,6 +522,7 @@ static void use_sip_tls_cb(GtkWidget *widget, gpointer data)
gtk_widget_set_sensitive(published_addr_radio_button, FALSE);
gtk_widget_show(stun_server_label);
gtk_widget_show(stun_server_entry);
gtk_widget_set_sensitive(stun_server_entry, TRUE);
gtk_widget_hide(published_address_entry);
gtk_widget_hide(published_port_spin_box);
gtk_widget_hide(published_address_label);
......@@ -530,8 +530,7 @@ static void use_sip_tls_cb(GtkWidget *widget, gpointer data)
} else {
gtk_widget_set_sensitive(same_as_local_radio_button, TRUE);
gtk_widget_set_sensitive(published_addr_radio_button, TRUE);
gtk_widget_hide(stun_server_label);
gtk_widget_hide(stun_server_entry);
gtk_widget_set_sensitive(stun_server_entry, FALSE);
}
}
}
......@@ -609,6 +608,7 @@ static void use_stun_cb(GtkWidget *widget, gpointer data UNUSED)
DEBUG("Config: Showing stun options, hiding Local/Published info");
gtk_widget_show(stun_server_label);
gtk_widget_show(stun_server_entry);
gtk_widget_set_sensitive(stun_server_entry, TRUE);
gtk_widget_set_sensitive(same_as_local_radio_button, FALSE);
gtk_widget_set_sensitive(published_addr_radio_button, FALSE);
......@@ -617,9 +617,8 @@ static void use_stun_cb(GtkWidget *widget, gpointer data UNUSED)
gtk_widget_hide(published_address_entry);
gtk_widget_hide(published_port_spin_box);
} else {
DEBUG("Config: hiding stun options, showing Local/Published info");
gtk_widget_hide(stun_server_label);
gtk_widget_hide(stun_server_entry);
DEBUG("Config: disabling stun options, showing Local/Published info");
gtk_widget_set_sensitive(stun_server_entry, FALSE);
gtk_widget_set_sensitive(same_as_local_radio_button, TRUE);
gtk_widget_set_sensitive(published_addr_radio_button, TRUE);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment