Newer
Older
/**
* Copyright (C) 2004-2005 Savoir-Faire Linux inc.
* Author : Laurielle Lea <laurielle.lea@savoirfairelinux.com>
*
* Portions Copyright (C) 2002,2003 Aymeric Moizard <jack@atosc.org>
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "manager.h"
#include "sipcall.h"
#include "user_cfg.h"
#define DEFAULT_SIP_PORT 5060
#define RANDOM_SIP_PORT rand() % 64000 + 1024
#define DEFAULT_LOCAL_PORT 10500
#define RANDOM_LOCAL_PORT ((rand() % 27250) + 5250)*2
#define VOICE_MSG "Voice-Message"
#define LENGTH_VOICE_MSG 15
// default _audioRTP object initialization
_evThread = new EventThread(this);
// second parameter, NULL is "::" for ipv6 and "0.0.0.0" for ipv4, we can put INADDR_ANY
i = eXosip_listen_addr(IPPROTO_UDP, INADDR_ANY, DEFAULT_SIP_PORT, AF_INET, 0);
i = eXosip_listen_addr(IPPROTO_UDP, INADDR_ANY, RANDOM_SIP_PORT, AF_INET, 0);
std::string tmp = std::string(PROGNAME_GLOBAL) + "/" + std::string(SFLPHONED_VERSION);
// If use STUN server, firewall address setup
if (Manager::instance().useStun()) {
if (behindNat() != 1) {
// This method is used to replace contact address with the public address of your NAT
eXosip_masquerade_contact((Manager::instance().getFirewallAddress()).data(), Manager::instance().getFirewallPort());
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
/**
* Subscibe to message-summary notify
* It allows eXosip to not send ' 481 Subcription Does Not Exist ' response
*/
void
SipVoIPLink::subscribeMessageSummary()
{
osip_message_t *subscribe;
const char *route= NULL;
// from/to
ManagerImpl& manager = Manager::instance();
std::string from = fromHeader(manager.getConfigString(SIGNALISATION, USER_PART), manager.getConfigString(SIGNALISATION, HOST_PART));
// to
std::string to;
to = manager.getConfigString(SIGNALISATION, PROXY);
if (!to.empty()) {
to = toHeader(manager.getConfigString(SIGNALISATION, USER_PART)) + "@" + to;
} else {
to = from;
}
// like in http://www.faqs.org/rfcs/rfc3842.html
const char *event="message-summary";
int expires = 86400;
// return 0 if no error
// the first from is the to... but we send the same
int error = eXosip_subscribe_build_initial_request(&subscribe, to.c_str(), from.c_str(), route, event, expires);
if (error == 0) {
// Accept: application/simple-message-summary
osip_message_set_header (subscribe, "Accept", "application/simple-message-summary");
_debug("Sending Message-summary subscription");
// return 0 if ok
error = eXosip_subscribe_send_initial_request (subscribe);
eXosip_unlock();
bool
SipVoIPLink::isInRtpmap (int index, int payload, CodecDescriptorVector* cdv) {
for (int i = 0; i < index; i++) {
if (cdv->at(i)->getPayload() == payload) {
return true;
}
int
SipVoIPLink::setRegister (void)
{
if (_reg_id != -1) {
manager.displayError("Registration already sent. Try to unregister");
return -1;
}
std::string proxy = "sip:" + manager.getConfigString(SIGNALISATION, PROXY);
std::string hostname = "sip:" + manager.getConfigString(SIGNALISATION, HOST_PART);
std::string from = fromHeader(manager.getConfigString(SIGNALISATION, USER_PART), manager.getConfigString(SIGNALISATION, HOST_PART));
_reg_id = eXosip_register_build_initial_register ((char*)from.data(),
(char*)proxy.data(), NULL, EXPIRES_VALUE, ®);
} else {
_reg_id = eXosip_register_build_initial_register ((char*)from.data(),
(char*)hostname.data(), NULL, EXPIRES_VALUE, ®);
}
}
if (setAuthentication() == -1) {
_debug("No authentication\n");
return -1;
}
osip_message_set_header (reg, "Event", "Registration");
osip_message_set_header (reg, "Allow-Events", "presence");
/**
* setUnregister
* unregister if we already send the first registration
* @return -1 if there is an error
*/
if (_reg_id > 0) {
i = eXosip_register_build_register (_reg_id, 0, ®);
}
// TODO: should be inside account settings
ManagerImpl& manager = Manager::instance();
std::string hostFrom = host;
if ( hostFrom.empty() ) {
hostFrom = getLocalIpAddress();
from = fromHeader(manager.getConfigString(SIGNALISATION, USER_PART), hostFrom);
if(!host.empty()) {
to = to + "@" + manager.getConfigString(SIGNALISATION, HOST_PART);
}
return -1;
}
return 0;
} else {
// If SIP proxy setting
int i;
int port;
char tmpbuf[64];
bzero (tmpbuf, 64);
// Get port
snprintf (tmpbuf, 63, "%d", getSipCall(id)->getLocalAudioPort());
_debug("%10d: Answer call [cid = %d, did = %d]\n", id, getSipCall(id)->getCid(), getSipCall(id)->getDid());
eXosip_lock ();
eXosip_call_send_answer (ca->getTid(), RINGING, NULL);
eXosip_unlock ();
// Send 200 OK
eXosip_lock();
eXosip_call_send_answer (ca->getTid(), BAD_REQ, NULL);
} else {
eXosip_call_send_answer (ca->getTid(), UNSUP_MEDIA_TYPE, NULL);
} else {
}
}
eXosip_unlock();
// Incoming call is answered, start the sound channel.
_debug("FATAL: Unable to start sound (%s:%d)\n", __FILE__, __LINE__);
id, sipcall->getCid(), sipcall->getDid());
// Release SIP stack.
eXosip_lock();
i = eXosip_call_terminate (sipcall->getCid(), sipcall->getDid());
eXosip_unlock();
if (id == Manager::instance().getCurrentCallId()) {
_audiortp.closeRtpSession();
}
// Release SIP stack.
eXosip_lock();
i = eXosip_call_terminate (sipcall->getCid(), -1);
eXosip_unlock();
SipCall *sipcall = getSipCall(id);
if ( sipcall == NULL ) { return -1; }
did = sipcall->getDid();
eXosip_lock ();
local_sdp = eXosip_get_local_sdp (did);
eXosip_unlock ();
i = eXosip_call_build_request (did, INVITE_METHOD, &invite);
eXosip_unlock ();
if (i != 0) {
sdp_message_free(local_sdp);
return -1;
}
sdp_message_free (local_sdp);
osip_message_free (invite);
return -1;
}
i = sdp_message_to_str (local_sdp, &tmp);
sdp_message_free (local_sdp);
if (i != 0) {
}
osip_message_set_body (invite, tmp, strlen (tmp));
osip_free (tmp);
osip_message_set_content_type (invite, "application/sdp");
}
osip_message_t *invite;
int i;
int did;
sdp_message_t *local_sdp = NULL;
did = getSipCall(id)->getDid();
eXosip_lock ();
local_sdp = eXosip_get_local_sdp (did);
eXosip_unlock ();
if (local_sdp == NULL) {
return -1;
}
i = eXosip_call_build_request (did, INVITE_METHOD, &invite);
eXosip_unlock ();
if (i != 0) {
sdp_message_free(local_sdp);
return -1;
}
/* add sdp body */
{
char *tmp = NULL;
i = sdp_off_hold_call (local_sdp);
if (i != 0) {
sdp_message_free (local_sdp);
osip_message_free (invite);
return -1;
}
i = sdp_message_to_str (local_sdp, &tmp);
sdp_message_free (local_sdp);
if (i != 0) {
}
osip_message_set_body (invite, tmp, strlen (tmp));
osip_free (tmp);
osip_message_set_content_type (invite, "application/sdp");
}
if (_audiortp.createNewSession (getSipCall(id)) < 0) {
_debug("FATAL: Unable to start sound (%s:%d)\n", __FILE__, __LINE__);
i = -1;
}
tmp_to = tmp_to + "@" + Manager::instance().getConfigString(SIGNALISATION,
HOST_PART);
eXosip_lock();
// Build transfer request
i = eXosip_call_build_refer (getSipCall(id)->getDid(), (char*)tmp_to.data(),
&refer);
if (i == 0) {
// Send transfer request
i = eXosip_call_send_request (getSipCall(id)->getDid(), refer);
}
eXosip_unlock();
return i;
int i;
char tmpbuf[64];
bzero (tmpbuf, 64);
// Get local port
snprintf (tmpbuf, 63, "%d", getSipCall(id)->getLocalAudioPort());
i = eXosip_call_build_answer (getSipCall(id)->getTid(), SIP_DECLINE, &answerMessage);
i = eXosip_call_send_answer (getSipCall(id)->getTid(), SIP_DECLINE, answerMessage);
// wait for 0 s, 50 ms
eXosip_event_t* event = eXosip_event_wait (0, 50);
eXosip_lock();
eXosip_automatic_action();
eXosip_unlock();
if (event == NULL) {
return -1;
_debug("Receive SipEvent #%d %s\n", event->type, event->textinfo);
switch (event->type) {
// IP-Phone user receives a new call
case EXOSIP_CALL_INVITE: //
// Set local random port for incoming call
if (!Manager::instance().useStun()) {
setLocalPort(RANDOM_LOCAL_PORT);
} else {
// If there is a firewall
if (behindNat() != 0) {
sipcall->setLocalAudioPort(_localPort);
sipcall->setLocalIp(getLocalIpAddress());
_debug(" Local listening port: %d\n", _localPort);
_debug(" Local listening IP: %s\n", getLocalIpAddress().c_str());
if (sipcall->newIncomingCall(event) == 0 ) {
if (Manager::instance().incomingCall(id, sipcall->getName(), sipcall->getNumber()) == -1) {
deleteSipCall(id);
}
} else {
Manager::instance().peerHungupCall(id);
deleteSipCall(id);
//eXosip_call_send_answer(event->tid, 403, NULL);
//488 as http://www.atosc.org/pipermail/public/osip/2005-June/005385.html
_debug("%10d: Receive Reinvite [cid = %d, did = %d], localport=%d\n", id, event->cid, event->did,sipcall->getLocalAudioPort());
sipcall->newReinviteCall(event);
// we should receive an ack after that...
case EXOSIP_CALL_RINGING: // 9 peer call is ringing
id = findCallIdInitial(event);
_debug("%10d: Receive Call Ringing [cid = %d, did = %d]\n", id, event->cid, event->did);
if (id != 0) {
getSipCall(id)->ringingCall(event);
Manager::instance().peerRingingCall(id);
} else {
returnValue = -1;
}
break;
// The peer-user answers
id = findCallIdInitial(event);
if ( id != 0) {
sipcall = getSipCall(id);
_debug("%10d: Receive Call Answer [cid = %d, did = %d], localport=%d\n", id, event->cid, event->did, sipcall->getLocalAudioPort());
// Answer
if (Manager::instance().callCanBeAnswered(id)) {
sipcall->setStandBy(false);
if (sipcall->answeredCall(event) != -1) {
sipcall->answeredCall_without_hold(event);
Manager::instance().peerAnsweredCall(id);
if(!Manager::instance().callIsOnHold(id) && Manager::instance().getCurrentCallId()==id) {
_debug("%10d: Receive ACK [cid = %d, did = %d]\n", id, event->cid, event->did);
if (id != 0 ) {
sipcall = getSipCall(id);
if(sipcall != 0 ) {
sipcall->receivedAck(event);
if (sipcall->isReinvite()) {
sipcall->endReinvite();
if(!Manager::instance().callIsOnHold(id) && Manager::instance().getCurrentCallId()==id) {
} else {
_debug(" Didn't start RTP because it's on hold or it's not the current call id\n");
_debug("%10d: Receive BYE [cid = %d, did = %d]\n", id, event->cid, event->did);
}
Manager::instance().peerHungupCall(id);
deleteSipCall(id);
} else {
if (event) {
_debug("SIP call released: [cid = %d, did = %d]\n", event->cid, event->did);
id = findCallId(event);
if (id!=0) {
// not supposed to be execute on a current call...
Manager::instance().callFailure(id);
deleteSipCall(id);
}
case EXOSIP_CALL_REQUESTFAILURE:
id = findCallId(event);
// Handle 4XX errors
switch (event->response->status_code) {
case AUTH_REQUIRED:
eXosip_lock();
eXosip_automatic_action();
eXosip_unlock();
break;
case UNAUTHORIZED:
_debug("Request is unauthorized. SIP Server ask authentification: logging...\n");
setAuthentication();
break;
case BAD_REQ:
case FORBIDDEN:
case NOT_FOUND:
case NOT_ALLOWED:
case NOT_ACCEPTABLE:
case REQ_TIMEOUT:
case TEMP_UNAVAILABLE:
case ADDR_INCOMPLETE:
//Manager::instance().displayError(event->response->reason_phrase);
Manager::instance().displayErrorText(id, event->response->reason_phrase);
break;
case BUSY_HERE:
Manager::instance().displayErrorText(id, event->response->reason_phrase);
break;
case REQ_TERMINATED:
break;
default:
break;
}
break;
case EXOSIP_CALL_SERVERFAILURE:
// Handle 5XX errors
switch (event->response->status_code) {
case SERVICE_UNAVAILABLE:
break;
default:
break;
}
break;
case EXOSIP_CALL_GLOBALFAILURE:
// Handle 6XX errors
switch (event->response->status_code) {
case BUSY_EVERYWHERE:
case DECLINE:
if (0 == event->request) break;
if (MSG_IS_INFO(event->request)) {
_debug("Receive a call message request info\n");
osip_content_type_t* c_t = event->request->content_type;
if (c_t != 0 && c_t->type != 0 && c_t->subtype != 0 ) {
_debug(" Content Type of the message: %s/%s\n", c_t->type, c_t->subtype);
// application/dtmf-relay
if (strcmp(c_t->type, "application") == 0 && strcmp(c_t->subtype, "dtmf-relay") == 0) {
handleDtmfRelay(event);
}
}
}
osip_message_t *answerOKNewMessage;
eXosip_lock();
if ( 0 == eXosip_call_build_answer(event->tid, OK, &answerOKNewMessage)) {
_debug("< Sending 200 OK\n");
eXosip_call_send_answer(event->tid, OK, answerOKNewMessage);
} else {
_debug("Could not sent an OK message\n");
}
eXosip_unlock();
break;
/* answer 486 ok */
eXosip_options_send_answer (event->tid, BUSY_HERE, NULL);
// Get the message body
ii = osip_message_get_body(event->request, 0, &body);
if (ii != 0) {
if (!body || !body->body) {
returnValue = -1;
break;
}
std::string str(body->body);
pos = str.find(VOICE_MSG);
// Set the number of voice-message
setMsgVoicemail(atoi(nb_msg.data()));
if (getMsgVoicemail() != 0) {
// http://www.jdrosen.net/papers/draft-ietf-simple-im-session-00.txt
} else if (MSG_IS_MESSAGE(event->request)) {
_debug("> MESSAGE received\n");
// osip_content_type_t* osip_message::content_type
osip_content_type_t* c_t = event->request->content_type;
if (c_t != 0 && c_t->type != 0 && c_t->subtype != 0 ) {