diff --git a/sflphone-client-gnome/VERSION b/sflphone-client-gnome/VERSION index 517317e95fb23bda5f1c305dfaa84bfa8021a824..bc440692c3b559a2d3fe749ce99f8993b879252f 100644 --- a/sflphone-client-gnome/VERSION +++ b/sflphone-client-gnome/VERSION @@ -1 +1 @@ -0.9.6~beta +0.9.6~rc1 diff --git a/sflphone-common/VERSION b/sflphone-common/VERSION index 517317e95fb23bda5f1c305dfaa84bfa8021a824..bc440692c3b559a2d3fe749ce99f8993b879252f 100644 --- a/sflphone-common/VERSION +++ b/sflphone-common/VERSION @@ -1 +1 @@ -0.9.6~beta +0.9.6~rc1 diff --git a/sflphone-common/configure.ac b/sflphone-common/configure.ac index b39dc0343faa0146a480fe1388fc95212f2c7c65..92c734e3d61ae39012220437756c563118fd5a26 100644 --- a/sflphone-common/configure.ac +++ b/sflphone-common/configure.ac @@ -2,7 +2,7 @@ dnl SFLPhone - configure.ac for automake 1.9 and autoconf 2.59 dnl dnl Process this file with autoconf to produce a configure script. AC_PREREQ(2.59) - AC_INIT([SFLphone],[0.9.6~beta],[sflphoneteam@savoirfairelinux.com],[sflphone]) + AC_INIT([SFLphone],[0.9.6~rc1],[sflphoneteam@savoirfairelinux.com],[sflphone]) AC_COPYRIGHT([[Copyright (c) Savoir-Faire Linux 2004-2009]]) AC_REVISION([$Revision$]) diff --git a/sflphone-common/src/config/config.cpp b/sflphone-common/src/config/config.cpp index 9c6bb914baf03d73aaa73f94d6f6b2b5340730e5..4f8c02c8de554f762e1963133d452c67122e1654 100644 --- a/sflphone-common/src/config/config.cpp +++ b/sflphone-common/src/config/config.cpp @@ -22,6 +22,9 @@ #include "../global.h" #include <fstream> #include <cstdlib> +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> namespace Conf { @@ -255,7 +258,11 @@ ConfigTree::saveConfigTree (const std::string& fileName) } file.close(); - + + if(chmod(fileName.c_str(), S_IRUSR | S_IWUSR)) { + _debug("Failed to set permission on configuration file because: %s\n",strerror(errno)); + } + return true; } @@ -267,7 +274,7 @@ int ConfigTree::populateFromFile (const std::string& fileName) { bool out = false; - + if (fileName.empty()) { return 0; } @@ -332,7 +339,11 @@ ConfigTree::populateFromFile (const std::string& fileName) } file.close(); - + + if(chmod(fileName.c_str(), S_IRUSR | S_IWUSR)) { + _debug("Failed to set permission on configuration file because: %s\n",strerror(errno)); + } + return 1; } diff --git a/sflphone-common/src/config/config.h b/sflphone-common/src/config/config.h index 0872889486659d2a7db64634106f36fcb58ce3a0..0fa75a24acd2e580d1ddb457179f8091507f6d3b 100644 --- a/sflphone-common/src/config/config.h +++ b/sflphone-common/src/config/config.h @@ -155,7 +155,7 @@ class ConfigTree * List of sections. Each sections has an ItemList as child */ SectionMap _sections; - + friend class ConfigTreeIterator; public: diff --git a/sflphone-common/src/global.h b/sflphone-common/src/global.h index d08d9ce8524dddad65ddb2831421baf27eaa2d62..a6053980b86bb7f1947ff03ca7b9da1f55dee94c 100644 --- a/sflphone-common/src/global.h +++ b/sflphone-common/src/global.h @@ -32,7 +32,7 @@ #include <map> #include <vector> -#define SFLPHONED_VERSION "0.9.6~beta" /** Version number */ +#define SFLPHONED_VERSION "0.9.6~rc1" /** Version number */ #define HOMEDIR (getenv ("HOME")) /** Home directory */ diff --git a/sflphone-common/src/managerimpl.cpp b/sflphone-common/src/managerimpl.cpp index 7a49b2c04a3948237400173cfd5e3859ec6f01c7..345fb7df667cac41ccbd41ddfaa2c03bea97e44a 100644 --- a/sflphone-common/src/managerimpl.cpp +++ b/sflphone-common/src/managerimpl.cpp @@ -1293,7 +1293,7 @@ ManagerImpl::createSettingsPath (void) { _path = std::string (HOMEDIR) + DIR_SEPARATOR_STR + "." + PROGDIR; - if (mkdir (_path.data(), 0755) != 0) { + if (mkdir (_path.data(), 0600) != 0) { // If directory creation failed if (errno != EEXIST) { _debug ("Cannot create directory: %s\n", strerror (errno)); @@ -1952,31 +1952,7 @@ void ManagerImpl::setAudioManager (const int32_t& api) switchAudioManager(); return; - - /* - int manager; - - _debug(" ManagerImpl::setAudioManager :: %i \n",api); - - manager = api; - if( manager == PULSEAUDIO ) - { - if(app_is_running("pulseaudio") != 0) - { - // The pulseaudio daemon is not running - manager = ALSA; - notifyErrClient(PULSEAUDIO_NOT_RUNNING); - } - } - - if(manager == api) - { - // it means that we can change the audio manager - setConfig( PREFERENCES , CONFIG_AUDIO , api) ; - switchAudioManager(); - } - */ - + } int32_t diff --git a/sflphone-common/src/sdp.cpp b/sflphone-common/src/sdp.cpp index 9256b238b8ca8db8dd1cf6341e296940d5b1c4da..8c79cb36dd98489ccf568fc3bf27e12335a36aff 100644 --- a/sflphone-common/src/sdp.cpp +++ b/sflphone-common/src/sdp.cpp @@ -180,7 +180,6 @@ int Sdp::receiving_initial_offer (pjmedia_sdp_session* remote) // pjmedia_sdp_neg_create_w_remote_offer with the remote offer, and by providing the local offer ( optional ) pj_status_t status; - pjmedia_sdp_neg_state state; _debug ("Receiving initial offer\n"); @@ -200,13 +199,68 @@ int Sdp::receiving_initial_offer (pjmedia_sdp_session* remote) status = pjmedia_sdp_neg_create_w_remote_offer (_pool, get_local_sdp_session(), remote, &_negociator); - state = pjmedia_sdp_neg_get_state (_negociator); - PJ_ASSERT_RETURN (status == PJ_SUCCESS, 1); return PJ_SUCCESS; } +pj_status_t Sdp::check_sdp_answer(pjsip_inv_session *inv, pjsip_rx_data *rdata) +{ + static const pj_str_t str_application = { "application", 11 }; + static const pj_str_t str_sdp = { "sdp", 3 }; + pj_status_t status; + pjsip_msg * message = NULL; + pjmedia_sdp_session * remote_sdp = NULL; + + if (pjmedia_sdp_neg_get_state(inv->neg) == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER) { + + message = rdata->msg_info.msg; + + if(message == NULL) { + _debug("No message"); + return PJMEDIA_SDP_EINSDP; + } + + if (message->body == NULL) { + _debug("Empty message body\n"); + return PJMEDIA_SDP_EINSDP; + } + + if (pj_stricmp(&message->body->content_type.type, &str_application) || pj_stricmp(&message->body->content_type.subtype, &str_sdp)) { + _debug("Incoming Message does not contain SDP\n"); + return PJMEDIA_SDP_EINSDP; + } + + // Parse the SDP body. + status = pjmedia_sdp_parse(rdata->tp_info.pool, (char*)message->body->data, message->body->len, &remote_sdp); + if (status == PJ_SUCCESS) { + status = pjmedia_sdp_validate(remote_sdp); + } + + if (status != PJ_SUCCESS) { + _debug("SDP cannot be validated\n"); + return PJMEDIA_SDP_EINSDP; + } + + // This is an answer + _debug("Got SDP answer %s\n", pjsip_rx_data_get_info(rdata)); + status = pjmedia_sdp_neg_set_remote_answer(inv->pool, inv->neg, remote_sdp); + + if (status != PJ_SUCCESS) { + _debug("An error occured while processing remote answer %s\n", pjsip_rx_data_get_info(rdata)); + return PJMEDIA_SDP_EINSDP; + } + + // Prefer our codecs to remote when possible + pjmedia_sdp_neg_set_prefer_remote_codec_order(inv->neg, 0); + + status = pjmedia_sdp_neg_negotiate(inv->pool, inv->neg, 0); + _debug("Negotiation returned with status %d PJ_SUCCESS being %d\n", status, PJ_SUCCESS); + } + + return status; +} + void Sdp::sdp_add_protocol (void) { this->_local_offer->origin.version = 0; @@ -298,7 +352,7 @@ void Sdp::clean_session_media() _session_media.clear(); } -void Sdp::set_negociated_offer (const pjmedia_sdp_session *sdp) +void Sdp::set_negotiated_sdp (const pjmedia_sdp_session *sdp) { int nb_media, nb_codecs; @@ -308,7 +362,6 @@ void Sdp::set_negociated_offer (const pjmedia_sdp_session *sdp) std::string type, dir; CodecsMap codecs_list; CodecsMap::iterator iter; - AudioCodec *codec_to_add; pjmedia_sdp_attr *attribute; pjmedia_sdp_rtpmap *rtpmap; diff --git a/sflphone-common/src/sdp.h b/sflphone-common/src/sdp.h index ec3178955b57c5370872d43ada2c92302f9f18af..fcd28db15eabc1aabfc0b0d91292829037572204 100644 --- a/sflphone-common/src/sdp.h +++ b/sflphone-common/src/sdp.h @@ -25,6 +25,8 @@ #include <pjmedia/sdp_neg.h> #include <pjsip/sip_transport.h> #include <pjlib.h> +#include <pjsip_ua.h> +#include <pjmedia/errno.h> #include <pj/pool.h> #include <pj/assert.h> @@ -97,6 +99,17 @@ class Sdp { */ int receiving_initial_offer( pjmedia_sdp_session* remote ); + /* + * On receiving a message, check if it contains SDP and negotiate. Should be used for + * SDP answer and offer but currently is only used for answer. + * SDP negociator instance with the remote offer. + * + * @param inv The the invitation + * @param rdata The remote data + */ + + pj_status_t check_sdp_answer(pjsip_inv_session *inv, pjsip_rx_data *rdata); + /* * Remove all media in the session media vector. */ @@ -138,7 +151,7 @@ class Sdp { * * @param sdp the negociated offer */ - void set_negociated_offer( const pjmedia_sdp_session *sdp ); + void set_negotiated_sdp ( const pjmedia_sdp_session *sdp ); /* * Attribute the specified port to every medias provided diff --git a/sflphone-common/src/sipvoiplink.cpp b/sflphone-common/src/sipvoiplink.cpp index af41b6d268c760870fcca500204e488df9331432..7d402327517b2d17505b39c2e501abd055f32681 100644 --- a/sflphone-common/src/sipvoiplink.cpp +++ b/sflphone-common/src/sipvoiplink.cpp @@ -503,7 +503,6 @@ SIPVoIPLink::newOutgoingCall (const CallID& id, const std::string& toUrl) SIPCall* call = new SIPCall (id, Call::Outgoing, _pool); - if (call) { account = dynamic_cast<SIPAccount *> (Manager::instance().getAccount (Manager::instance().getAccountFromCall (id))); @@ -520,7 +519,6 @@ SIPVoIPLink::newOutgoingCall (const CallID& id, const std::string& toUrl) setCallAudioLocal (call, getLocalIPAddress(), useStun(), getStunServer()); - try { _debug ("CREATE NEW RTP SESSION FROM NEWOUTGOINGCALL\n"); _audiortp->createNewSession (call); @@ -528,9 +526,6 @@ SIPVoIPLink::newOutgoingCall (const CallID& id, const std::string& toUrl) _debug ("Failed to create rtp thread from newOutGoingCall\n"); } - - - call->initRecFileName(); _debug ("Try to make a call to: %s with call ID: %s\n", toUrl.data(), id.data()); @@ -560,8 +555,6 @@ SIPVoIPLink::newOutgoingCall (const CallID& id, const std::string& toUrl) bool SIPVoIPLink::answer (const CallID& id) { - - int i; SIPCall *call; pj_status_t status; pjsip_tx_data *tdata; @@ -1415,7 +1408,6 @@ bool get_dns_server_addresses (std::vector<std::string> *servers) nameservers.push_back (inet_ntoa (address)); } - //nameservers.push_back ("192.168.50.3"); *servers = nameservers; return true; @@ -1427,8 +1419,6 @@ pj_status_t SIPVoIPLink::enable_dns_srv_resolver (pjsip_endpoint *endpt, pj_dns_ pj_status_t status; pj_dns_resolver *resv; std::vector <std::string> dns_servers; - pj_uint16_t port = 5353; - pjsip_resolver_t *res; int scount, i; // Create the DNS resolver instance @@ -1706,13 +1696,10 @@ int SIPVoIPLink::createUDPServer (void) pj_sockaddr_in bound_addr; pjsip_host_port a_name; char tmpIP[32]; - pj_sock_t sock; - // Init bound address to ANY pj_memset (&bound_addr, 0, sizeof (bound_addr)); - bound_addr.sin_addr.s_addr = pj_htonl (PJ_INADDR_ANY); bound_addr.sin_port = pj_htons ( (pj_uint16_t) _localPort); bound_addr.sin_family = PJ_AF_INET; @@ -1875,22 +1862,17 @@ void SIPVoIPLink::handle_reinvite (SIPCall *call) } } - -/*******************************/ -/* CALLBACKS IMPLEMENTATION */ -/*******************************/ - +// This callback is called when the invite session state has changed void call_on_state_changed (pjsip_inv_session *inv, pjsip_event *e) { - _debug ("--------------------- call_on_state_changed --------------------- %i\n", inv->state); SIPCall *call; AccountID accId; SIPVoIPLink *link; pjsip_rx_data *rdata; - - + pj_status_t status; + /* Retrieve the call information */ call = reinterpret_cast<SIPCall*> (inv->mod_data[_mod_ua.id]); @@ -1900,7 +1882,7 @@ void call_on_state_changed (pjsip_inv_session *inv, pjsip_event *e) //Retrieve the body message rdata = e->body.tsx_state.src.rdata; - + /* If this is an outgoing INVITE that was created because of * REFER/transfer, send NOTIFY to transferer. */ @@ -1961,84 +1943,79 @@ void call_on_state_changed (pjsip_inv_session *inv, pjsip_event *e) } } } - } else { + + return; + } + + // The call is ringing - We need to handle this case only on outgoing call + if (inv->state == PJSIP_INV_STATE_EARLY && e->body.tsx_state.tsx->role == PJSIP_ROLE_UAC) { + call->setConnectionState (Call::Ringing); + Manager::instance().peerRingingCall (call->getCallId()); + } + // After 2xx is sent/received. + else if (inv->state == PJSIP_INV_STATE_CONNECTING) { + status = call->getLocalSDP()->check_sdp_answer (inv, rdata); + if (status != PJ_SUCCESS) { + _debug("Failed to check_incoming_sdp in call_on_state_changed\n"); + return; + } + } + // After we sent or received a ACK - The connection is established + else if (inv->state == PJSIP_INV_STATE_CONFIRMED) { - // The call is ringing - We need to handle this case only on outgoing call - if (inv->state == PJSIP_INV_STATE_EARLY && e->body.tsx_state.tsx->role == PJSIP_ROLE_UAC) { - call->setConnectionState (Call::Ringing); - Manager::instance().peerRingingCall (call->getCallId()); + /* If the call is a direct IP-to-IP call */ + if (call->getCallConfiguration () == Call::IPtoIP) { + link = SIPVoIPLink::instance (""); + } else { + accId = Manager::instance().getAccountFromCall (call->getCallId()); + link = dynamic_cast<SIPVoIPLink *> (Manager::instance().getAccountLink (accId)); } - // We receive a ACK - The connection is established - else if (inv->state == PJSIP_INV_STATE_CONFIRMED) { + if (link) + link->SIPCallAnswered (call, rdata); + } + else if (inv->state == PJSIP_INV_STATE_DISCONNECTED) { + _debug ("------------------- Call disconnected ---------------------\n"); + _debug ("State: %i, Disconnection cause: %i\n", inv->state, inv->cause); - /* If the call is a direct IP-to-IP call */ - if (call->getCallConfiguration () == Call::IPtoIP) { - link = SIPVoIPLink::instance (""); - } else { + switch (inv->cause) { + /* The call terminates normally - BYE / CANCEL */ + case PJSIP_SC_OK: + case PJSIP_SC_DECLINE: + case PJSIP_SC_REQUEST_TERMINATED: accId = Manager::instance().getAccountFromCall (call->getCallId()); link = dynamic_cast<SIPVoIPLink *> (Manager::instance().getAccountLink (accId)); - } - - if (link) - link->SIPCallAnswered (call, rdata); - } - - else if (inv->state == PJSIP_INV_STATE_DISCONNECTED) { - int count = 0; - _debug ("------------------- Call disconnected ---------------------\n"); - _debug ("State: %i, Disconnection cause: %i\n", inv->state, inv->cause); - - switch (inv->cause) { - /* The call terminates normally - BYE / CANCEL */ - - case PJSIP_SC_OK: - - case PJSIP_SC_DECLINE: - - case PJSIP_SC_REQUEST_TERMINATED: - - accId = Manager::instance().getAccountFromCall (call->getCallId()); - link = dynamic_cast<SIPVoIPLink *> (Manager::instance().getAccountLink (accId)); - - if (link) { - link->SIPCallClosed (call); - } - - break; - - /* The call connection failed */ - - case PJSIP_SC_NOT_FOUND: /* peer not found */ - - case PJSIP_SC_REQUEST_TIMEOUT: /* request timeout */ - - case PJSIP_SC_NOT_ACCEPTABLE_HERE: /* no compatible codecs */ - case PJSIP_SC_NOT_ACCEPTABLE_ANYWHERE: - - case PJSIP_SC_UNSUPPORTED_MEDIA_TYPE: - - case PJSIP_SC_UNAUTHORIZED: - - case PJSIP_SC_REQUEST_PENDING: - accId = Manager::instance().getAccountFromCall (call->getCallId()); - link = dynamic_cast<SIPVoIPLink *> (Manager::instance().getAccountLink (accId)); + if (link) { + link->SIPCallClosed (call); + } - if (link) { - link->SIPCallServerFailure (call); - } + break; + /* The call connection failed */ + case PJSIP_SC_NOT_FOUND: /* peer not found */ + case PJSIP_SC_REQUEST_TIMEOUT: /* request timeout */ + case PJSIP_SC_NOT_ACCEPTABLE_HERE: /* no compatible codecs */ + case PJSIP_SC_NOT_ACCEPTABLE_ANYWHERE: + case PJSIP_SC_UNSUPPORTED_MEDIA_TYPE: + case PJSIP_SC_UNAUTHORIZED: + case PJSIP_SC_REQUEST_PENDING: + accId = Manager::instance().getAccountFromCall (call->getCallId()); + link = dynamic_cast<SIPVoIPLink *> (Manager::instance().getAccountLink (accId)); - break; + if (link) { + link->SIPCallServerFailure (call); + } - default: - _debug ("sipvoiplink.cpp - line %d : Unhandled call state. This is probably a bug.\n", __LINE__); - break; - } + break; + default: + _debug ("sipvoiplink.cpp - line %d : Unhandled call state. This is probably a bug.\n", __LINE__); + break; } } + } +// This callback is called after SDP offer/answer session has completed. void call_on_media_update (pjsip_inv_session *inv, pj_status_t status) { _debug ("--------------------- call_on_media_update --------------------- \n"); @@ -2048,38 +2025,42 @@ void call_on_media_update (pjsip_inv_session *inv, pj_status_t status) SIPVoIPLink * link = NULL; SIPCall * call; - - if (status != PJ_SUCCESS) { - _debug ("Error while negociating the offer\n"); - return; - } - - // Get the new sdp, result of the negociation - pjmedia_sdp_neg_get_active_local (inv->neg, &local_sdp); - pjmedia_sdp_neg_get_active_remote(inv->neg, &remote_sdp); - + call = reinterpret_cast<SIPCall *> (inv->mod_data[getModId() ]); if (!call) { _debug ("Call declined by peer, SDP negociation stopped\n"); return; } - - // Clean the resulting sdp offer to create a new one (in case of a reinvite) - call->getLocalSDP()->clean_session_media(); - - // Set the fresh negociated one - call->getLocalSDP()->set_negociated_offer (local_sdp); - // Set remote ip / port - call->getLocalSDP()->set_media_transport_info_from_remote_sdp (remote_sdp); - link = dynamic_cast<SIPVoIPLink *> (Manager::instance().getAccountLink(AccountNULL)); if(link == NULL) { _debug ("Failed to get sip link\n"); return; } + if (status != PJ_SUCCESS) { + _debug ("Error while negotiating the offer\n"); + link->hangup(call->getCallId()); + Manager::instance().callFailure(call->getCallId()); + return; + } + + // Get the new sdp, result of the negotiation + pjmedia_sdp_neg_get_active_local (inv->neg, &local_sdp); + pjmedia_sdp_neg_get_active_remote (inv->neg, &remote_sdp); + + // Clean the resulting sdp offer to create a new one (in case of a reinvite) + call->getLocalSDP()->clean_session_media(); + + // Set the fresh negotiated one, no matter if that was an offer or answer. + // The local sdp is updated in case of an answer, even if the remote sdp + // is kept internally. + call->getLocalSDP()->set_negotiated_sdp (local_sdp); + + // Set remote ip / port + call->getLocalSDP()->set_media_transport_info_from_remote_sdp (remote_sdp); + try { call->setAudioStart (true); link->getAudioRtp()->start(); @@ -2107,11 +2088,8 @@ void call_on_tsx_changed (pjsip_inv_session *inv, pjsip_transaction *tsx, pjsip_ void regc_cb (struct pjsip_regc_cbparam *param) { - - //AccountID *id = static_cast<AccountID *> (param->token); SIPAccount *account; - //_debug("UserAgent: Account ID is %s, Register result: %d, Status: %d\n", id->data(), param->status, param->code); account = static_cast<SIPAccount *> (param->token); if (!account) @@ -2167,11 +2145,10 @@ void regc_cb (struct pjsip_regc_cbparam *param) } +// Optional function to be called to process incoming request message. pj_bool_t mod_on_rx_request (pjsip_rx_data *rdata) { - - pj_status_t status; pj_str_t reason; unsigned options = 0; @@ -2325,7 +2302,6 @@ mod_on_rx_request (pjsip_rx_data *rdata) get_remote_sdp_from_offer (rdata, &r_sdp); -// _debug("r_sdp = %s\n", r_sdp); status = call->getLocalSDP()->receiving_initial_offer (r_sdp); if (status!=PJ_SUCCESS) { @@ -2334,7 +2310,6 @@ mod_on_rx_request (pjsip_rx_data *rdata) return false; } - call->setConnectionState (Call::Progressing); call->setPeerNumber (peerNumber); @@ -2364,7 +2339,6 @@ mod_on_rx_request (pjsip_rx_data *rdata) return true; } - // Specify media capability during invite session creation status = pjsip_inv_create_uas (dialog, rdata, call->getLocalSDP()->get_local_sdp_session(), 0, &inv);