Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
jami-daemon
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Iterations
Wiki
Requirements
Code
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Locked files
Deploy
Releases
Model registry
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
Repository analytics
Issue analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
savoirfairelinux
jami-daemon
Commits
41643411
Commit
41643411
authored
16 years ago
by
Yun Liu
Browse files
Options
Downloads
Patches
Plain Diff
sip manager implementation including all the callbacks
parent
41e73d7b
No related branches found
No related tags found
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
src/sipmanager.cpp
+1175
-0
1175 additions, 0 deletions
src/sipmanager.cpp
src/sipmanager.h
+152
-0
152 additions, 0 deletions
src/sipmanager.h
with
1327 additions
and
0 deletions
src/sipmanager.cpp
0 → 100755
+
1175
−
0
View file @
41643411
/*
* Copyright (C) 2004-2005 Savoir-Faire Linux inc.
* Author: Yun Liu <yun.liu@savoirfairelinux.com>
*
* 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, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include
"manager.h"
#include
"sipcall.h"
#include
"sipmanager.h"
#include
"sipvoiplink.h"
#define DEFAULT_SIP_PORT 5068
#define RANDOM_SIP_PORT rand() % 64000 + 1024
#define RANDOM_LOCAL_PORT ((rand() % 27250) + 5250)*2
SIPManager
*
SIPManager
::
_current
;
pjsip_inv_session
*
SIPManager
::
_invSession
;
SIPManager
::
SIPManager
()
{
_useStun
=
false
;
_localIPAddress
=
"127.0.0.1"
;
SIPManager
::
_current
=
this
;
}
SIPManager
::~
SIPManager
()
{
_debug
(
"Somebody call me!
\n
"
);
}
pj_status_t
SIPManager
::
sipCreate
()
{
pj_status_t
status
;
//_debug("stun host is %s\n", _stunHost.ptr);
/* Init pjsua data */
//init_data();
/* Set default logging settings */
//pjsua_logging_config_default(&pjsua_var.log_cfg);
/* Init PJLIB: */
status
=
pj_init
();
if
(
status
!=
PJ_SUCCESS
)
{
_debug
(
"! SIP Failure: Could not initialize PJSip
\n
"
);
return
status
;
}
/* Init random seed */
//init_random_seed();
/* Init PJLIB-UTIL: */
status
=
pjlib_util_init
();
if
(
status
!=
PJ_SUCCESS
)
{
_debug
(
"! SIP Failure: Could not initialize PJ Util
\n
"
);
return
status
;
}
/* Init PJNATH */
status
=
pjnath_init
();
if
(
status
!=
PJ_SUCCESS
)
{
_debug
(
"! SIP Failure: Could not initialize PJ Nath
\n
"
);
return
status
;
}
/* Set default sound device ID */
//pjsua_var.cap_dev = pjsua_var.play_dev = -1;
/* Init caching pool. */
pj_caching_pool_init
(
&
_cp
,
NULL
,
0
);
/* Create memory pool for application. */
_pool
=
pj_pool_create
(
&
_cp
.
factory
,
"sflphone"
,
4000
,
4000
,
NULL
);
if
(
!
_pool
)
{
_debug
(
"! SIP Failure: Could not initialize memory pool
\n
"
);
return
PJ_ENOMEM
;
}
/* Create mutex */
status
=
pj_mutex_create_recursive
(
_pool
,
"sflphone"
,
&
_mutex
);
if
(
status
!=
PJ_SUCCESS
)
{
_debug
(
"! SIP Failure: Unable to create mutex
\n
"
);
return
status
;
}
/* Must create SIP endpoint to initialize SIP parser. The parser
* is needed for example when application needs to call pjsua_verify_url().
*/
status
=
pjsip_endpt_create
(
&
_cp
.
factory
,
pj_gethostname
()
->
ptr
,
&
_endpt
);
if
(
status
!=
PJ_SUCCESS
)
{
_debug
(
"! SIP Failure: Unable to create mutex
\n
"
);
return
status
;
}
return
PJ_SUCCESS
;
}
pj_status_t
SIPManager
::
sipInit
()
{
pj_status_t
status
;
const
pj_str_t
STR_OPTIONS
=
{
"OPTIONS"
,
7
};
/* Init SIP UA: */
//FIXME! DNS initialize here! */
/* Start resolving STUN server */
// if we useStun and we failed to receive something on port 5060, we try a random port
// If use STUN server, firewall address setup
if
(
!
loadSIPLocalIP
())
{
_debug
(
"! SIP FAILURE: Unable to determine network capabilities
\n
"
);
return
false
;
}
int
errPjsip
=
0
;
int
port
=
DEFAULT_SIP_PORT
;
//_debug("stun host is %s\n", _stunHost.ptr);
if
(
_useStun
&&
!
Manager
::
instance
().
behindNat
(
_stunServer
,
port
))
{
port
=
RANDOM_SIP_PORT
;
if
(
!
Manager
::
instance
().
behindNat
(
_stunServer
,
port
))
{
_debug
(
"! SIP Failure: Unable to check NAT setting
\n
"
);
return
false
;
// hoho we can't use the random sip port too...
}
}
_localPort
=
port
;
if
(
_useStun
)
{
// set by last behindNat() call (ish)...
stunServerResolve
();
_localExternAddress
=
Manager
::
instance
().
getFirewallAddress
();
_localExternPort
=
Manager
::
instance
().
getFirewallPort
();
}
else
{
_localExternAddress
=
_localIPAddress
;
_localExternPort
=
_localPort
;
}
errPjsip
=
createUDPServer
();
if
(
errPjsip
!=
0
)
{
_debug
(
"* SIP Info: could not initialize SIP listener on port %d
\n
"
,
port
);
port
=
RANDOM_SIP_PORT
;
_debug
(
"! SIP Failure: SIP failed to listen on port %d
\n
"
,
port
);
return
errPjsip
;
}
_debug
(
" SIP Init: listening on port %d
\n
"
,
_localExternPort
);
/* Initialize transaction layer: */
status
=
pjsip_tsx_layer_init_module
(
_endpt
);
if
(
status
!=
PJ_SUCCESS
)
{
_debug
(
"! SIP Failure: Unable to initialize transaction layer.
\n
"
);
return
status
;
}
/* Initialize UA layer module: */
status
=
pjsip_ua_init_module
(
_endpt
,
NULL
);
if
(
status
!=
PJ_SUCCESS
)
{
_debug
(
"! SIP Failure: Unable to initialize UA layer module.
\n
"
);
return
status
;
}
/* Initialize Replaces support. */
status
=
pjsip_replaces_init_module
(
_endpt
);
if
(
status
!=
PJ_SUCCESS
)
{
_debug
(
"! SIP Failure: Unable to initialize Replaces support.
\n
"
);
return
status
;
}
/* Initialize 100rel support */
status
=
pjsip_100rel_init_module
(
_endpt
);
if
(
status
!=
PJ_SUCCESS
)
{
_debug
(
"! SIP Failure: Unable to initialize 100rel support.
\n
"
);
return
status
;
}
/* Initialize and register sflphone module. */
{
const
pjsip_module
mod_initializer
=
{
NULL
,
NULL
,
/* prev, next. */
{
"mod-sflphone"
,
9
},
/* Name. */
-
1
,
/* Id */
PJSIP_MOD_PRIORITY_APPLICATION
,
/* Priority */
NULL
,
/* load() */
NULL
,
/* start() */
NULL
,
/* stop() */
NULL
,
/* unload() */
&
mod_on_rx_request
,
/* on_rx_request() */
&
mod_on_rx_response
,
/* on_rx_response() */
NULL
,
/* on_tx_request. */
NULL
,
/* on_tx_response() */
NULL
,
/* on_tsx_state() */
};
_mod
=
mod_initializer
;
status
=
pjsip_endpt_register_module
(
_endpt
,
&
_mod
);
if
(
status
!=
PJ_SUCCESS
)
{
_debug
(
"! SIP Failure: Unable to register sflphone module.
\n
"
);
return
status
;
}
}
/* Initialize PJSUA call subsystem: */
/*status = pjsua_call_subsys_init(ua_cfg);
if (status != PJ_SUCCESS) {
_debug("! SIP Failure: Unable to initialize ")
goto on_error;
}*/
/* Initialize PJSUA media subsystem */
/*status = pjsua_media_subsys_init(media_cfg);
if (status != PJ_SUCCESS) {
_debug("! SIP Failure: Unable to initialize ")
goto on_error;
}*/
/* Init core SIMPLE module : */
status
=
pjsip_evsub_init_module
(
_endpt
);
if
(
status
!=
PJ_SUCCESS
)
{
_debug
(
"! SIP Failure: Unable to initialize core SIMPLE module.
\n
"
);
return
status
;
}
/* Init presence module: */
status
=
pjsip_pres_init_module
(
_endpt
,
pjsip_evsub_instance
());
if
(
status
!=
PJ_SUCCESS
)
{
_debug
(
"! SIP Failure: Unable to initialize presence module.
\n
"
);
return
status
;
}
/* Init PUBLISH module */
pjsip_publishc_init_module
(
_endpt
);
/* Init xfer/REFER module */
status
=
pjsip_xfer_init_module
(
_endpt
);
if
(
status
!=
PJ_SUCCESS
)
{
_debug
(
"! SIP Failure: Unable to initialize xfer/PEFER module.
\n
"
);
return
status
;
}
/* Init pjsua presence handler: */
/*status = pjsua_pres_init();
if (status != PJ_SUCCESS) {
_debug("! SIP Failure: Unable to initialize ")
goto on_error;
}*/
/* Init out-of-dialog MESSAGE request handler. */
/*status = pjsua_im_init();
if (status != PJ_SUCCESS) {
_debug("! SIP Failure: Unable to initialize ")
goto on_error;
}*/
{
const
pjsip_module
handler
=
{
NULL
,
NULL
,
/* prev, next. */
{
"mod-pjsua-options"
,
17
},
/* Name. */
-
1
,
/* Id */
PJSIP_MOD_PRIORITY_APPLICATION
,
/* Priority */
NULL
,
/* load() */
NULL
,
/* start() */
NULL
,
/* stop() */
NULL
,
/* unload() */
&
options_on_rx_request
,
/* on_rx_request() */
NULL
,
/* on_rx_response() */
NULL
,
/* on_tx_request. */
NULL
,
/* on_tx_response() */
NULL
,
/* on_tsx_state() */
};
_options_handler
=
handler
;
}
/* Register OPTIONS handler */
pjsip_endpt_register_module
(
_endpt
,
&
_options_handler
);
/* Add OPTIONS in Allow header */
pjsip_endpt_add_capability
(
_endpt
,
NULL
,
PJSIP_H_ALLOW
,
NULL
,
1
,
&
STR_OPTIONS
);
// Initialize invite session module
// These callbacks will be called on incoming requests, media session state, etc.
{
pjsip_inv_callback
inv_cb
;
// Init the callback for INVITE session:
pj_bzero
(
&
inv_cb
,
sizeof
(
inv_cb
));
inv_cb
.
on_state_changed
=
&
call_on_state_changed
;
inv_cb
.
on_new_session
=
&
call_on_forked
;
inv_cb
.
on_media_update
=
&
call_on_media_update
;
inv_cb
.
on_tsx_state_changed
=
&
call_on_tsx_changed
;
_debug
(
"AAAA VOIP callbacks initialized
\n
"
);
// Initialize session invite module
status
=
pjsip_inv_usage_init
(
_endpt
,
&
inv_cb
);
PJ_ASSERT_RETURN
(
status
==
PJ_SUCCESS
,
1
);
}
// Add endpoint capabilities (INFO, OPTIONS, etc) for this UA
{
pj_str_t
allowed
[]
=
{
{
"INFO"
,
4
},
{
"REGISTER"
,
8
}
};
// //{"INVITE", 6}, {"ACK",3}, {"BYE",3}, {"CANCEL",6}, {"OPTIONS", 7},
pj_str_t
accepted
=
{
"application/sdp"
,
15
};
// Register supported methods
pjsip_endpt_add_capability
(
_endpt
,
&
_mod
,
PJSIP_H_ALLOW
,
NULL
,
PJ_ARRAY_SIZE
(
allowed
),
allowed
);
// Register "application/sdp" in ACCEPT header
pjsip_endpt_add_capability
(
_endpt
,
&
_mod
,
PJSIP_H_ACCEPT
,
NULL
,
1
,
&
accepted
);
}
_debug
(
"sflphone version %s for %s initialized
\n
"
,
pj_get_version
(),
PJ_OS_NAME
);
status
=
pj_thread_create
(
_pool
,
"sflphone"
,
&
worker_thread
,
NULL
,
0
,
0
,
&
_thread
);
/* Done! */
return
PJ_SUCCESS
;
on_error
:
//sipDestroy();
return
status
;
}
bool
SIPManager
::
addAccount
(
AccountID
id
,
pjsip_regc
*
regc2
,
const
std
::
string
&
server
,
const
std
::
string
&
user
,
const
std
::
string
&
passwd
,
const
int
&
timeout
)
{
pj_status_t
status
;
AccountID
*
currentId
=
new
AccountID
(
id
);
//pjsip_cred_info cred;
char
contactTmp
[
256
];
pjsip_regc
*
regc
;
pj_mutex_lock
(
_mutex
);
std
::
string
tmp
;
status
=
pjsip_regc_create
(
_endpt
,
(
void
*
)
currentId
,
&
regc_cb
,
&
regc
);
if
(
status
!=
PJ_SUCCESS
)
{
_debug
(
"! SIP Failure: Unable to create regc.
\n
"
);
return
status
;
}
tmp
=
"sip:"
+
server
;
pj_str_t
svr
=
pj_str
((
char
*
)
tmp
.
data
());
tmp
=
"<sip:"
+
user
+
"@"
+
server
+
">"
;
pj_str_t
aor
=
pj_str
((
char
*
)
tmp
.
data
());
sprintf
(
contactTmp
,
"<sip:%s@%s:%d>"
,
user
.
data
(),
_localExternAddress
.
data
(),
_localExternPort
);
pj_str_t
contact
=
pj_str
(
contactTmp
);
_debug
(
"Get in %s %d %s
\n
"
,
svr
.
ptr
,
svr
.
slen
,
aor
.
ptr
);
_debug
(
"after here! contact is %s
\n
"
,
contact
.
ptr
);
status
=
pjsip_regc_init
(
regc
,
&
svr
,
&
aor
,
&
aor
,
1
,
&
contact
,
600
);
//timeout);
if
(
status
!=
PJ_SUCCESS
)
{
_debug
(
"! SIP Failure: Unable to initialize regc. %d
\n
"
,
status
);
//, regc->str_srv_url.ptr);
return
status
;
}
_debug
(
"after here!
\n
"
);
AccBaseInfo
*
info
=
new
AccBaseInfo
();
pj_bzero
(
&
info
->
cred
,
sizeof
(
info
->
cred
));
pj_strdup2
(
_pool
,
&
info
->
cred
.
username
,
user
.
data
());
info
->
cred
.
data_type
=
PJSIP_CRED_DATA_PLAIN_PASSWD
;
pj_strdup2
(
_pool
,
&
info
->
cred
.
data
,
passwd
.
data
());
pj_strdup2
(
_pool
,
&
info
->
cred
.
realm
,
"*"
);
pj_strdup2
(
_pool
,
&
info
->
cred
.
scheme
,
"digest"
);
pjsip_regc_set_credentials
(
regc
,
1
,
&
info
->
cred
);
_debug
(
"after here!
\n
"
);
pjsip_tx_data
*
tdata
;
status
=
pjsip_regc_register
(
regc
,
PJ_TRUE
,
&
tdata
);
if
(
status
!=
PJ_SUCCESS
)
{
_debug
(
"! SIP Failure: Unable to register regc.
\n
"
);
return
status
;
}
_debug
(
"after here!
\n
"
);
status
=
pjsip_regc_send
(
regc
,
tdata
);
if
(
status
!=
PJ_SUCCESS
)
{
_debug
(
"! SIP Failure: Unable to send regc request.
\n
"
);
return
status
;
}
_debug
(
"after here!
\n
"
);
info
->
userName
=
user
;
info
->
server
=
server
;
info
->
id
=
id
;
pj_strdup2
(
_pool
,
&
info
->
contact
,
contact
.
ptr
);
_accBaseInfoList
.
push_back
(
info
);
pj_mutex_unlock
(
_mutex
);
return
true
;
}
pj_str_t
SIPManager
::
buildContact
(
char
*
userName
)
{
pj_str_t
contact
;
char
tmp
[
256
];
//FIXME: IPV6 issue!!
_debug
(
"In build Contact %s %s %d
\n
"
,
userName
,
_localExternAddress
.
data
(),
_localExternPort
);
sprintf
(
tmp
,
"<sip:%s@%s:%d>"
,
userName
,
_localExternAddress
.
data
(),
_localExternPort
);
_debug
(
"get tmp
\n
"
);
return
pj_str
(
tmp
);
}
pj_status_t
SIPManager
::
stunServerResolve
()
{
pj_str_t
stun_adr
;
pj_hostent
he
;
pj_stun_config
stunCfg
;
pj_status_t
stun_status
;
pj_sockaddr
stun_srv
;
// Initialize STUN configuration
pj_stun_config_init
(
&
stunCfg
,
&
_cp
.
factory
,
0
,
pjsip_endpt_get_ioqueue
(
_endpt
),
pjsip_endpt_get_timer_heap
(
_endpt
));
stun_status
=
PJ_EPENDING
;
// Init STUN socket
stun_adr
=
pj_str
((
char
*
)
_stunServer
.
data
());
stun_status
=
pj_sockaddr_in_init
(
&
stun_srv
.
ipv4
,
&
stun_adr
,
(
pj_uint16_t
)
3478
);
if
(
stun_status
!=
PJ_SUCCESS
)
{
_debug
(
"***********Unresolved stud server***********!
\n
"
);
stun_status
=
pj_gethostbyname
(
&
stun_adr
,
&
he
);
if
(
stun_status
==
PJ_SUCCESS
)
{
pj_sockaddr_in_init
(
&
stun_srv
.
ipv4
,
NULL
,
0
);
stun_srv
.
ipv4
.
sin_addr
=
*
(
pj_in_addr
*
)
he
.
h_addr
;
stun_srv
.
ipv4
.
sin_port
=
pj_htons
((
pj_uint16_t
)
3478
);
}
}
return
stun_status
;
}
int
SIPManager
::
createUDPServer
()
{
pj_status_t
status
;
pj_str_t
ipAddr
;
pj_sockaddr_in
bound_addr
;
// Init bound address to ANY
pj_memset
(
&
bound_addr
,
0
,
sizeof
(
bound_addr
));
bound_addr
.
sin_addr
.
s_addr
=
PJ_INADDR_ANY
;
// Create UDP server socket
status
=
pj_sock_socket
(
PJ_AF_INET
,
PJ_SOCK_DGRAM
,
0
,
&
_sock
);
if
(
status
!=
PJ_SUCCESS
)
{
_debug
(
"(%d) UDP socket() error
\n
"
,
status
);
return
status
;
}
status
=
pj_sock_bind_in
(
_sock
,
pj_ntohl
(
bound_addr
.
sin_addr
.
s_addr
),
(
pj_uint16_t
)
_localPort
);
if
(
status
!=
PJ_SUCCESS
)
{
_debug
(
"(%d) UDP bind() error
\n
"
,
status
);
pj_sock_close
(
_sock
);
return
status
;
}
_debug
(
"Use IP: %s
\n
"
,
_localExternAddress
.
data
());
// Create UDP-Server (default port: 5060)
pjsip_host_port
a_name
;
char
tmpIP
[
32
];
strcpy
(
tmpIP
,
_localExternAddress
.
data
());
a_name
.
host
=
pj_str
(
tmpIP
);
a_name
.
port
=
(
pj_uint16_t
)
_localExternPort
;
status
=
pjsip_udp_transport_attach
(
_endpt
,
_sock
,
&
a_name
,
1
,
NULL
);
if
(
status
!=
PJ_SUCCESS
)
{
_debug
(
"(%d) Unable to start UDP transport!
\n
"
,
status
);
return
-
1
;
}
else
{
_debug
(
"UDP server listening on port %d
\n
"
,
_localExternPort
);
}
return
0
;
}
void
SIPManager
::
setStunServer
(
const
char
*
server
)
{
_stunServer
=
std
::
string
(
server
);
_useStun
=
true
;
}
void
SIPManager
::
regc_cb
(
struct
pjsip_regc_cbparam
*
param
)
{
AccountID
*
id
=
static_cast
<
AccountID
*>
(
param
->
token
);
_debug
(
"Account ID is %s, Register result: %d
\n
"
,
id
->
data
(),
param
->
status
);
if
(
param
->
status
==
PJ_SUCCESS
)
{
Manager
::
instance
().
getAccountLink
(
*
id
)
->
setRegistrationState
(
VoIPLink
::
Registered
);
}
else
{
Manager
::
instance
().
getAccountLink
(
*
id
)
->
setRegistrationState
(
VoIPLink
::
Error
);
}
}
bool
SIPManager
::
loadSIPLocalIP
()
{
bool
returnValue
=
true
;
if
(
_localIPAddress
==
"127.0.0.1"
)
{
pj_sockaddr
ip_addr
;
if
(
pj_gethostip
(
pj_AF_INET
(),
&
ip_addr
)
!=
PJ_SUCCESS
)
{
// Update the registration state if no network capabilities found
_debug
(
"Get host ip failed!
\n
"
);
//setRegistrationState( ErrorNetwork );
returnValue
=
false
;
}
else
{
_localIPAddress
=
std
::
string
(
pj_inet_ntoa
(
ip_addr
.
ipv4
.
sin_addr
));
_debug
(
" SIP Info: Checking network, setting local IP address to: %s
\n
"
,
_localIPAddress
.
data
());
}
}
return
returnValue
;
}
/* Worker thread function. */
int
SIPManager
::
worker_thread
(
void
*
arg
)
{
//enum { TIMEOUT = 10 };
PJ_UNUSED_ARG
(
arg
);
while
(
true
)
{
//int count;
pj_time_val
timeout
=
{
0
,
10
};
pjsip_endpt_handle_events
(
getInstance
()
->
getEndPoint
(),
&
timeout
);
}
return
0
;
}
pj_bool_t
SIPManager
::
mod_on_rx_request
(
pjsip_rx_data
*
rdata
)
{
pj_status_t
status
;
pj_str_t
reason
;
unsigned
options
=
0
;
pjsip_dialog
*
dialog
;
pjsip_tx_data
*
tdata
;
pjmedia_sdp_session
*
r_sdp
;
_debug
(
"Callback on_rx_request entered
\n
"
);
PJ_UNUSED_ARG
(
rdata
);
pjsip_uri
*
uri
=
rdata
->
msg_info
.
to
->
uri
;
pjsip_sip_uri
*
sip_uri
=
(
pjsip_sip_uri
*
)
pjsip_uri_get_uri
(
uri
);
std
::
string
userName
=
std
::
string
(
sip_uri
->
user
.
ptr
,
sip_uri
->
user
.
slen
);
std
::
string
server
=
std
::
string
(
sip_uri
->
host
.
ptr
,
sip_uri
->
host
.
slen
);
_debug
(
"The receiver is : %s@%s
\n
"
,
userName
.
data
(),
server
.
data
());
uri
=
rdata
->
msg_info
.
from
->
uri
;
sip_uri
=
(
pjsip_sip_uri
*
)
pjsip_uri_get_uri
(
uri
);
std
::
string
caller
=
std
::
string
(
sip_uri
->
user
.
ptr
,
sip_uri
->
user
.
slen
);
std
::
string
callerServer
=
std
::
string
(
sip_uri
->
host
.
ptr
,
sip_uri
->
host
.
slen
);
std
::
string
peerNumber
=
caller
+
"@"
+
callerServer
;
/* Respond statelessly any non-INVITE requests with 500 */
if
(
rdata
->
msg_info
.
msg
->
line
.
req
.
method
.
id
!=
PJSIP_INVITE_METHOD
)
{
if
(
rdata
->
msg_info
.
msg
->
line
.
req
.
method
.
id
!=
PJSIP_ACK_METHOD
)
{
reason
=
pj_str
((
char
*
)
" user agent unable to handle this request "
);
pjsip_endpt_respond_stateless
(
getInstance
()
->
getEndPoint
(),
rdata
,
MSG_METHOD_NOT_ALLOWED
,
&
reason
,
NULL
,
NULL
);
return
PJ_TRUE
;
}
}
// Verify that we can handle the request
status
=
pjsip_inv_verify_request
(
rdata
,
&
options
,
NULL
,
NULL
,
getInstance
()
->
getEndPoint
(),
NULL
);
if
(
status
!=
PJ_SUCCESS
)
{
reason
=
pj_str
((
char
*
)
" user agent unable to handle this INVITE "
);
pjsip_endpt_respond_stateless
(
getInstance
()
->
getEndPoint
(),
rdata
,
MSG_METHOD_NOT_ALLOWED
,
&
reason
,
NULL
,
NULL
);
return
PJ_TRUE
;
}
CallID
id
=
Manager
::
instance
().
getNewCallID
();
_debug
(
"####################
\n
##############call id is %s
\n
"
,
id
.
c_str
());
SIPCall
*
call
=
new
SIPCall
(
id
,
Call
::
Incoming
);
if
(
!
call
)
{
_debug
(
"! SIP Failure: unable to create an incoming call"
);
return
PJ_FALSE
;
}
getInstance
()
->
setCallAudioLocal
(
call
);
call
->
setCodecMap
(
Manager
::
instance
().
getCodecDescriptorMap
());
call
->
setConnectionState
(
Call
::
Progressing
);
call
->
setIp
(
getInstance
()
->
getLocalIP
());
call
->
setPeerNumber
(
peerNumber
);
if
(
call
->
SIPCallInvite
(
rdata
,
getInstance
()
->
getAppPool
()))
{
AccountID
id
=
getInstance
()
->
getAccountIdFromNameAndServer
(
userName
,
server
);
_debug
(
"####################
\n
##############account id is %s
\n
"
,
id
.
c_str
());
if
(
Manager
::
instance
().
incomingCall
(
call
,
id
))
{
Manager
::
instance
().
getAccountLink
(
id
)
->
addCall
(
call
);
//addCall(call);
_debug
(
"OK
\n
"
);
}
else
{
delete
call
;
call
=
0
;
}
}
else
{
delete
call
;
call
=
0
;
}
_debug
(
"Here!!!!!
\n
"
);
/* Create the local dialog (UAS) */
status
=
pjsip_dlg_create_uas
(
pjsip_ua_instance
(),
rdata
,
NULL
,
&
dialog
);
if
(
status
!=
PJ_SUCCESS
)
{
pjsip_endpt_respond_stateless
(
getInstance
()
->
getEndPoint
(),
rdata
,
MSG_SERVER_INTERNAL_ERROR
,
&
reason
,
NULL
,
NULL
);
return
PJ_TRUE
;
}
// Specify media capability during invite session creation
status
=
pjsip_inv_create_uas
(
dialog
,
rdata
,
call
->
getLocalSDPSession
(),
0
,
&
_invSession
);
PJ_ASSERT_RETURN
(
status
==
PJ_SUCCESS
,
1
);
_invSession
->
mod_data
[
getInstance
()
->
getModId
()]
=
call
;
// Send a 180/Ringing response
status
=
pjsip_inv_initial_answer
(
_invSession
,
rdata
,
PJSIP_SC_RINGING
,
NULL
,
NULL
,
&
tdata
);
PJ_ASSERT_RETURN
(
status
==
PJ_SUCCESS
,
1
);
status
=
pjsip_inv_send_msg
(
_invSession
,
tdata
);
PJ_ASSERT_RETURN
(
status
==
PJ_SUCCESS
,
1
);
// Update the connection state
if
(
call
)
{
call
->
setConnectionState
(
Call
::
Ringing
);
}
/* Done */
return
PJ_SUCCESS
;
}
AccountID
SIPManager
::
getAccountIdFromNameAndServer
(
const
std
::
string
&
userName
,
const
std
::
string
&
server
)
{
int
size
=
_accBaseInfoList
.
size
();
for
(
int
i
=
0
;
i
<
size
;
i
++
)
{
if
(
_accBaseInfoList
[
i
]
->
userName
==
userName
&&
_accBaseInfoList
[
i
]
->
server
==
server
)
{
_debug
(
"Full match
\n
"
);
return
_accBaseInfoList
[
i
]
->
id
;
}
}
for
(
int
i
=
0
;
i
<
size
;
i
++
)
{
if
(
_accBaseInfoList
[
i
]
->
userName
==
userName
)
{
_debug
(
"Username match
\n
"
);
return
_accBaseInfoList
[
i
]
->
id
;
}
}
return
AccountNULL
;
}
SIPManager
::
AccBaseInfo
*
SIPManager
::
getAccountInfoFromId
(
AccountID
id
)
{
int
size
=
_accBaseInfoList
.
size
();
for
(
int
i
=
0
;
i
<
size
;
i
++
)
{
if
(
_accBaseInfoList
[
i
]
->
id
==
id
)
{
return
_accBaseInfoList
[
i
];
}
}
return
NULL
;
}
bool
SIPManager
::
setCallAudioLocal
(
SIPCall
*
call
)
{
// Setting Audio
unsigned
int
callLocalAudioPort
=
RANDOM_LOCAL_PORT
;
unsigned
int
callLocalExternAudioPort
=
callLocalAudioPort
;
if
(
_useStun
)
{
// If use Stun server
if
(
Manager
::
instance
().
behindNat
(
_stunServer
,
callLocalAudioPort
))
{
callLocalExternAudioPort
=
Manager
::
instance
().
getFirewallPort
();
}
}
_debug
(
" Setting local audio port to: %d
\n
"
,
callLocalAudioPort
);
_debug
(
" Setting local audio port (external) to: %d
\n
"
,
callLocalExternAudioPort
);
// Set local audio port for SIPCall(id)
call
->
setLocalIp
(
_localIPAddress
);
call
->
setLocalAudioPort
(
callLocalAudioPort
);
call
->
setLocalExternAudioPort
(
callLocalExternAudioPort
);
return
true
;
}
int
SIPManager
::
answer
(
SIPCall
*
call
)
{
pj_status_t
status
;
pjsip_tx_data
*
tdata
;
if
(
call
->
startNegociation
(
_pool
))
{
// Create and send a 200(OK) response
_debug
(
"Negociation success!
\n
"
);
status
=
pjsip_inv_answer
(
_invSession
,
PJSIP_SC_OK
,
NULL
,
NULL
,
&
tdata
);
PJ_ASSERT_RETURN
(
status
==
PJ_SUCCESS
,
1
);
status
=
pjsip_inv_send_msg
(
_invSession
,
tdata
);
PJ_ASSERT_RETURN
(
status
==
PJ_SUCCESS
,
1
);
return
0
;
}
return
1
;
}
bool
SIPManager
::
makeOutgoingCall
(
const
std
::
string
&
strTo
,
SIPCall
*
call
,
const
AccountID
&
id
)
{
pj_status_t
status
;
pjsip_dialog
*
dialog
;
pjsip_tx_data
*
tdata
;
pj_str_t
from
,
to
;
AccBaseInfo
*
accBase
=
getAccountInfoFromId
(
id
);
std
::
string
strFrom
=
"sip:"
+
accBase
->
userName
+
"@"
+
accBase
->
server
;
_debug
(
"Make a new call from:%s to %s. Contact is %s
\n
"
,
strFrom
.
data
(),
strTo
.
data
(),
accBase
->
contact
.
ptr
);
from
=
pj_str
((
char
*
)
strFrom
.
data
());
to
=
pj_str
((
char
*
)
strTo
.
data
());
status
=
pjsip_dlg_create_uac
(
pjsip_ua_instance
(),
&
from
,
&
accBase
->
contact
,
//NULL,
&
to
,
NULL
,
&
dialog
);
PJ_ASSERT_RETURN
(
status
==
PJ_SUCCESS
,
1
);
setCallAudioLocal
(
call
);
call
->
setIp
(
getInstance
()
->
getLocalIP
());
// Building the local SDP offer
call
->
createInitialOffer
(
_pool
);
status
=
pjsip_inv_create_uac
(
dialog
,
call
->
getLocalSDPSession
(),
0
,
&
_invSession
);
PJ_ASSERT_RETURN
(
status
==
PJ_SUCCESS
,
1
);
pjsip_auth_clt_set_credentials
(
&
dialog
->
auth_sess
,
1
,
&
accBase
->
cred
);
_invSession
->
mod_data
[
_mod
.
id
]
=
call
;
status
=
pjsip_inv_invite
(
_invSession
,
&
tdata
);
PJ_ASSERT_RETURN
(
status
==
PJ_SUCCESS
,
1
);
status
=
pjsip_inv_send_msg
(
_invSession
,
tdata
);
PJ_ASSERT_RETURN
(
status
==
PJ_SUCCESS
,
1
);
return
true
;
}
void
SIPManager
::
call_on_forked
(
pjsip_inv_session
*
inv
,
pjsip_event
*
e
)
{
//_debug("HERE!\n");
}
void
SIPManager
::
call_on_tsx_changed
(
pjsip_inv_session
*
inv
,
pjsip_transaction
*
tsx
,
pjsip_event
*
e
)
{
PJ_UNUSED_ARG
(
inv
);
_debug
(
"@@@@@@@@@@@@@@@ Here we are, the tsx->state is %d; tsx->role is %d; code is %d; method id is %s.
\n
"
,
tsx
->
state
,
tsx
->
role
,
tsx
->
status_code
,
tsx
->
method
.
name
.
ptr
);
if
(
tsx
->
state
==
PJSIP_TSX_STATE_TERMINATED
&&
tsx
->
role
==
PJSIP_ROLE_UAC
)
{
int
code
;
pjsip_rx_data
*
rdata
;
AccountID
accId
;
//Retrieve the body message
rdata
=
e
->
body
.
tsx_state
.
src
.
rdata
;
code
=
tsx
->
status_code
;
if
(
code
==
200
)
{
_debug
(
"Use this to handle the incoming call!!!
\n
"
);
SIPCall
*
call
=
reinterpret_cast
<
SIPCall
*>
(
inv
->
mod_data
[
getInstance
()
->
getModId
()]);
if
(
call
==
NULL
)
return
;
_debug
(
"The call id is %s
\n
"
,
call
->
getCallId
().
data
());
//pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
accId
=
Manager
::
instance
().
getAccountFromCall
(
call
->
getCallId
());
SIPVoIPLink
*
link
=
dynamic_cast
<
SIPVoIPLink
*>
(
Manager
::
instance
().
getAccountLink
(
accId
));
link
->
SIPCallAnswered
(
call
,
rdata
);
}
}
else
if
(
tsx
->
state
==
PJSIP_TSX_STATE_TRYING
&&
tsx
->
role
==
PJSIP_ROLE_UAS
)
{
/*_debug("HERE!!!!!!!!!!!!!!!!!!!\n");
// Incoming message request
pjsip_rx_data *rdata;
pjsip_msg *msg;
pj_status_t status;
std::string text;
// Retrieve the body message
rdata = e->body.tsx_state.src.rdata;
msg = rdata->msg_info.msg;
// Respond with OK message
status = pjsip_dlg_respond(inv->dlg, rdata, PJSIP_SC_OK, NULL, NULL, NULL);*/
}
else
if
(
tsx
->
state
==
PJSIP_TSX_STATE_PROCEEDING
&&
tsx
->
role
==
PJSIP_ROLE_UAC
)
{
int
code
;
pjsip_rx_data
*
rdata
;
pjsip_msg
*
msg
;
AccountID
accId
;
// Retrieve the body message
rdata
=
e
->
body
.
tsx_state
.
src
.
rdata
;
msg
=
rdata
->
msg_info
.
msg
;
SIPCall
*
call
=
reinterpret_cast
<
SIPCall
*>
(
inv
->
mod_data
[
getInstance
()
->
getModId
()]);
if
(
call
==
NULL
)
return
;
code
=
msg
->
line
.
status
.
code
;
switch
(
code
)
{
case
180
:
_debug
(
"HERE!!!!!!!!!!!!!!!!!!!
\n
"
);
call
->
setConnectionState
(
Call
::
Ringing
);
Manager
::
instance
().
peerRingingCall
(
call
->
getCallId
());
break
;
default:
break
;
}
}
else
if
(
tsx
->
state
==
PJSIP_TSX_STATE_COMPLETED
&&
tsx
->
role
==
PJSIP_ROLE_UAS
)
{
if
(
tsx
->
status_code
==
200
&&
tsx
->
method
.
id
==
PJSIP_BYE_METHOD
)
{
_debug
(
"Receive target phone hang up (bye) message
\n
"
);
SIPCall
*
call
=
reinterpret_cast
<
SIPCall
*>
(
inv
->
mod_data
[
getInstance
()
->
getModId
()]);
if
(
call
==
NULL
)
{
_debug
(
"Call has been removed!
\n
"
);
return
;
}
AccountID
accId
=
Manager
::
instance
().
getAccountFromCall
(
call
->
getCallId
());
SIPVoIPLink
*
link
=
dynamic_cast
<
SIPVoIPLink
*>
(
Manager
::
instance
().
getAccountLink
(
accId
));
if
(
link
)
{
link
->
SIPCallClosed
(
call
);
inv
->
mod_data
[
getInstance
()
->
getModId
()]
=
NULL
;
}
}
else
if
(
tsx
->
status_code
==
200
&&
tsx
->
method
.
id
==
PJSIP_CANCEL_METHOD
)
{
_debug
(
"Receive cancel message
\n
"
);
SIPCall
*
call
=
reinterpret_cast
<
SIPCall
*>
(
inv
->
mod_data
[
getInstance
()
->
getModId
()]);
if
(
call
==
NULL
)
{
_debug
(
"Call has been removed!
\n
"
);
return
;
}
AccountID
accId
=
Manager
::
instance
().
getAccountFromCall
(
call
->
getCallId
());
SIPVoIPLink
*
link
=
dynamic_cast
<
SIPVoIPLink
*>
(
Manager
::
instance
().
getAccountLink
(
accId
));
if
(
link
)
{
link
->
SIPCallReleased
(
call
);
inv
->
mod_data
[
getInstance
()
->
getModId
()]
=
NULL
;
}
}
}
else
if
(
tsx
->
state
==
PJSIP_TSX_STATE_COMPLETED
&&
tsx
->
role
==
PJSIP_ROLE_UAC
)
{
if
(
tsx
->
status_code
/
100
==
6
||
tsx
->
status_code
==
404
)
{
_debug
(
"Receive server error message
\n
"
);
SIPCall
*
call
=
reinterpret_cast
<
SIPCall
*>
(
inv
->
mod_data
[
getInstance
()
->
getModId
()]);
if
(
call
==
NULL
)
{
_debug
(
"Call has been removed!
\n
"
);
return
;
}
AccountID
accId
=
Manager
::
instance
().
getAccountFromCall
(
call
->
getCallId
());
SIPVoIPLink
*
link
=
dynamic_cast
<
SIPVoIPLink
*>
(
Manager
::
instance
().
getAccountLink
(
accId
));
if
(
link
)
{
link
->
SIPCallServerFailure
(
call
);
inv
->
mod_data
[
getInstance
()
->
getModId
()]
=
NULL
;
}
}
}
}
void
SIPManager
::
call_on_state_changed
(
pjsip_inv_session
*
inv
,
pjsip_event
*
e
)
{
PJ_UNUSED_ARG
(
inv
);
/*if( inv->state == PJSIP_INV_STATE_CONFIRMED ) {
_debug("Use this to handle the incoming call!!!\n");
SIPCall *call = reinterpret_cast<SIPCall *>(inv->mod_data[getInstance()->getModId()]);
_debug("The call id is %s\n", call->getCallId().data());
pjsip_rx_data *rdata = e->body.tsx_state.src.rdata;
AccountID accId = Manager::instance().getAccountFromCall(call->getCallId());
Manager::instance().getAccountLink(accId)->callAnswered(call, rdata);
}*/
}
bool
SIPManager
::
onhold
(
SIPCall
*
call
)
{
_debug
(
"*********Before onhold pjsip_inv_reinite begins***********
\n
"
);
pj_status_t
status
;
pjsip_tx_data
*
tdata
;
pjmedia_sdp_attr
*
attr
;
/* Create re-INVITE with new offer */
pjmedia_sdp_media_remove_all_attr
(
call
->
getLocalSDPSession
()
->
media
[
0
],
"sendrecv"
);
attr
=
pjmedia_sdp_attr_create
(
_pool
,
"sendonly"
,
NULL
);
pjmedia_sdp_media_add_attr
(
call
->
getLocalSDPSession
()
->
media
[
0
],
attr
);
status
=
pjsip_inv_reinvite
(
_invSession
,
NULL
,
call
->
getLocalSDPSession
(),
&
tdata
);
/* Send the request */
status
=
pjsip_inv_send_msg
(
_invSession
,
tdata
);
_debug
(
"*********After pjsip_inv_reinite begins***********
\n
"
);
}
bool
SIPManager
::
offhold
(
SIPCall
*
call
)
{
_debug
(
"*********Before offhold pjsip_inv_reinite begins***********
\n
"
);
pj_status_t
status
;
pjsip_tx_data
*
tdata
;
pjmedia_sdp_attr
*
attr
;
/* Create re-INVITE with new offer */
pjmedia_sdp_media_remove_all_attr
(
call
->
getLocalSDPSession
()
->
media
[
0
],
"sendonly"
);
attr
=
pjmedia_sdp_attr_create
(
_pool
,
"sendrecv"
,
NULL
);
pjmedia_sdp_media_add_attr
(
call
->
getLocalSDPSession
()
->
media
[
0
],
attr
);
status
=
pjsip_inv_reinvite
(
_invSession
,
NULL
,
call
->
getLocalSDPSession
(),
&
tdata
);
/* Send the request */
status
=
pjsip_inv_send_msg
(
_invSession
,
tdata
);
_debug
(
"*********After pjsip_inv_reinite begins***********
\n
"
);
}
bool
SIPManager
::
hangup
()
{
pj_status_t
status
;
pjsip_tx_data
*
tdata
;
status
=
pjsip_inv_end_session
(
_invSession
,
404
,
NULL
,
&
tdata
);
PJ_ASSERT_RETURN
(
status
==
PJ_SUCCESS
,
false
);
status
=
pjsip_inv_send_msg
(
_invSession
,
tdata
);
PJ_ASSERT_RETURN
(
status
==
PJ_SUCCESS
,
false
);
_invSession
->
mod_data
[
getInstance
()
->
getModId
()]
=
NULL
;
return
true
;
}
bool
SIPManager
::
refuse
()
{
pj_status_t
status
;
pjsip_tx_data
*
tdata
;
status
=
pjsip_inv_end_session
(
_invSession
,
PJSIP_SC_DECLINE
,
NULL
,
&
tdata
);
//603
PJ_ASSERT_RETURN
(
status
==
PJ_SUCCESS
,
false
);
status
=
pjsip_inv_send_msg
(
_invSession
,
tdata
);
PJ_ASSERT_RETURN
(
status
==
PJ_SUCCESS
,
false
);
_invSession
->
mod_data
[
getInstance
()
->
getModId
()]
=
NULL
;
return
true
;
}
bool
SIPManager
::
transfer
(
SIPCall
*
call
,
const
std
::
string
&
to
)
{
pjsip_evsub
*
sub
;
pjsip_tx_data
*
tdata
;
pjsip_dialog
*
dlg
;
pjsip_generic_string_hdr
*
gs_hdr
;
const
pj_str_t
str_ref_by
=
{
"Referred-By"
,
11
};
struct
pjsip_evsub_user
xfer_cb
;
pj_status_t
status
;
pj_str_t
dest
;
pj_strdup2
(
_pool
,
&
dest
,
to
.
data
());
/* Create xfer client subscription. */
pj_bzero
(
&
xfer_cb
,
sizeof
(
xfer_cb
));
xfer_cb
.
on_evsub_state
=
&
xfer_func_cb
;
status
=
pjsip_xfer_create_uac
(
_invSession
->
dlg
,
&
xfer_cb
,
&
sub
);
if
(
status
!=
PJ_SUCCESS
)
{
_debug
(
"Unable to create xfer -- %d
\n
"
,
status
);
return
false
;
}
_debug
(
"xfer created!!!!!!!!!!!!!!!
\n
"
);
/* Associate this call with the client subscription */
AccountID
accId
=
Manager
::
instance
().
getAccountFromCall
(
call
->
getCallId
());
SIPVoIPLink
*
link
=
dynamic_cast
<
SIPVoIPLink
*>
(
Manager
::
instance
().
getAccountLink
(
accId
));
pjsip_evsub_set_mod_data
(
sub
,
_mod
.
id
,
link
);
_debug
(
"call associated!!!!!!!!!!!!!!!
\n
"
);
/*
* Create REFER request.
*/
status
=
pjsip_xfer_initiate
(
sub
,
&
dest
,
&
tdata
);
if
(
status
!=
PJ_SUCCESS
)
{
_debug
(
"Unable to create REFER request -- %d
\n
"
,
status
);
return
false
;
}
_debug
(
"Here1 !!!!!!!!!!!!!!!!!!!
\n
"
);
/* Add Referred-By header */
//gs_hdr = pjsip_generic_string_hdr_create(tdata->pool, &str_ref_by, &dest);
//_debug("22222222222222222222222222\n");
//pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)gs_hdr);
//_debug("3333333333333333333333333333\n");
/* Send. */
status
=
pjsip_xfer_send_request
(
sub
,
tdata
);
if
(
status
!=
PJ_SUCCESS
)
{
_debug
(
"Unable to send REFER request -- %d
\n
"
,
status
);
return
false
;
}
return
true
;
}
void
SIPManager
::
xfer_func_cb
(
pjsip_evsub
*
sub
,
pjsip_event
*
event
)
{
PJ_UNUSED_ARG
(
event
);
_debug
(
"#############We are in the callback!!!
\n
"
);
/*
* When subscription is accepted (got 200/OK to REFER), check if
* subscription suppressed.
*/
if
(
pjsip_evsub_get_state
(
sub
)
==
PJSIP_EVSUB_STATE_ACCEPTED
)
{
pjsip_rx_data
*
rdata
;
pjsip_generic_string_hdr
*
refer_sub
;
const
pj_str_t
REFER_SUB
=
{
"Refer-Sub"
,
9
};
SIPVoIPLink
*
link
=
reinterpret_cast
<
SIPVoIPLink
*>
(
pjsip_evsub_get_mod_data
(
sub
,
getInstance
()
->
getModId
()));
/* Must be receipt of response message */
pj_assert
(
event
->
type
==
PJSIP_EVENT_TSX_STATE
&&
event
->
body
.
tsx_state
.
type
==
PJSIP_EVENT_RX_MSG
);
rdata
=
event
->
body
.
tsx_state
.
src
.
rdata
;
/* Find Refer-Sub header */
refer_sub
=
(
pjsip_generic_string_hdr
*
)
pjsip_msg_find_hdr_by_name
(
rdata
->
msg_info
.
msg
,
&
REFER_SUB
,
NULL
);
/* Check if subscription is suppressed */
if
(
refer_sub
&&
pj_stricmp2
(
&
refer_sub
->
hvalue
,
"false"
)
==
0
)
{
/* Since no subscription is desired, assume that call has been
* transfered successfully.
*/
if
(
link
)
{
link
->
transferStep2
();
}
/* Yes, subscription is suppressed.
* Terminate our subscription now.
*/
_debug
(
"Xfer subscription suppressed, terminating event subcription...
\n
"
);
pjsip_evsub_terminate
(
sub
,
PJ_TRUE
);
}
else
{
/* Notify application about call transfer progress.
* Initially notify with 100/Accepted status.
*/
_debug
(
"Xfer subscription 100/Accepted received...
\n
"
);
}
}
/*
* On incoming NOTIFY, notify application about call transfer progress.
*/
else
if
(
pjsip_evsub_get_state
(
sub
)
==
PJSIP_EVSUB_STATE_ACTIVE
||
pjsip_evsub_get_state
(
sub
)
==
PJSIP_EVSUB_STATE_TERMINATED
)
{
pjsip_msg
*
msg
;
pjsip_msg_body
*
body
;
pjsip_status_line
status_line
;
pj_bool_t
is_last
;
pj_bool_t
cont
;
pj_status_t
status
;
SIPVoIPLink
*
link
=
reinterpret_cast
<
SIPVoIPLink
*>
(
pjsip_evsub_get_mod_data
(
sub
,
getInstance
()
->
getModId
()));
/* When subscription is terminated, clear the xfer_sub member of
* the inv_data.
*/
if
(
pjsip_evsub_get_state
(
sub
)
==
PJSIP_EVSUB_STATE_TERMINATED
)
{
pjsip_evsub_set_mod_data
(
sub
,
getInstance
()
->
getModId
(),
NULL
);
_debug
(
"Xfer client subscription terminated
\n
"
);
}
if
(
!
link
||
!
event
)
{
/* Application is not interested with call progress status */
_debug
(
"Either link or event is empty!
\n
"
);
return
;
}
/* This better be a NOTIFY request */
if
(
event
->
type
==
PJSIP_EVENT_TSX_STATE
&&
event
->
body
.
tsx_state
.
type
==
PJSIP_EVENT_RX_MSG
)
{
pjsip_rx_data
*
rdata
;
rdata
=
event
->
body
.
tsx_state
.
src
.
rdata
;
/* Check if there's body */
msg
=
rdata
->
msg_info
.
msg
;
body
=
msg
->
body
;
if
(
!
body
)
{
_debug
(
"Warning: received NOTIFY without message body
\n
"
);
return
;
}
/* Check for appropriate content */
if
(
pj_stricmp2
(
&
body
->
content_type
.
type
,
"message"
)
!=
0
||
pj_stricmp2
(
&
body
->
content_type
.
subtype
,
"sipfrag"
)
!=
0
)
{
_debug
(
"Warning: received NOTIFY with non message/sipfrag content
\n
"
);
return
;
}
/* Try to parse the content */
status
=
pjsip_parse_status_line
((
char
*
)
body
->
data
,
body
->
len
,
&
status_line
);
if
(
status
!=
PJ_SUCCESS
)
{
_debug
(
"Warning: received NOTIFY with invalid message/sipfrag content
\n
"
);
return
;
}
}
else
{
_debug
(
"Set code to 500!
\n
"
);
status_line
.
code
=
500
;
status_line
.
reason
=
*
pjsip_get_status_text
(
500
);
}
/* Notify application */
is_last
=
(
pjsip_evsub_get_state
(
sub
)
==
PJSIP_EVSUB_STATE_TERMINATED
);
cont
=
!
is_last
;
if
(
status_line
.
code
/
100
==
2
)
{
_debug
(
"Try to stop rtp!
\n
"
);
pjsip_tx_data
*
tdata
;
status
=
pjsip_inv_end_session
(
_invSession
,
PJSIP_SC_GONE
,
NULL
,
&
tdata
);
if
(
status
!=
PJ_SUCCESS
)
{
_debug
(
"Fail to create end session msg!
\n
"
);
}
else
{
status
=
pjsip_inv_send_msg
(
_invSession
,
tdata
);
if
(
status
!=
PJ_SUCCESS
)
_debug
(
"Fail to send end session msg!
\n
"
);
}
link
->
transferStep2
();
cont
=
PJ_FALSE
;
}
if
(
!
cont
)
{
pjsip_evsub_set_mod_data
(
sub
,
getInstance
()
->
getModId
(),
NULL
);
}
}
}
This diff is collapsed.
Click to expand it.
src/sipmanager.h
0 → 100755
+
152
−
0
View file @
41643411
/*
* Copyright (C) 2004-2005 Savoir-Faire Linux inc.
* Author: Yun Liu <yun.liu@savoirfairelinux.com>
*
* 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, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _SIPMANAGER_H
#define _SIPMANAGER_H
#include
<pjsip.h>
#include
<pjlib-util.h>
#include
<pjlib.h>
#include
<pjnath/stun_config.h>
#include
<pjsip_simple.h>
#include
<pjsip_ua.h>
#include
<pjmedia/sdp.h>
#include
<pjmedia/sdp_neg.h>
#include
<string>
#include
<vector>
#define MSG_OK 200
#define MSG_METHOD_NOT_ALLOWED 405
#define MSG_NOT_ACCEPTABLE_HERE 488
#define MSG_SERVER_INTERNAL_ERROR 500
typedef
std
::
string
AccountID
;
class
SIPCall
;
class
SIPManager
{
private:
/** PJSIP Endpoint */
pjsip_endpoint
*
_endpt
;
pj_sock_t
_sock
;
//pjsip_module _appMod;
pj_caching_pool
_cp
;
pj_pool_t
*
_pool
;
pj_thread_t
*
_voip_listen_thread
;
pj_mutex_t
*
_mutex
;
/** Mutex protection for this data */
pjsip_module
_mod
;
/** PJSIP module. */
pjsip_module
_options_handler
;
bool
_useStun
;
pj_str_t
_stunHost
;
std
::
string
_stunServer
;
/** Local Extern Address is the IP address seen by peers for SIP listener */
std
::
string
_localExternAddress
;
std
::
string
_localIPAddress
;
/** Local Extern Port is the port seen by peers for SIP listener */
unsigned
int
_localExternPort
;
unsigned
int
_localPort
;
pj_thread_t
*
_thread
;
static
SIPManager
*
_current
;
static
pjsip_inv_session
*
_invSession
;
struct
AccBaseInfo
{
std
::
string
userName
;
std
::
string
server
;
AccountID
id
;
pjsip_cred_info
cred
;
pj_str_t
contact
;
};
typedef
std
::
vector
<
AccBaseInfo
*>
AccBaseInfoList
;
AccBaseInfoList
_accBaseInfoList
;
public
:
SIPManager
();
~
SIPManager
();
pj_status_t
sipCreate
();
/**
* This method is used to initialize the pjsip
*/
pj_status_t
sipInit
();
/** Create SIP UDP Listener */
int
createUDPServer
();
/** Set whether it will use stun server */
void
setStunServer
(
const
char
*
server
);
//{_stunHost = pj_str(server); _useStun = true;};
pj_str_t
getStunServer
()
{
return
_stunHost
;}
//bool addAccount(AccountID id, pjsip_regc *regc, const pj_str_t& registrar, pj_str_t& user, pjsip_cred_info& cred, int& timeout);
bool
addAccount
(
AccountID
id
,
pjsip_regc
*
regc
,
const
std
::
string
&
server
,
const
std
::
string
&
user
,
const
std
::
string
&
passwd
,
const
int
&
timeout
);
pj_str_t
buildContact
(
char
*
userName
);
bool
loadSIPLocalIP
();
pj_status_t
stunServerResolve
();
pjsip_endpoint
*
getEndPoint
()
{
return
_endpt
;}
std
::
string
getLocalIP
()
{
return
_localExternAddress
;}
int
getModId
()
{
return
_mod
.
id
;}
AccountID
getAccountIdFromNameAndServer
(
const
std
::
string
&
userName
,
const
std
::
string
&
server
);
AccBaseInfo
*
getAccountInfoFromId
(
AccountID
id
);
bool
setCallAudioLocal
(
SIPCall
*
call
);
int
answer
(
SIPCall
*
call
);
bool
hangup
();
bool
refuse
();
bool
onhold
(
SIPCall
*
call
);
bool
offhold
(
SIPCall
*
call
);
bool
transfer
(
SIPCall
*
call
,
const
std
::
string
&
to
);
bool
makeOutgoingCall
(
const
std
::
string
&
to
,
SIPCall
*
call
,
const
AccountID
&
id
);
pj_pool_t
*
getAppPool
()
{
return
_pool
;}
static
pj_bool_t
mod_on_rx_request
(
pjsip_rx_data
*
rdata
);
static
pj_bool_t
mod_on_rx_response
(
pjsip_rx_data
*
rdata
)
{
return
PJ_SUCCESS
;}
static
pj_bool_t
options_on_rx_request
(
pjsip_rx_data
*
rdata
)
{
return
PJ_SUCCESS
;}
static
void
regc_cb
(
struct
pjsip_regc_cbparam
*
param
);
static
void
xfer_func_cb
(
pjsip_evsub
*
sub
,
pjsip_event
*
event
);
static
void
call_on_media_update
(
pjsip_inv_session
*
inv
,
pj_status_t
status
)
{}
static
void
call_on_state_changed
(
pjsip_inv_session
*
inv
,
pjsip_event
*
e
);
static
void
call_on_forked
(
pjsip_inv_session
*
inv
,
pjsip_event
*
e
);
static
void
call_on_tsx_changed
(
pjsip_inv_session
*
inv
,
pjsip_transaction
*
tsx
,
pjsip_event
*
e
);
static
int
worker_thread
(
void
*
arg
);
static
SIPManager
*
getInstance
()
{
return
_current
;}
};
#endif
/* _SIPMANAGER_H */
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment