- resiprocate is back as a part of solid repo

This commit is contained in:
2026-01-31 22:04:21 +03:00
parent 7a5ed7d369
commit 1a506862d2
7704 changed files with 2005146 additions and 0 deletions

View File

@@ -0,0 +1,16 @@
image: Visual Studio 2015
configuration:
- Debug
- Release
platform:
- x64
- Win32
build:
parallel: true
project: reSIProcate_14_0.sln
matrix:
fast_finish: true

View File

@@ -0,0 +1,12 @@
Checks: >-
-*,
bugprone-exception-escape,
bugprone-move-forwarding-reference,
bugprone-undefined-memory-manipulation,
bugprone-unhandled-self-assignment,
bugprone-use-after-move,
performance-move-const-arg,
performance-move-constructor-init,
performance-no-automatic-move,
performance-noexcept-move-constructor
HeaderFilterRegex: .*

View File

@@ -0,0 +1,5 @@
[*]
indent_style=space
[*.{hxx,cxx,hpp,cpp,h,c}]
indent_size=3

View File

@@ -0,0 +1,92 @@
name: CI
on: [push, pull_request]
jobs:
build:
name: Build with ${{ matrix.c-compiler }}
runs-on: ubuntu-20.04
container:
image: debian:bullseye-slim
options: --ulimit memlock=-1
strategy:
fail-fast: false
matrix:
c-compiler: [gcc-10, clang-13]
include:
- c-compiler: gcc-10
cxx-compiler: g++-10
- c-compiler: clang-13
cxx-compiler: clang++-13
env:
CC: /usr/bin/${{ matrix.c-compiler }}
CXX: /usr/bin/${{ matrix.cxx-compiler }}
steps:
- name: Get number of CPU cores
uses: SimenB/github-actions-cpu-cores@v1.1.0
id: cpu-cores
- name: Install Dependencies
run: |
echo "deb http://deb.debian.org/debian bullseye-backports main" > /etc/apt/sources.list.d/backports.list
apt-get update -qq
apt-get install -qq wget
wget -O - http://apt.debify.org/add-apt-debify | bash
apt-get update -qq
apt-get install -qq \
clang-13 \
clang-tidy-13 \
cmake \
default-libmysqlclient-dev \
g++-10 \
git \
gperf \
libasio-dev \
libboost-all-dev \
libc-ares-dev \
libcajun-dev \
libcppunit-dev \
libdb++-dev \
libfmt-dev \
libgeoip-dev \
libgloox-dev \
libgstreamermm-1.0-dev \
libpcre3-dev \
libpopt-dev \
libpq-dev \
postgresql-server-dev-all \
libqpid-proton-cpp12-dev \
libradcli-dev \
libsipxtapi-dev \
libsnmp-dev \
libsoci-dev \
libsrtp2-dev \
libssl-dev \
libtelepathy-qt5-dev \
libwebsocketpp-dev \
libxerces-c-dev \
lld-13 \
make \
perl \
python3-cxx-dev \
python3-dev \
sox \
xxd
- name: Checkout source
uses: actions/checkout@v3
- name: Bootstrap
run: ./build/travis/bootstrap
- name: Configure
run: ./build/travis/configure
- name: Build
run: ./build/travis/build
- name: Analyse
if: ${{ matrix.c-compiler == 'clang-13' }}
run: run-clang-tidy-13 -j ${{ steps.cpu-cores.outputs.count }} -quiet
- name: Test
run: make -j1 CTEST_OUTPUT_ON_FAILURE=1 test

75
src/libs/resiprocate/.gitignore vendored Normal file
View File

@@ -0,0 +1,75 @@
# This file is only looked at when a checked-out SVN
# repository is used as the source for a git repo.
*.dll
*.o
*.lo
*.la
*.bak
*.obj
*.pdb
*.ilk
*.idb
*.log
/Makefile
/Makefile.in
/.deps
/.libs
**/.vs
/aclocal.m4
/config.h
/config.h.in
/config.log
/config.status
/configure
/libtool
/m4
/stamp-h1
/autom4te.cache
/build-aux
/packages
/resiprocate.spec
/resiprocate-[0-9]*.tar.gz
/resiprocate-[0-9]*.zip
/resiprocate-contrib-[0-9]*.tar.gz
/resiprocate-contrib-[0-9]*.zip
repro_*.db
reproInfo.hxx
/SVN-VERSION
/.make_prefs
/build/Makefile.conf
tags
*build.Linux*
.dependlibs
bin.debug.*
obj.debug.*
bin.opt.*
obj.opt.*
bin.gopt.*
obj.gopt.*
obj.prof.*
bin.prof.*
**/[Ww]in32
**/x64
*.vcxproj.user
**/Debug Dll
**/Release Dll
**/x64-Debug
**/packages
**/test/*.exe
/.idea
/cmake-build-*
CMakeCache.txt
CPackConfig.cmake
CPackSourceConfig.cmake
**/CMakeFiles/
**/CTestTestfile.cmake
**/cmake_install.cmake
**/lib*.so
**/lib*.so.*
**/Testing/

View File

@@ -0,0 +1,89 @@
Please add your name, email address and if you contribute on
behalf of a company, please identity the name of the company,
company registration number and the place of incorporation.
This file identifies the authors/contributors/copyright holders who
have contributed works of any kind to the main reSIProcate
distribution tarball.
This file does not cover the material in the contrib/ directory of
the source control system, as each of those components is
unmodified and distributed with it's own AUTHORS file.
$ git log | grep ^Author | sort -u | cut -f2 -d' '
adam
adamr
alan
arosenberg
bbramwel
bcampen
bko
bob
brocha
bryan
cbond
cisco
cktam
dabryan
daniel
danweber
Danweber
davidb
dbozzali
dean
derek
Derek
derekm
dlb
dpetrie
dpocock: Daniel Pocock <daniel@pocock.com.au>
dragos
dsuh
duanestorey
dworley
ekr
emcmurry
fjoanis
fluffy
greg
jason
jdeverick
jgeras
jmatthewsr
jozsef
kchmilar
kdc
kenho
ken
kittlitz
kwhite
lowekamp
matthias
maxb
mfroman
moetje
nagendra
nash
nils
(no
partim
pckizer
rjsparks
rohan
ronh
ryker
sailesh
satluri
schanin
sgodin
shaun
troll
vann
veer
vinit
wensong
xmlscott

View File

@@ -0,0 +1,67 @@
If you use the helper scripts build/debian.sh or build/fedora.sh
they will automatically check if you have ccache and distcc
on your system and enable both of them.
ccache improves performance even if you only have a single system to
build on.
For our scripts to work, please install both of them together, even
if you only need one of them:
Debian/Ubuntu:
$ sudo apt install ccache distcc distcc-pump
Fedora/Red Hat/RPM-based systems:
$ sudo dnf install ccache distcc
On each host that will participate in a distcc build you need to install
the distcc package and the same compiler used on the primary workstation.
For example, if you are using GNU C/C++ locally, you need to install that
on every distcc host. If you use CLang locally, you need to install that
on every distcc host too.
If you are using the regular distcc TCP connection over a LAN or VPN,
on each of the participating build servers, run the distccd daemon,
for example:
$ distccd --daemon
If you are going to use distcc over SSH then do not start the daemon,
the client starts it for you.
On the workstation where you are starting the build, you can setup
the distcc configuration in an environment variable or configuration
file. Here is a simple example with the environment variable:
$ export DISTCC_HOSTS='localhost/2 --localslots_cpp=5 192.168.1.105/63'
The above command includes the following:
localhost/2 - use up to 2 cores on the local CPU
--localslots_cpp=5 - use up to 5 cores for C preprocessor locally
192.168.1.105/63 - use up to 63 cores on server 192.168.1.105
If you want to use SSH instead of TCP, use this environment variable instead:
$ export DISTCC_HOSTS='localhost/2 --localslots_cpp=5 @192.168.1.105/63'
With the environment configured, you can now run the configure and compile.
For example, on a Debian/Ubuntu host:
$ ssh 192.168.1.105 distccd --daemon
$ export DISTCC_HOSTS='localhost/2 --localslots_cpp=5 192.168.1.105/63'
$ build/debian.sh
$ make clean
$ make -j70
On a Fedora/Red Hat host:
$ ssh 192.168.1.105 distccd --daemon
$ export DISTCC_HOSTS='localhost/2 --localslots_cpp=5 192.168.1.105/63'
$ build/fedora.sh
$ make clean
$ make -j70

View File

@@ -0,0 +1,372 @@
project (resiprocate)
if (NOT OPENSSL_INCLUDE)
message(FATAL_ERROR "OPENSSL_INCLUDE has to be directory with OpenSSL 1.1.x include files.")
endif()
# Rely on C++ 20
set (CMAKE_CXX_STANDARD 20)
set (CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set (DIR_ARES rutil/dns/ares)
set (ARES_SOURCES
${DIR_ARES}/ares_timeout.c
${DIR_ARES}/ares_strerror.c
${DIR_ARES}/ares_send.c
${DIR_ARES}/ares_search.c
${DIR_ARES}/ares_query.c
${DIR_ARES}/ares_process.c
${DIR_ARES}/ares_parse_ptr_reply.c
${DIR_ARES}/ares_parse_a_reply.c
${DIR_ARES}/ares_mkquery.c
${DIR_ARES}/ares_local.c
${DIR_ARES}/ares_init.c
${DIR_ARES}/ares_gethostbyname.c
${DIR_ARES}/ares_gethostbyaddr.c
${DIR_ARES}/ares_free_string.c
${DIR_ARES}/ares_free_hostent.c
${DIR_ARES}/ares_free_errmem.c
${DIR_ARES}/ares_fds.c
${DIR_ARES}/ares_expand_name.c
${DIR_ARES}/ares_destroy.c
${DIR_ARES}/ares__read_line.c
${DIR_ARES}/ares__get_hostent.c
${DIR_ARES}/ares__close_sockets.c
)
set (STACK_SOURCES
resip/stack/TokenOrQuotedStringCategory.hxx
resip/stack/TokenOrQuotedStringCategory.cxx
resip/stack/TrickleIceContents.hxx
resip/stack/TrickleIceContents.cxx
resip/stack/TcpConnectState.hxx
resip/stack/TcpConnectState.cxx
resip/stack/gen/MonthHash.cxx
resip/stack/gen/DayOfWeekHash.cxx
resip/stack/Compression.cxx
resip/stack/CallId.cxx
resip/stack/BranchParameter.cxx
resip/stack/BasicNonceHelper.cxx
resip/stack/Auth.cxx
resip/stack/ApplicationSip.cxx
resip/stack/ApiCheck.cxx
resip/stack/Aor.cxx
resip/stack/DateCategory.cxx
resip/stack/DataParameter.cxx
resip/stack/CSeqCategory.cxx
resip/stack/CpimContents.cxx
resip/stack/ContentsFactoryBase.cxx
resip/stack/Contents.cxx
resip/stack/ConnectionManager.cxx
resip/stack/ConnectionBase.cxx
resip/stack/Connection.cxx
resip/stack/DnsResult.cxx
resip/stack/DnsInterface.cxx
resip/stack/DeprecatedDialog.cxx
resip/stack/GenericUri.cxx
resip/stack/GenericContents.cxx
resip/stack/FloatParameter.cxx
resip/stack/ExternalBodyContents.cxx
resip/stack/ExtensionParameter.cxx
resip/stack/ExtensionHeader.cxx
resip/stack/ExpiresCategory.cxx
resip/stack/ExistsParameter.cxx
resip/stack/ExistsOrDataParameter.cxx
resip/stack/EventStackThread.cxx
resip/stack/Embedded.cxx
resip/stack/DtlsMessage.cxx
resip/stack/gen/HeaderHash.cxx
resip/stack/HeaderFieldValueList.cxx
resip/stack/HeaderFieldValue.cxx
resip/stack/MsgHeaderScanner.cxx
resip/stack/Mime.cxx
resip/stack/MethodTypes.cxx
resip/stack/gen/MethodHash.cxx
resip/stack/MessageWaitingContents.cxx
resip/stack/MessageFilterRule.cxx
resip/stack/Message.cxx
resip/stack/LazyParser.cxx
resip/stack/KeepAliveMessage.cxx
resip/stack/InvalidContents.cxx
resip/stack/InterruptableStackThread.cxx
resip/stack/InteropHelper.cxx
resip/stack/InternalTransport.cxx
resip/stack/IntegerParameter.cxx
resip/stack/IntegerCategory.cxx
resip/stack/Helper.cxx
resip/stack/HeaderTypes.cxx
resip/stack/Headers.cxx
resip/stack/gen/ParameterHash.cxx
resip/stack/Parameter.cxx
resip/stack/OctetContents.cxx
resip/stack/NonceHelper.cxx
resip/stack/NameAddr.cxx
resip/stack/MultipartSignedContents.cxx
resip/stack/MultipartRelatedContents.cxx
resip/stack/MultipartMixedContents.cxx
resip/stack/MultipartAlternativeContents.cxx
resip/stack/SipStack.cxx
resip/stack/SipMessage.cxx
resip/stack/SipFrag.cxx
resip/stack/SERNonceHelper.cxx
resip/stack/SecurityAttributes.cxx
resip/stack/SdpContents.cxx
resip/stack/RportParameter.cxx
resip/stack/Rlmi.cxx
resip/stack/RequestLine.cxx
resip/stack/RAckCategory.cxx
resip/stack/QValueParameter.cxx
resip/stack/QValue.cxx
resip/stack/QuotedDataParameter.cxx
resip/stack/PrivacyCategory.cxx
resip/stack/PlainContents.cxx
resip/stack/Pkcs8Contents.cxx
resip/stack/Pkcs7Contents.cxx
resip/stack/Pidf.cxx
resip/stack/ParserContainerBase.cxx
resip/stack/ParserCategory.cxx
resip/stack/ParserCategories.cxx
resip/stack/ParameterTypes.cxx
resip/stack/X509Contents.cxx
resip/stack/WarningCategory.cxx
resip/stack/Via.cxx
resip/stack/Uri.cxx
resip/stack/UnknownParameter.cxx
resip/stack/UInt32Parameter.cxx
resip/stack/UInt32Category.cxx
resip/stack/Cookie.hxx
resip/stack/Cookie.cxx
resip/stack/UdpTransport.cxx
resip/stack/WsBaseTransport.cxx
resip/stack/WsBaseTransport.hxx
resip/stack/WsConnectionBase.cxx
resip/stack/WsConnectionBase.hxx
resip/stack/WsConnection.cxx
resip/stack/WsConnection.hxx
resip/stack/WsTransport.cxx
resip/stack/WsTransport.hxx
resip/stack/WsFrameExtractor.cxx
resip/stack/WsFrameExtractor.hxx
resip/stack/WsCookieContext.cxx
resip/stack/WsCookieContext.hxx
resip/stack/WsDecorator.cxx
resip/stack/WsDecorator.hxx
resip/stack/ssl/WssTransport.cxx
resip/stack/ssl/WssTransport.hxx
resip/stack/ssl/WssConnection.cxx
resip/stack/ssl/WssConnection.hxx
resip/stack/ssl/TlsBaseTransport.cxx
resip/stack/ssl/TlsBaseTransport.hxx
resip/stack/TuSelector.cxx
resip/stack/TupleMarkManager.cxx
resip/stack/Tuple.cxx
resip/stack/TuIM.cxx
resip/stack/TransportThread.cxx
resip/stack/TransportSelector.cxx
resip/stack/TransportFailure.cxx
resip/stack/Transport.cxx
resip/stack/TransactionUserMessage.cxx
resip/stack/TransactionUser.cxx
resip/stack/TransactionState.cxx
resip/stack/TransactionMap.cxx
resip/stack/TransactionController.cxx
resip/stack/Token.cxx
resip/stack/TimerQueue.cxx
resip/stack/TimerMessage.cxx
resip/stack/TimeAccumulate.cxx
resip/stack/TcpTransport.cxx
resip/stack/TcpConnection.cxx
resip/stack/TcpBaseTransport.cxx
resip/stack/Symbols.cxx
resip/stack/StringCategory.cxx
resip/stack/StatusLine.cxx
resip/stack/StatisticsMessage.cxx
resip/stack/StatisticsManager.cxx
resip/stack/StatisticsHandler.cxx
resip/stack/StatelessHandler.cxx
resip/stack/StackThread.cxx
resip/stack/ssl/Security.cxx
#resip/stack/ssl/MacSecurity.cxx
resip/stack/ssl/TlsConnection.cxx
resip/stack/ssl/TlsTransport.cxx
resip/stack/BasicDomainMatcher.hxx
resip/stack/BasicDomainMatcher.cxx
)
if (CMAKE_SYSTEM MATCHES "Windows*")
set (STACK_SOURCES ${STACK_SOURCES}
resip/stack/ssl/WinSecurity.cxx)
endif()
set (DUM_SOURCES
resip/dum/DialogUsageManager.cxx
resip/dum/DialogUsage.cxx
resip/dum/DialogSetId.cxx
resip/dum/DialogSet.cxx
resip/dum/DialogId.cxx
resip/dum/DialogEventStateManager.cxx
resip/dum/DialogEventInfo.cxx
resip/dum/Dialog.cxx
resip/dum/DestroyUsage.cxx
resip/dum/DefaultServerReferHandler.cxx
resip/dum/ContactInstanceRecord.cxx
resip/dum/ClientSubscription.cxx
resip/dum/ClientRegistration.cxx
resip/dum/ClientPublication.cxx
resip/dum/ClientPagerMessage.cxx
resip/dum/ClientOutOfDialogReq.cxx
resip/dum/ClientInviteSession.cxx
resip/dum/ClientAuthManager.cxx
resip/dum/ClientAuthExtension.cxx
resip/dum/ChallengeInfo.cxx
resip/dum/CertMessage.cxx
resip/dum/BaseUsage.cxx
resip/dum/BaseSubscription.cxx
resip/dum/BaseCreator.cxx
resip/dum/AppDialogSetFactory.cxx
resip/dum/AppDialogSet.cxx
resip/dum/AppDialog.cxx
resip/dum/KeepAliveTimeout.cxx
resip/dum/KeepAliveManager.cxx
resip/dum/InviteSessionHandler.cxx
resip/dum/InviteSessionCreator.cxx
resip/dum/InviteSession.cxx
resip/dum/InMemorySyncRegDb.cxx
resip/dum/InMemoryRegistrationDatabase.cxx
resip/dum/IdentityHandler.cxx
resip/dum/HttpProvider.cxx
resip/dum/HttpGetMessage.cxx
resip/dum/HandleManager.cxx
resip/dum/HandleException.cxx
resip/dum/Handled.cxx
resip/dum/Handle.cxx
resip/dum/EncryptionRequest.cxx
resip/dum/DumTimeout.cxx
resip/dum/DumThread.cxx
resip/dum/DumProcessHandler.cxx
resip/dum/DumHelper.cxx
resip/dum/DumFeatureMessage.cxx
resip/dum/DumFeatureChain.cxx
resip/dum/DumFeature.cxx
resip/dum/DumDecrypted.cxx
resip/dum/ServerSubscription.cxx
resip/dum/ServerRegistration.cxx
resip/dum/ServerPublication.cxx
resip/dum/ServerPagerMessage.cxx
resip/dum/ServerOutOfDialogReq.cxx
resip/dum/ServerInviteSession.cxx
resip/dum/ServerAuthManager.cxx
resip/dum/RegistrationHandler.cxx
resip/dum/RegistrationCreator.cxx
resip/dum/RedirectManager.cxx
resip/dum/RADIUSServerAuthManager.cxx
resip/dum/PublicationCreator.cxx
resip/dum/Profile.cxx
resip/dum/PagerMessageCreator.cxx
resip/dum/OutOfDialogReqCreator.cxx
resip/dum/OutgoingEvent.cxx
resip/dum/NonDialogUsage.cxx
resip/dum/NetworkAssociation.cxx
resip/dum/MergedRequestRemovalCommand.cxx
resip/dum/MergedRequestKey.cxx
resip/dum/MasterProfile.cxx
resip/dum/UserProfile.cxx
resip/dum/UserAuthInfo.cxx
resip/dum/TlsPeerAuthManager.cxx
resip/dum/TargetCommand.cxx
resip/dum/SubscriptionState.cxx
resip/dum/SubscriptionHandler.cxx
resip/dum/SubscriptionCreator.cxx
resip/dum/ssl/EncryptionManager.cxx
)
SET (RUTIL_SOURCES
rutil/FileSystem.cxx
rutil/FdPoll.cxx
rutil/DnsUtil.cxx
rutil/ssl/OpenSSLInit.cxx
rutil/ssl/SHA1Stream.cxx
rutil/dns/RRVip.cxx
rutil/dns/RROverlay.cxx
rutil/dns/RRList.cxx
rutil/dns/RRCache.cxx
rutil/dns/QueryTypes.cxx
# rutil/dns/LocalDns.cxx
rutil/dns/ExternalDnsFactory.cxx
rutil/dns/DnsThread.cxx
rutil/dns/DnsStub.cxx
rutil/dns/DnsSrvRecord.cxx
rutil/dns/DnsResourceRecord.cxx
rutil/dns/DnsNaptrRecord.cxx
rutil/dns/DnsHostRecord.cxx
rutil/dns/DnsCnameRecord.cxx
rutil/dns/DnsAAAARecord.cxx
rutil/dns/AresDns.cxx
rutil/DataStream.cxx
rutil/Data.cxx
rutil/CountStream.cxx
rutil/ConfigParse.cxx
# rutil/Condition.cxx
rutil/Coders.cxx
rutil/BaseException.cxx
rutil/AbstractFifo.cxx
rutil/XMLCursor.cxx
rutil/vmd5.cxx
rutil/TransportType.cxx
rutil/Timer.cxx
rutil/Time.cxx
rutil/ThreadIf.cxx
rutil/SysLogStream.cxx
rutil/SysLogBuf.cxx
rutil/Subsystem.cxx
rutil/stun/Udp.cxx
rutil/stun/Stun.cxx
rutil/Socket.cxx
rutil/ServerProcess.cxx
rutil/SelectInterruptor.cxx
rutil/RWMutex.cxx
rutil/resipfaststreams.cxx
# rutil/RecursiveMutex.cxx
rutil/Random.cxx
rutil/RADIUSDigestAuthenticator.cxx
rutil/PoolBase.cxx
rutil/Poll.cxx
rutil/ParseException.cxx
rutil/ParseBuffer.cxx
# rutil/Mutex.cxx
rutil/MD5Stream.cxx
rutil/Log.cxx
rutil/Lock.cxx
rutil/KeyValueStore.cxx
rutil/HeapInstanceCounter.cxx
rutil/GeneralCongestionManager.cxx
rutil/ssl/OpenSSLDeleter.hxx
rutil/ssl/OpenSSLDeleter.cxx
)
if (CMAKE_SYSTEM MATCHES "Windows*")
set (RUTIL_SOURCES ${RUTIL_SOURCES} rutil/WinCompat.cxx)
endif()
add_library(resiprocate STATIC ${ARES_SOURCES} ${RUTIL_SOURCES} ${STACK_SOURCES} ${DUM_SOURCES})
target_include_directories(resiprocate PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
${DIR_ARES}
${OPENSSL_INCLUDE}
)
set (RESIP_DEFINES -DUSE_SSL -DUSE_IPV6 -DUSE_ARES)
if (TARGET_WIN)
set (RESIP_DEFINES ${RESIP_DEFINES} -DARES_LEGACY_DEFINES)
else()
set (RESIP_DEFINES ${RESIP_DEFINES} -DHAVE_ARPA_NAMESER_H)
endif()
target_compile_definitions(resiprocate PUBLIC ${RESIP_DEFINES})
target_link_libraries (resiprocate PUBLIC ${OPENSSL_SSL} ${OPENSSL_CRYPTO})

View File

@@ -0,0 +1,833 @@
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/build/cmake_modules")
if(POLICY CMP0042)
CMAKE_POLICY(SET CMP0042 NEW)
endif(POLICY CMP0042)
if(POLICY CMP0077)
CMAKE_POLICY(SET CMP0077 NEW)
endif(POLICY CMP0077)
# FIXME - how to include suffix such as 1.13.0~alpha1 ?
# https://cmake.org/cmake/help/latest/variable/PROJECT_VERSION.html
project(resiprocate VERSION 1.13.0)
# Warning: CMAKE_BUILD_TYPE
#
# Using CMAKE_BUILD_TYPE=Debug will create a build without the NDEBUG flag
#
# Any other CMAKE_BUILD_TYPE appears to set NDEBUG sometimes
# Some documentation suggest that CMAKE_BUILD_TYPE=RelWithDebInfo will
# not set the NDEBUG flag but this appears to be inconsistent.
#
# reSIProcate makes extensive use of assert()
# assert() is disabled by NDEBUG
# Application code should not rely on NDEBUG for any purpose, its only
# purpose is for disabling assert()
#
# https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html#variable:CMAKE_BUILD_TYPE
#
# shared library versioning
#set(SO_ABI "0.0.0")
set(SO_RELEASE "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
include(GNUInstallDirs)
include(Utilities)
include(CheckStructHasMember)
enable_testing()
option(ENABLE_LOG_REPOSITORY_DETAILS "Log repository revision and branch" TRUE)
if(ENABLE_LOG_REPOSITORY_DETAILS)
find_package(Git REQUIRED)
execute_process(
COMMAND ${GIT_EXECUTABLE} describe --match="" --always --abbrev=40 --dirty
OUTPUT_VARIABLE RESIPROCATE_GIT_ID
OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(
COMMAND ${GIT_EXECUTABLE} rev-parse --abbrev-ref HEAD
OUTPUT_VARIABLE RESIPROCATE_BRANCH_NAME
OUTPUT_STRIP_TRAILING_WHITESPACE)
endif()
# https://cmake.org/cmake/help/latest/module/FindThreads.html
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
find_package(Threads REQUIRED)
if(NOT Threads_FOUND)
exit()
endif()
if(CMAKE_USE_PTHREADS_INIT)
add_definitions(-D__REENTRANT)
add_definitions(-pthread)
endif()
set(REPRO_BUILD_REV ${PACKAGE_VERSION})
set(REPRO_RELEASE_VERSION ${PACKAGE_VERSION})
set(RESIP_SIP_MSG_MAX_BYTES 10485760)
# https://cmake.org/cmake/help/latest/module/TestBigEndian.html
# see also
# https://cmake.org/cmake/help/latest/variable/CMAKE_LANG_BYTE_ORDER.html
include (TestBigEndian)
test_big_endian(RESIP_BIG_ENDIAN)
CHECK_STRUCT_HAS_MEMBER(sockaddr_in sin_len arpa/inet.h HAVE_sockaddr_in_len)
if(HAVE_sockaddr_in_len)
add_definitions(-DHAVE_sockaddr_in_len)
endif()
# Top-level user-settable variables (with defaults)
# Those can be queried from the command line using "cmake -LH" and can be
# specified on the command line, using cmake-gui or ccmake.
option(WITH_C_ARES "Link against libc-ares (rather than rutil/dns/ares)" FALSE)
option(WITH_SSL "Link against SSL libraries" TRUE)
option(USE_POPT "Link against POPT libraries" FALSE)
option(USE_SIGCOMP "Use OpenSigComp" FALSE)
option(USE_FMT "Link against fmt library" FALSE)
option(VERSIONED_SONAME "Include Major.Minor version in SONAME" TRUE)
option(ENABLE_ANDROID "Enable Android build" FALSE)
option(USE_IPV6 "Enable IPv6" TRUE)
option(USE_DTLS "Enable DTLS" TRUE)
option(PEDANTIC_STACK "Enable pedantic behavior (fully parse all messages)" FALSE)
option(USE_MYSQL "Link against MySQL client libraries" FALSE)
# some systems may have a newer version of libpq that is not
# compatible with the packaged version of soci_postgresql
option(USE_SOCI_POSTGRESQL "Build recon with SOCI PostgreSQL support" FALSE)
# can't have both MariaDB C client and SOCI MySQL at the same
# time in some environments, e.g. CentOS 8.1
option(USE_SOCI_MYSQL "Build recon with SOCI MySQL support" FALSE)
option(USE_POSTGRESQL "Link against PostgreSQL client libraries" FALSE)
option(USE_MAXMIND_GEOIP "Link against MaxMind GeoIP libraries" FALSE)
option(RESIP_HAVE_RADCLI "Link against radcli RADIUS client library" FALSE)
option(USE_NETSNMP "Link against NetSNMP client libraries" FALSE)
option(BUILD_REPRO "Build repro SIP proxy" TRUE)
option(BUILD_DSO_PLUGINS "Build DSO plugins" TRUE)
option(BUILD_RETURN "Build reTurn server" TRUE)
option(BUILD_REND "Build rend" FALSE)
option(BUILD_TFM "Build TFM, requires Netxx and cppunit" FALSE)
option(BUILD_CLICKTOCALL "Build Click to call application" FALSE)
option(BUILD_ICHAT_GW "Build iChat gateway, requires gloox" FALSE)
option(BUILD_TELEPATHY_CM "Build Telepathy connection manager" FALSE)
option(BUILD_RECON "Build reCon Conversation Manager library" FALSE)
option(USE_SRTP1 "Use srtp 1.x instead of current version" FALSE)
option(BUILD_RECONSERVER "Build reConServer" FALSE)
option(USE_SIPXTAPI "Link against sipXtapi" FALSE)
option(USE_KURENTO "Build Kurento client (requires websocketpp)" FALSE)
option(USE_GSTREAMER "Link against Gstreamer" FALSE)
option(USE_LIBWEBRTC "Link against LibWebRTC" FALSE)
option(RECON_LOCAL_HW_TESTS "Attempt to use local audio hardware in unit tests" FALSE)
option(BUILD_P2P "Build P2P, links against S2C and SSL, unfinished" FALSE)
option(BUILD_PYTHON "Build components requiring Python" FALSE)
option(BUILD_QPID_PROTON "Build components requiring qpid-proton (AMQP)" TRUE)
option(RESIP_ASSERT_SYSLOG "Log assertion failures with Syslog" TRUE)
option(REGENERATE_MEDIA_SAMPLES "Regenerate the header files containing raw audio samples (requires sox, xxd)" TRUE)
set(DEFAULT_BRIDGE_MAX_IN_OUTPUTS 20 CACHE STRING "recon: Maximum connections on bridge")
# This must be enabled when building with the Android ndkports tools.
# It should not be enabled for any other case.
option(USE_NDKPORTS_HACKS "Android ndkports build: use hardcoded paths to dependencies" FALSE)
#
# Libtool / autotools is able to build both the static and shared
# version of a library based on a single definition of the library.
#
# CMake is trying to support platforms like Windows that do not
# allow both the static and shared library to share the same target
# name.
#
# Therefore, with our initial CMake implementation, we only support
# one type of build or the other.
#
# People who need both static and shared libraries can run the build
# twice with alternate values of BUILD_SHARED_LIBS
#
# FIXME - can we replicate one of the hacks for building both static
# and shared?
# - it is a good idea to ask the CMake developers and ask the
# packaging system maintainers (debhelper, rpmbuild)
#
# Example hacks:
# https://stackoverflow.com/questions/2152077/is-it-possible-to-get-cmake-to-build-both-a-static-and-shared-library-at-the-sam
# https://github.com/baresip/rem/pull/84/files
#
if(WIN32)
set(BUILD_SHARED_LIBS_DEFAULT OFF)
set(USE_CONTRIB_DEFAULT ON)
set(USE_NUGET ON)
else()
set(BUILD_SHARED_LIBS_DEFAULT ON)
set(USE_CONTRIB_DEFAULT OFF)
set(USE_NUGET OFF)
endif()
option(BUILD_SHARED_LIBS "Build libraries as shared" ${BUILD_SHARED_LIBS_DEFAULT})
option(USE_CONTRIB "Use libraries from contrib folder" ${USE_CONTRIB_DEFAULT})
set(CMAKE_CXX_STANDARD 11)
########################
### Helper functions ###
########################
function(option_def)
if(${ARGV0})
add_definitions(-D${ARGV0})
endif()
endfunction()
function(set_def)
set(${ARGV0} TRUE)
add_definitions(-D${ARGV0})
endfunction()
function(do_fail_win32)
message(FATAL_ERROR "please complete Win32 support for ${ARGV0} in CMakeLists.txt")
endfunction()
# See
# https://cmake.org/cmake/help/latest/prop_tgt/SOVERSION.html
# https://cmake.org/cmake/help/latest/prop_tgt/VERSION.html
function(version_libname)
if(SO_ABI)
set_target_properties(${ARGV0} PROPERTIES SOVERSION ${SO_ABI})
endif()
# This logic tries to replicate the libtool -release X.Y ...
# but it doesn't create the same symlink that libtool creates.
# FIXME
# Other people have complained about the same problem, e.g.
# https://discourse.libsdl.org/t/patches-dynamic-library-name-should-it-be-libsdl2-2-0-so-or-libsdl2-so/19400/8
if(VERSIONED_SONAME)
set_target_properties(${ARGV0} PROPERTIES OUTPUT_NAME ${ARGV0}-${SO_RELEASE})
file(CREATE_LINK lib${ARGV0}-${SO_RELEASE}.so ${CMAKE_CURRENT_BINARY_DIR}/lib${ARGV0}.so RESULT ${ARGV0}-IGNORE SYMBOLIC)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/lib${ARGV0}.so DESTINATION ${CMAKE_INSTALL_LIBDIR})
endif()
endfunction()
if(NOT VERSIONED_SONAME)
set(CMAKE_PLATFORM_NO_VERSIONED_SONAME True)
endif()
################################
### Per-program dependencies ###
################################
set(USE_PCRE FALSE)
set(USE_WEBSOCKETPP FALSE)
if(BUILD_REPRO)
set(USE_BDB TRUE)
set(USE_PCRE TRUE)
set(USE_CAJUN TRUE)
endif()
if(BUILD_RECON)
set(USE_SRTP TRUE)
endif()
if(BUILD_TFM)
set(USE_NETXX TRUE)
set(USE_CPPUNIT TRUE)
endif()
if(BUILD_RETURN)
set(USE_ASIO TRUE)
#set(USE_BOOST TRUE) # Dependency has been replaced by C++11
endif()
if(USE_KURENTO)
set(USE_ASIO TRUE)
set(USE_WEBSOCKETPP TRUE)
endif()
if(BUILD_CLICKTOCALL)
set(USE_PCRE TRUE)
endif()
####################
### Dependencies ###
####################
if(NOT USE_CONTRIB)
find_package(PkgConfig REQUIRED)
endif()
# ares
if(WITH_C_ARES)
# Don't use built-in ares
pkg_check_modules(cares libcares REQUIRED)
set(USE_CARES true)
add_definitions(-DUSE_CARES)
set(ARES_LIBRARIES ${cares_LIBRARIES})
include_directories(${cares_INCLUDE_DIR})
else()
# Use built-in ares
set(USE_ARES true)
add_definitions(-DUSE_ARES)
# Put the resip ares include dir before the system ones to not conflict with
# c-ares if also present.
include_directories(BEFORE rutil/dns/ares)
set(ARES_LIBRARIES resipares)
endif()
if("${CMAKE_EXE_LINKER_FLAGS}" STREQUAL "/machine:x64")
set(WIN_ARCH "x64")
else()
set(WIN_ARCH "Win32")
endif()
# Download NuGet Package Manager and ensure it is in %PATH%
# before running CMake
if(USE_NUGET)
find_program(NUGET_EXE NAMES nuget.exe REQUIRED)
endif()
function(nuget_inst)
exec_program(${NUGET_EXE}
ARGS install "${ARGV1}" -Version ${ARGV2} -ExcludeVersion -OutputDirectory ${CMAKE_BINARY_DIR}/packages
)
set(${ARGV0}_TARGETS ${CMAKE_BINARY_DIR}/packages/${ARGV1}/build/native/${ARGV1}.targets PARENT_SCOPE)
set(PKG_TOP "${CMAKE_BINARY_DIR}/packages/${ARGV1}/build/native")
set(PKG_LIB "${PKG_TOP}/lib/${WIN_ARCH}/Debug") # FIXME
set(${ARGV0}_ROOT_DIR "${PKG_TOP}" PARENT_SCOPE)
# These vary a lot from one package to the next. We
# set them to some common default values but in many
# cases the subsequent code needs to override these
# values with package-specific values.
set(${ARGV0}_INCLUDE_DIRS "${PKG_TOP}/include" PARENT_SCOPE)
set(${ARGV0}_LIBRARIES_DIR "${PKG_LIB}" PARENT_SCOPE)
endfunction()
# OpenSSL
if(WITH_SSL)
if(USE_NUGET)
nuget_inst(OPENSSL "zeroc.openssl.v142" "1.1.1.2")
message("Using ${OPENSSL_ROOT_DIR} and ${OPENSSL_LIBRARIES}")
# this is an argument to FindOpenSSL
# https://cmake.org/cmake/help/latest/module/FindOpenSSL.html
set(OPENSSL_USE_STATIC_LIBS True)
# set(OPENSSL_CRYPTO_LIBRARY "${OPENSSL_LIBRARIES}/libcrypto.lib")
set(OPENSSL_LIBRARIES
"${OPENSSL_LIBRARIES_DIR}/libssl.lib"
"${OPENSSL_LIBRARIES_DIR}/libcrypto.lib")
# FIXME - check if those libraries and headers really exist
set(OPENSSL_FOUND TRUE)
elseif(USE_NDKPORTS_HACKS)
if(NOT ANDROID_ABI)
message(FATAL_ERROR "ndkports hack requested but ANDROID_ABI not set")
endif()
#set(distribution_DIR ${CMAKE_SOURCE_DIR}/../../../../distribution)
#set(OPENSSL_ROOT_DIR ${distribution_DIR}/openssl/${ANDROID_ABI})
set(OPENSSL_ROOT_DIR /src/openssl/build/port/aar/prefab/modules)
set(CRYPTO_LIBRARIES_DIR "${OPENSSL_ROOT_DIR}/crypto/libs/android.${ANDROID_ABI}")
set(SSL_LIBRARIES_DIR "${OPENSSL_ROOT_DIR}/ssl/libs/android.${ANDROID_ABI}")
set(OPENSSL_INCLUDE_DIR ${OPENSSL_ROOT_DIR}/ssl/include)
set(OPENSSL_LIBRARIES
"${SSL_LIBRARIES_DIR}/libssl.so"
"${CRYPTO_LIBRARIES_DIR}/libcrypto.so")
# FIXME - check if those libraries and headers really exist
set(OPENSSL_FOUND TRUE)
else()
# SSL support is requested, so make it mandatory when calling find_package
find_package(OpenSSL REQUIRED) # HINTS ${OPENSSL_LIBRARIES})
endif()
# Oldest OpenSSL API to target (1.1.1)
add_compile_definitions(OPENSSL_API_COMPAT=0x10101000L)
set_def(USE_SSL)
else()
# Explicitly set OPENSSL_FOUND to false since we didn't even run
# find_package on it. It needs to be set to false for other CMake scripts to
# know it is not being used.
set(OPENSSL_FOUND FALSE)
endif()
# popt
# Debian: libpopt-dev
if(USE_POPT)
if(USE_CONTRIB)
add_subdirectory(contrib/popt)
set(POPT_LIBRARIES popt)
set(POPT_INCLUDE_DIRS contrib/popt)
else()
find_package(popt REQUIRED)
endif()
set(HAVE_POPT_H true)
add_definitions(-DHAVE_POPT_H)
endif()
# OpenSigComp
if(USE_SIGCOMP)
if(USE_CONTRIB)
add_subdirectory(contrib/opensigcomp)
set(opensigcomp_LIBRARIES opensigcomp)
else()
find_package(opensigcomp REQUIRED)
endif()
endif()
# fmt
# Debian: libfmt-dev
if(USE_FMT)
if(USE_CONTRIB)
add_subdirectory(contrib/fmt)
else()
find_package(fmt REQUIRED)
endif()
set_def(USE_FMT)
endif()
option_def(USE_IPV6)
option_def(USE_DTLS)
option_def(PEDANTIC_STACK)
# MySQL
# Debian: default-libmysqlclient-dev
if(USE_MYSQL)
if(USE_CONTRIB)
# There is a pre-compiled MySQL client binary in contrib
# so we hardcode the paths to the headers and binary
# artifacts.
#add_subdirectory(contrib/MySQLConnectorC)
set(MySQL_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/contrib/MySQLConnectorC")
set(MySQL_INCLUDE_DIRS "${MySQL_ROOT}/include")
set(MySQL_LIBRARIES "${MySQL_ROOT}/lib/debug/libmysql.lib")
set(MySQL_FOUND TRUE)
else()
find_package(MySQL REQUIRED)
endif()
endif()
# soci (MySQL, PostgreSQL)
# Debian: libsoci-dev
# FIXME - hardcoded
# FIXME - MySQL, PostgreSQL
if(USE_SOCI_POSTGRESQL OR USE_SOCI_MYSQL)
find_library(SOCI_LIBRARIES soci_core REQUIRED)
# FIXME include path
set(SOCI_INCLUDE_DIRS "/usr/include/soci")
option_def(USE_SOCI_POSTGRESQL)
option_def(USE_SOCI_MYSQL)
endif()
# PostgreSQL
# Debian: libpq-dev postgresql-server-dev-all
if(USE_POSTGRESQL)
if(USE_CONTRIB)
add_subdirectory(contrib/psql)
else()
find_package(PostgreSQL REQUIRED)
endif()
endif()
# GeoIP
# Debian: libgeoip-dev
if(USE_MAXMIND_GEOIP)
if(USE_CONTRIB)
# FIXME - update reSIProcate for libmaxminddb - successor to GeoIP
message(FATAL_ERROR "GeoIP has been deprecated upstream, see https://github.com/maxmind/geoip-api-c")
#add_subdirectory(contrib/GeoIP)
else()
find_package(GeoIP REQUIRED)
endif()
endif()
# radcli (RADIUS client)
# Debian: libradcli-dev
# FIXME: do we need to support alternatives like
# freeradius-client and radiusclient-ng?
if(RESIP_HAVE_RADCLI)
if(USE_CONTRIB)
do_fail_win32("radcli")
else()
pkg_check_modules(LIBRADIUS radcli REQUIRED)
endif()
option_def(RESIP_HAVE_RADCLI)
set_def(USE_RADIUS_CLIENT)
endif()
# NetSNMP
# Debian: libsnmp-dev
if(USE_NETSNMP)
if(USE_CONTRIB)
do_fail_win32("netsnmp")
else()
# net-snmp-config --agent-libs
pkg_check_modules(NETSNMP_AGENT netsnmp-agent REQUIRED)
endif()
set_def(USE_NETSNMP)
endif()
option_def(BUILD_REPRO)
set(CMAKE_INSTALL_PKGLIBDIR ${CMAKE_INSTALL_LIBDIR}/${CMAKE_PROJECT_NAME})
set(CMAKE_INSTALL_MIBDIR ${CMAKE_INSTALL_DATAROOTDIR}/snmp/mibs)
if(BUILD_DSO_PLUGINS)
add_definitions(-DDSO_PLUGINS)
set(INSTALL_REPRO_PLUGIN_DIR ${CMAKE_INSTALL_PKGLIBDIR}/repro/plugins)
endif()
set(INSTALL_RETURN_PKGLIB_DIR ${CMAKE_INSTALL_PKGLIBDIR}/reTurnServer)
option_def(BUILD_RETURN)
option_def(BUILD_REND)
option_def(BUILD_TFM)
# BUILD_APPS has been omitted
option_def(BUILD_ICHAT_GW)
# Netxx
# Debian: libnetxx-dev
if(USE_NETXX)
if(USE_CONTRIB)
add_subdirectory(contrib/Netxx-0.3.2)
set(Netxx_LIBRARIES Netxx)
else()
find_package(Netxx REQUIRED)
endif()
endif()
# cppunit
# Debian: libcppunit-dev
if(USE_CPPUNIT)
if(USE_CONTRIB)
add_subdirectory(contrib/cppunit)
set(CPPUNIT_LIBRARIES cppunit)
else()
pkg_check_modules(CPPUNIT cppunit REQUIRED)
endif()
endif()
# BerkeleyDb
# Debian: libdb++-dev
if(USE_BDB)
if(USE_NUGET)
#nuget_inst(BERKELEYDB "BerkeleyDB-4_8_30-Cpp" "4.8.30.2")
#set(BERKELEYDB_LIBRARIES_DIR "${BERKELEYDB_ROOT_DIR}/bin")
#set(BERKELEYDB_LIBRARIES
# "${BERKELEYDB_LIBRARIES_DIR}/lib/${WIN_ARCH}/Debug/libdb48d.lib")
# https://www.nuget.org/packages/berkeley.db.v140
nuget_inst(BERKELEYDB "berkeley.db.v140" "5.3.28.3")
set(BERKELEYDB_LIBRARIES_DIR "${BERKELEYDB_ROOT_DIR}/lib/${WIN_ARCH}/Debug")
set(BERKELEYDB_LIBRARIES
"${BERKELEYDB_LIBRARIES_DIR}/libdb53d.lib")
# FIXME - check if those libraries and headers really exist
set(BERKELEYDB_FOUND TRUE)
elseif(USE_CONTRIB)
add_subdirectory(contrib/db)
else()
find_package(BerkeleyDb REQUIRED)
endif()
set(DB_HEADER "db_cxx.h")
endif()
# PCRE
# Debian: libpcre3-dev
# FIXME - deprecate PCRE in favour of C++11 <regex>
if(USE_PCRE)
if(USE_NUGET)
nuget_inst(PCRE "pcre" "8.33.0.1")
if(BUILD_SHARED_LIBS)
set(WIN_LIB_LINKING "dynamic")
else()
set(WIN_LIB_LINKING "static")
add_definitions(-DPCRE_STATIC)
endif()
set(PCRE_LIBRARIES_DIR "${PCRE_ROOT_DIR}/lib/v110/${WIN_ARCH}/Debug/${WIN_LIB_LINKING}/utf8")
set(PCRE_LIBRARIES
"${PCRE_LIBRARIES_DIR}/pcre8.lib")
# FIXME - check if those libraries and headers really exist
if(NOT EXISTS "${PCRE_LIBRARIES}")
message(FATAL_ERROR "could not find ${PCRE_LIBRARIES}")
endif()
set(PCRE_FOUND TRUE)
elseif(USE_CONTRIB)
add_subdirectory(contrib/pcre)
set(PCRE_LIBRARIES pcre)
else()
pkg_check_modules(PCRE REQUIRED libpcre)
endif()
endif()
# Cajun
# Debian: libcajun-dev
if(USE_CAJUN)
if(USE_CONTRIB)
# FIXME: convert Cajun to CMake build system
# FIXME: include Cajun as a Git submodule or NuGet
#add_subdirectory(contrib/cajun)
set(CAJUN_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/contrib/cajun/include")
else()
find_package(cajun REQUIRED)
endif()
endif()
# ASIO
# Debian: libasio-dev
# modern ASIO requires C++11
if(USE_ASIO)
if(USE_CONTRIB)
# FIXME: include asio as a Git submodule or NuGet
set(ASIO_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/contrib/asio")
else()
find_package(ASIO REQUIRED)
endif()
endif()
# Boost
# Debian: libboost-all-dev
if(USE_BOOST)
if(USE_NUGET)
nuget_inst(BOOST "boost" "1.80.0")
message("Using ${BOOST_ROOT_DIR} and ${BOOST_LIBRARIES}")
set(BOOST_LIBRARIES
"${BOOST_LIBRARIES_DIR}/libboostcore.lib")
# FIXME - check if those libraries and headers really exist
set(BOOST_FOUND TRUE)
else()
find_package(Boost REQUIRED)
endif()
endif()
if(BUILD_TELEPATHY_CM)
option_def(BUILD_TELEPATHY_CM)
set(USE_QT5)
endif()
# Telepathy-Qt
# Debian: libtelepathy-qt5-dev
if(USE_QT5)
# PKG_CHECK_MODULES([QT5], [Qt5Core, Qt5DBus Qt5Network])
# PKG_CHECK_MODULES([TP_QT5], [TelepathyQt5, TelepathyQt5Service])])
find_package(TelepathyQt5 REQUIRED)
endif()
option_def(BUILD_RECON)
# SRTP2
# Debian: libsrtp2-dev
if(USE_SRTP)
if(USE_SRTP1)
find_package(srtp REQUIRED)
else()
# FIXME - not in NuGet, not CMake native
if(USE_CONTRIB)
add_subdirectory("contrib/srtp")
#set(libsrtp2_INCLUDE_DIRS "${libsrtp2_INCLUDE_DIRS}")
#set(libsrtp2_LIBRARIES "${libsrtp2_LIBRARIES}")
# FIXME - these shouldn't be hard-coded, need to fix the above variables
set(SRTP2_INCLUDE_DIRS "${libsrtp2_SOURCE_DIR}/include")
set(SRTP2_LIBRARIES "${libsrtp2_BINARY_DIR}/contrib/srtp/${CMAKE_BUILD_TYPE}/srtp2.lib")
set(SRTP_FOUND TRUE)
else()
find_package(srtp2 REQUIRED)
endif()
endif()
endif()
# sipXtapi
# Debian: libsipxtapi-dev
if(USE_SIPXTAPI)
option_def(USE_SIPXTAPI)
find_package(sipXtapi REQUIRED)
if(NOT WIN32)
set(SIPX_NO_RECORD true)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__pingtel_on_posix__")
endif()
endif()
option_def(USE_KURENTO)
# gstreamermm
# Debian: libgstreamermm-1.0-dev
if(USE_GSTREAMER)
option_def(USE_GSTREAMER)
pkg_check_modules(GSTREAMERMM_1_0 gstreamermm-1.0 REQUIRED)
# gstwebrtc-1.0
# Debian: libgstreamer-plugins-bad1.0-dev
pkg_check_modules(GST_WEBRTC gstreamer-webrtc-1.0 REQUIRED)
endif()
option_def(USE_LIBWEBRTC)
option_def(RECON_LOCAL_HW_TESTS)
# Python
# Debian: python3-dev python3-cxx-dev
if(BUILD_PYTHON)
find_package(Python3 COMPONENTS Development REQUIRED)
pkg_check_modules(PYCXX PyCXX REQUIRED)
if(NOT PYCXX_SRCDIR)
pkg_get_variable(PYCXX_SRCDIR PyCXX srcdir)
if(NOT PYCXX_SRCDIR)
message(FATAL_ERROR "Failed to obtain PyCXX srcdir automatically, please set it manually or disable BUILD_PYTHON")
endif()
endif()
add_definitions(-DPy_LIMITED_API=0x03090000)
endif()
# Apache Qpid Proton
# Debian: libqpid-proton-cpp12-dev
if(BUILD_QPID_PROTON)
if(USE_NUGET)
# FIXME - they only publish the C API, need full C++ API
nuget_inst(QPIDPROTON "Apache.Qpid.Proton" "1.0.0-M6")
message("Using ${QPIDPROTON_ROOT_DIR} and ${QPIDPROTON_LIBRARIES}")
set(QPIDPROTON_LIBRARIES
"${QPIDPROTON_LIBRARIES_DIR}/libqpidproton.lib")
# FIXME - check if those libraries and headers really exist
set(QPIDPROTON_FOUND TRUE)
else()
pkg_check_modules(QPIDPROTON libqpid-proton-cpp REQUIRED)
endif()
option_def(BUILD_QPID_PROTON)
endif()
option_def(RESIP_ASSERT_SYSLOG)
# FIXME
# The AC_SEARCH_LIBS macro from autotools doesn't
# appear to have an equivalent in CMake.
# If we need to link against nsl or socket then it
# needs to be specified manuall on the CMake command line.
# AC_SEARCH_LIBS(gethostbyname, nsl)
# AC_SEARCH_LIBS(socket, socket)
# websocketpp
# Debian: libwebsocketpp-dev
if(USE_WEBSOCKETPP)
if(USE_NUGET)
nuget_inst(WEBSOCKETPP "websocketpp-mtk.repack" "0.7.0-mtk19")
message("Using ${WEBSOCKETPP_ROOT_DIR} and ${WEBSOCKETPP_LIBRARIES}")
set(WEBSOCKETPP_LIBRARIES
"${WEBSOCKETPP_LIBRARIES_DIR}/libwebsocketpp.lib")
# FIXME - check if those libraries and headers really exist
set(WEBSOCKETPP_FOUND TRUE)
else()
find_package(websocketpp REQUIRED)
endif()
endif()
# monotonic clock
include(CheckCSourceRuns)
check_c_source_runs("
#include <time.h>
int main() {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return 0;
}" HAVE_CLOCK_GETTIME_MONOTONIC)
if(HAVE_CLOCK_GETTIME_MONOTONIC)
add_definitions(-DHAVE_CLOCK_GETTIME_MONOTONIC)
endif()
# epoll
include(CheckIncludeFiles)
check_include_files(sys/epoll.h HAVE_EPOLL)
# HAVE_LIBDL from autotools obsolete,
# now we use CMAKE_DL_LIBS to include the library
# when necessary
# gperf
set(GPERF_SIZE_TYPE "size_t")
if(WIN32)
add_definitions(-DNOMINMAX)
endif()
##############################
### Generation of config.h ###
##############################
# TODO - Bring more values from autotools
add_definitions(-DHAVE_CONFIG_H)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
# Used to group targets together when CMake generates projects for IDEs
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
add_subdirectory(rutil)
add_subdirectory(resip)
if(BUILD_REPRO)
add_subdirectory(repro)
endif()
if(BUILD_TFM)
add_subdirectory(tfm)
endif()
add_subdirectory(media)
if(BUILD_RETURN)
add_subdirectory(reTurn)
endif()
if(BUILD_RECON)
add_subdirectory(reflow)
endif()
if(BUILD_P2P)
add_subdirectory(p2p)
endif()
add_subdirectory(apps)
# Create spec file for RPM packaging
# The tarball containing a spec file can be fed directly
# to the rpmbuild command.
configure_file(
resiprocate.spec.in
resiprocate.spec
@ONLY)
# Add 'make dist' command for creating release tarball
set (CPACK_PACKAGE_VERSION ${PROJECT_VERSION})
set (CPACK_SOURCE_GENERATOR "TGZ")
set (CPACK_SOURCE_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}-${CPACK_PACKAGE_VERSION}")
# pax appears to be the default, we need it due to some filenames
#set (COMPRESSION_OPTIONS --format=pax)
list(APPEND CPACK_SOURCE_IGNORE_FILES "/\\\\.git/")
list(APPEND CPACK_SOURCE_IGNORE_FILES "\\\\.gitignore")
list(APPEND CPACK_SOURCE_IGNORE_FILES "/CMakeFiles/")
list(APPEND CPACK_SOURCE_IGNORE_FILES "/_CPack_Packages/")
list(APPEND CPACK_SOURCE_IGNORE_FILES "\\\\.deps/")
list(APPEND CPACK_SOURCE_IGNORE_FILES "\\\\.libs/")
list(APPEND CPACK_SOURCE_IGNORE_FILES "/.*\\\\.gz")
list(APPEND CPACK_SOURCE_IGNORE_FILES "/.*\\\\.zip")
list(APPEND CPACK_SOURCE_IGNORE_FILES ".*\\\\.o")
list(APPEND CPACK_SOURCE_IGNORE_FILES "lib.*\\\\.so*")
list(APPEND CPACK_SOURCE_IGNORE_FILES "/CMakeCache.txt")
list(APPEND CPACK_SOURCE_IGNORE_FILES "/contrib/")
list(APPEND CPACK_SOURCE_IGNORE_FILES "/debian/")
list(APPEND CPACK_SOURCE_IGNORE_FILES "Makefile")
list(APPEND CPACK_SOURCE_IGNORE_FILES "/config.h$")
include (CPack)
add_custom_target (dist COMMAND ${CMAKE_MAKE_PROGRAM} package_source)
###############
### Summary ###
###############
include(FeatureSummary)
feature_summary(WHAT ALL)

View File

@@ -0,0 +1,54 @@
License note:
- each source file has a license enclosed, usually in comments at
the end of the file
- individual authors have not always used an identical license
block in their code, yet all the license blocks are for most
purposes equivalent and compatible with the standard 3 clause
BSD license
- the bulk of the code is licensed under the terms of the Vovida
license, which is like the BSD license with a 4th clause
added restricting the use of the term VOCAL in the name
of any derivative work. A full copy of the Vovida license
is presented below.
The Vovida Software License, Version 1.0
Copyright (c) 2000-2008 Vovida Networks, Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
3. The names "VOCAL", "Vovida Open Communication Application Library",
and "Vovida Open Communication Application Library (VOCAL)" must
not be used to endorse or promote products derived from this
software without prior written permission. For written
permission, please contact vocal@vovida.org.
4. Products derived from this software may not be called "VOCAL", nor
may "VOCAL" appear in their name, without prior written
permission of Vovida Networks, Inc.
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.

View File

@@ -0,0 +1,79 @@
a) If using source code from the repository (not a tarball download),
you must bootstrap the source tree:
autoreconf --install
This must be done:
- after checking out the code for the first time
- after changing configure.ac or any Makefile.am file
NOTE: the bootstrap process only works reliably when using the same
(or a very similar) version of autotools as the officially
tested reSIProcate releases. The official releases are
bootstrapped using autotools on a Debian 6.0 (squeeze) system.
b) Run configure:
e.g. on a Debian system:
./configure --with-ssl --with-mysql --with-c-ares \
CXXFLAGS="-DRESIP_FIXED_POINT"
NOTE: some things (e.g. reTurnServer) will ONLY build if you
specify --with-ssl to link against SSL libraries
A more complete example, with tfm:
./configure \
--with-ssl --with-mysql --with-radius --with-tfm \
--enable-ipv6 \
CXXFLAGS="-I`pwd`/contrib/Netxx-0.3.2/include" \
LDFLAGS="-L`pwd`/contrib/Netxx-0.3.2/src"
(hint: if it fails to link against libNetxx.so, create a symlink, or
delete libNetxx.so and it should link against libNetxx.a)
OR (using contrib/ares)
./configure --with-ssl --with-mysql --enable-ipv6 --with-popt"
c) Build everything:
make
or to build just one thing:
make -C rutil
and if you have multiple CPUs/CPU-cores/hyper-threading, you can build
faster by telling make to use them in parallel, e.g.:
make -j 12
d) Test it, e.g. to test rutil:
make -C rutil check
e) Install somewhere:
mkdir /tmp/my-resip && make DESTDIR=/tmp/my-resip install
Supported Systems
-----------------
Supported Platforms: (to add new platform support see build/Makefile.osarch)
FreeBSD
Linux
QNX
SunOS
Mac
cygwin
Supported toolchains: (to add new toolchain support see build/Makefile.tools)
gnu (g++)
Intel (icc)
ARM cross-compiler (arm-linux-g++)
Sunpro (CC)

111
src/libs/resiprocate/README Normal file
View File

@@ -0,0 +1,111 @@
-----------------------------------------------------------
IMPORTANT
- the notes below relate to the legacy build
system from reSIProcate <= 1.7.x
- now, with reSIProcate 1.8.x and beyond,
please see:
http://www.resiprocate.org/AutotoolsBuild
and
http://www.resiprocate.org/Configuration_Options
-----------------------------------------------------------
Notes for the legacy build system:
The legacy reSIProcate build system is derived from
the VOCAL build system (http://www.vovida.org).
Adding New Files to a module
----------------------------
Example: Adding a new file Foo.cxx to the stack
1) Edit resip/stack/Makefile
2) Add Foo.cxx to the SRC list
Example: Adding a new file Bar.cxx to rutil
1) Edit rutil/Makefile
2) Add Bar.cxx to the SRC list
Notes:
- All files noted in SRC list will be added to the target library
- Adding a new header file does not need to be noted in the Makefile
- To add something to the compile line add to CXXFLAGS.
e.g. CXXFLAGS += -DMYSPECIALDEFINE
- To add something to the link line add to LDFLAGS and/or LDLIBS
e.g. LDFLAGS += -L/usr/local/myspeciallibdir
e.g. LDLIBS += -lmyspeciallib
Creating an application based on the stack:
Option 1: (Using the resip build system)
For example applications using the resip build system look at resip/stack/test or at repro.
###########################################################################################
# Create a Makefile in the directory with the units with the following template
# This should be the path to the build directory of resip (in the sip subdirectory)
BUILD = ../../build
# Includes macros
include $(BUILD)/Makefile.pre
# Add any options that need to be passed to the C++ compiler here
#CXXFLAGS += -DMYSPECIALDEFINE
# Add any options that need to be passed to the C compiler here
#CFLAGS += -DMYOTHERDEFINE
# Add any options that need to be passed to the linker here
#LDFLAGS += -L/usr/local/mydir
# Add any libraries that need to be passed to the linker here
#LDLIBS += -lmylib
# All of these packages are prerequisites for resiprocate
PACKAGES += RESIP RUTIL OPENSSL ARES PTHREAD
# Add an entry to TESTPROGRAMS for each target that has a main in it
# On linux this will generate an executable in bin.debug.Linux.i686/main
TESTPROGRAMS += main.cxx
# Add each of the C++ or C files that other than the main
# Each main target (from TESTPROGRAMS) will be linked with all of the files in SRC
SRC = TestSupport.cxx
# Includes macros
include $(BUILD)/Makefile.post
###########################################################################################
Option 2: (Using a third party build system)
Prerequisites:
- Install ares library from contrib/ares
- cd contrib/ares
- ./configure
- make
- make install
Pass the following flags to C++ compiler:
Assumptions:
- have pthreads
- have openssl installed
- have ares installed
- resiprocate library is built and installed
# Linux Example
CXXFLAGS += -Wall -fPIC -Wno-deprecated -march=i686 \
-D_REENTRANT -DUSE_SSL -DNEW_MSG_HEADER_SCANNER -DUSE_IPV6 -DUSE_ARES \
-I/usr/kerberos/include -I$(RESIP_DIR)/lib.debug.Linux.i686
LDFLAGS += -L$(RESIP_DIR)/lib.debug.Linux.i686
LDLIBS += -lresip -lrutil -lssl -lcrypto -lares -lpthread

View File

@@ -0,0 +1,54 @@
CMake Instructions
==================
This is currently an experiement to see how CMake could be used to build
reSIProcate.
Currently, only the core of rutil and its unit tests are built. This is a proof
of concept...
This was quickly tested on Mac OS, Linux (CentOS) and Windows 7...
To build an _out of tree_ build:
$ mkdir cmake_build # Or any other name
$ cd cmake_build
$ cmake ..
$ make
Once this is built, you can run the unit tests with:
$ ctest
or, for verbose output:
$ ctest -V
If you want to start fresh either delete the out of tree build directory or
delete the CMakeCache.txt file.
Configuration Flags
===================
* This is not fully implemented on all flags yet *
CMake "cached" variables are used to specify options such as whether c-ares
should be used or not. You can get the list and tweak them with:
$ cmake -i ..
You can also set them on the command line like:
$ cmake -DWITH_C_ARES=true ..
Future Considerations
=====================
Installation Packages
---------------------
CMake supports rpm/deb?/NSIS to build installable packages using CPack. If this
built-in support can not be used we could always specify internal build targets
that will run external commands to package the appropriate bundle depending on
the platform.

View File

@@ -0,0 +1,96 @@
We have started introducing support for AMQP messaging.
AMQP allows us to send notifications about events to other
applications on topics and to receive notifications and commands
over queues.
Maintainer
----------
Daniel Pocock
daniel@pocock.pro
https://softwarefreedom.institute
Dependencies
------------
Apache Qpid Proton C++
Version tested: 0.22.0
License: Apache 2.0
Apache Qpid Proton Python (optional, for testing)
Version tested: 0.22.0
RabbitMQ (optional, can use other brokers too)
Version tested: 3.8.9
Installing dependencies and compiling reSIProcate with Qpid Proton
------------------------------------------------------------------
Debian / Ubuntu:
sudo apt install \
libqpid-proton11-dev \
libqpid-proton-cpp11-dev
./configure ... --with-qpid-proton ...
RPM:
sudo dnf install qpid-proton-cpp-devel
./configure ... --with-qpid-proton ...
Installing and configuring RabbitMQ
-----------------------------------
Debian / Ubuntu:
sudo apt install rabbitmq-server
sudo rabbitmq-plugins enable rabbitmq_amqp1_0
sudo systemctl restart rabbitmq-server
RPM:
sudo dnf install rabbitmq-server
sudo rabbitmq-plugins enable rabbitmq_amqp1_0
sudo systemctl restart rabbitmq-server
Installing and using the Python command line utilities
------------------------------------------------------
Debian / Ubuntu:
sudo apt install python3-qpid-proton
RPM:
sudo dnf install python-qpid
Example sending a JSON command to reConServer:
Uncomment the BrokerURL in reConServer.config or any of the other
reSIProcate applications, repro.config, registrationAgent.config, ...
BrokerURL = amqp://localhost:5672//queue/sip.reconserver.cmd
(re)start the reConServer
Send the command:
./tools/send-cmd.py \
-a localhost:5672/sip.reconserver.cmd \
-m '{"command":"inviteToRoom","arguments":{"destination":"sip:cisco@10.1.2.3?transport=tcp","room":"room1"}}'
Example receiving messages from the reConServer queue or topic:
Uncomment the EventTopicURL in reConServer.config or any of the other
reSIProcate applications, repro.config, registrationAgent.config, ...
EventTopicURL = amqp://localhost:5672//queue/sip.reconserver.events
(re)start the reConServer
Run the utility in the console, messages appear on stdout:
./tools/monitor-amqp-queue-topic.py \
-a localhost:5672//queue/sip.reconserver.events

View File

@@ -0,0 +1,77 @@
About
-----
Android is a Linux-like operating system. It uses the Linux kernel
and the bionic C library rather than the more common glibc.
Android comes with an SDK for Java, the primary language used in
app development and a Native Development Kit (NDK) for low-level
languages such as C++.
History
-------
Android support was first added to the stack in 2013 by Daniel Pocock
The Android build was updated in 2021 for API level 21 with
support from Mobile Insight.
SDK and NDK evolution
---------------------
The original SDK was based on the Eclipse IDE. Since 2014, the SDK
is Android Studio, based on JetBrains' IntelliJ.
In the early days of the NDK, developers figured out how to integrate
their build systems with the NDK toolchains manually using scripts.
This was the approach used in the original reSIProcate Android effort.
Specifically, the build/android-custom-ndk script was created as a
wrapper around autotools. More recently, Google has included this
strategy in their documentation:
https://developer.android.com/ndk/guides/other_build_systems#autoconf
In 2016, Android Studio 2.2 introduced support for CMake with the NDK.
Using CMake is not mandatory. The SDK/NDK bundles a specific version
of CMake and if reSIProcate changes to CMake, it will be helpful
to ensure the versions are compatible.
https://android-developers.googleblog.com/2016/11/make-and-ndk-build-support-in-android.html
The original NDK was using the GCC toolchain for cross-compiling.
In around 2016, GCC was deprecated in favor of the CLang toolchain.
The list of CPU architectures supported by Android has evolved over time:
https://developer.android.com/ndk/guides/abis
Building for Android
--------------------
On a Linux host, install the SDK and NDK using the usual procedure.
Clone the reSIProcate project.
The first time you build reSIProcate, you will also need to
download and build OpenSSL for Android. Simply add the environment
variable BUILD_OPENSSL=1 to the front of your command line.
It is necessary to set the NDK_HOME environment variable through
the command line or your shell profile.
Here is an example:
BUILD_OPENSSL=1 \
NDK_HOME=${HOME}/Android/Sdk/ndk/23.1.7779620 \
build/android-custom-ndk
The binaries from both OpenSSL and reSIProcate are placed
in the directory ${HOME}/ndk-prebuilt
When you configure the logger in your code, we recommended you
enable the AndroidLogger from rutil/AndroidLogger.hxx
and then all the reSIProcate log output will be passed through
the Android logging system.
See the android-demo-message application for an example showing
how to integrate the libraries into your own app.
https://github.com/resiprocate/android-demo-message

View File

@@ -0,0 +1,251 @@
We try to make packages for users of Fedora, RHEL, CentOS, Rocky Linux,
derivatives and similar systems that use the RPM packaging system.
To support this effort, we also try to ensure all dependencies are
available in Fedora, EPEL or a reliable third-party repository.
This document will help you if you wish to do one of these things:
a) building the source code in a local workspace for development, OR
b) building the RPMs yourself, the same way that we build official RPMs
To get started, download your preferred distribution
----------------------------------------------------
Download the installation ISO, Fedora:
Fedora: https://getfedora.org/
Or a RHEL-compatible derivative like the old CentOS:
Rocky Linux: https://rockylinux.org/download
AlmaLinux: https://almalinux.org/
Install using default options.
Ensure you have sudo permissions
--------------------------------
On RHEL and similar hosts, login as root on the console
and run this command with your username:
usermod -aG wheel your-user-name
Logout and login again to verify you are in the correct group:
$ id
The output of the id command should include the wheel group.
RHEL, CentOS, Rocky Linux: enable repositories
----------------------------------------------
In Fedora, all the necessary packages and repositories are available.
Fedora users can skip this step. Users of RHEL and derivaties need
to manually enable some repositories before you can install
dependencies.
Enable powertools (for common *-devel packages)
sudo dnf -y install dnf-plugins-core
sudo dnf config-manager --set-enabled powertools
Enable EPEL
sudo dnf install epel-release
Setup the rpmbuild tool, configuration and directory structure
--------------------------------------------------------------
Based on the notes here:
https://wiki.centos.org/HowTos/SetupRpmBuildEnvironment
Install the rpmbuild tool and some related packages:
sudo dnf install rpm-build
sudo dnf install redhat-rpm-config
sudo dnf install rpmdevtools
In your home directory, run the following command to create
the RPM directory structure:
rpmdev-setuptree
Now you can verify the tree and config has been created correctly:
find ~/rpmbuild -type d
cat ~/.rpmmacros
Install reSIProcate build environment dependencies
--------------------------------------------------
sudo dnf install git \
gcc-c++ \
cmake \
python3-devel python3-pycxx-devel \
libdb-cxx libdb-cxx-devel \
cppunit cppunit-devel \
gperf \
radcli-devel \
c-ares-devel \
libsrtp-devel \
boost-devel \
openssl-devel \
mariadb-connector-c-devel \
pcre-devel \
popt-devel \
postgresql-devel \
xerces-c-devel \
net-snmp-devel \
qpid-proton-cpp-devel \
soci-devel soci-postgresql-devel soci-mysql-devel \
vim-common \
sox \
fmt-devel \
websocketpp-devel \
gstreamer1-devel \
gstreamer1-plugins-base-devel \
gstreamer1-plugins-bad-free-devel \
gstreamermm-devel
Manually create some dependencies
---------------------------------
Some dependencies are not available in EPEL right now. It is
necessary to copy them from Fedora and build them locally. You
can check the availability of some common dependencies by
looking in the Fedora package catalog:
https://src.fedoraproject.org/rpms/asio
https://src.fedoraproject.org/rpms/cajun-jsonapi
Try to install them with dnf, if the command fails, you need to
add an extra repository or build them manually:
sudo dnf install asio-devel
sudo dnf install cajun-jsonapi-devel
Here is an example to build asio-devel from source, use exactly the
same sequence of commands for cajun-jsonapi-devel or any other
missing dependency. Notice the repository name is not exactly the
same as the package name.
mkdir -p ~/ws/fedora-rpms
cd ~/ws/fedora-rpms
git clone https://src.fedoraproject.org/rpms/asio.git
cd asio
spectool -g -R asio.spec
rpmbuild -bb asio.spec
(it will complain about missing dependencies, so we install them ...)
sudo dnf install boost-devel openssl-devel perl-generators
rpmbuild -bb asio.spec
Now you can install the asio-devel package, the exact filename may
vary depending on the version you built and your CPU architecture:
sudo rpm -i ~/rpmbuild/RPMS/x86_64/asio-devel-1.16.1-3.el8.x86_64.rpm
You may need to repeat this procedure for the cajun-jsonapi package.
Install Docker (for Podman, alternative to Docker, see below)
-------------------------------------------------------------
If you are planning to use one of the related products that is
distributed as a Docker image then you need to install either Docker
or Podman. Typical Docker images include the HOMER system for
SIP message capture and the Kurento Media Server.
These are the steps to install Docker:
sudo dnf config-manager --add-repo=https://download.docker.com/linux/centos/docker-ce.repo
sudo dnf install docker-ce
systemctl is-active docker
sudo systemctl enable --now docker
systemctl is-active docker
systemctl is-enabled docker
sudo usermod -aG docker $USER
and these are the steps to install Podman:
sudo dnf install podman
If you like, you can create an alias for the docker command to run
Podman, save this in ~/.profile or a similar location:
alias docker=podman
Preparing to build the reSIProcate stack
----------------------------------------
You can clone the reSIProcate Git repository or download a copy
of the reSIProcate tarball release. Here are the steps to clone
the repository:
mkdir -p ~/ws
cd ~/ws
git clone https://github.com/resiprocate/resiprocate
cd resiprocate
Configuring the source tree
---------------------------
The project is currently built using CMake. We provide a
wrapper script for CMake on each major GNU/Linux distribution.
The wrapper script for Fedora and RHEL-based systems is:
build/fedora.sh
Run the script from the top level of the reSIProcate tree.
We recommend that you look inside the script and tweak any settings
you require. For example, if you are building on RHEL8 or an older
system, you need to add the configure switch:
--with-srtp1
Compiling the code in the source tree
-------------------------------------
After running the CMake configure command or using the wrapper
script described above, it is possible to start compiling the code.
To compile with 65 threads, on a system with 64 CPU cores, you could
use the following command:
make -j65
Running the unit tests
----------------------
The CMake "make test" target is used.
make test
Running the binaries or unit tests in the GDB debugger
------------------------------------------------------
Here is an example:
gdb --args \
apps/reConServer/reConServer \
apps/reConServer/reConServer.config
Building reSIProcate RPM packages
---------------------------------
To build packages, it is necessary to configure the tree:
build/fedora.sh
Create a reSIProcate release tarball:
make dist
Finally, tell rpmbuild to compile the tarball to RPMs. rpmbuild
uses the spec file resiprocate.spec inside the tarball:
rpmbuild -tb resiprocate-1.13.0.tar.gz

View File

@@ -0,0 +1,106 @@
reSIProcate release process
===========================
This document explains the process for building a release of the
reSIProcate software.
Deliverables
------------
The only official deliverable is the tarball, for example,
resiprocate-1.8.0.tar.gz
As a courtesy to users, a contrib tarball is also produced,
containing some third party code:
resiprocate-contrib-1.8.0.tar.gz
Building of binary packages (e.g. for Debian, RPM, OpenCSW) is
done after the tarball release. That is not covered here.
Workspace
---------
Obtain a release branch from the Git repository.
git clone -b release/1.8 https://github.com/resiprocate/resiprocate resip-1.8
cd resip-1.8
If this is the beginning of a release branch, manually copy the ChangeLog
file from the previous release branch and then add the new entries.
Version/tag
-----------
Here we give an example for building the release v1.8.5:
Update version information and tag it:
vi configure.ac (update the version and ABIVERSION numbers)
git add configure.ac
git commit -m 'release: Update for 1.8.5'
git tag -s -m 'release: Tag 1.8.5' resiprocate-1.8.5
git push (send changes back to Git)
Bootstrap
---------
The bootstrap must always be done on the same version of CMake
for consistency. The currently endorsed version is the CMake
distributed in Debian 11.0 (bullseye). If another version is to be used,
it should be discussed on the mailing list and noted in this document.
cmake .
Make a tarball
--------------
build/release-tarball.sh
* this script will call cmake . && make dist
* it uses a temporary clone from the current working directory
to avoid picking up files that are not committed
Make the contrib tarball
------------------------
build/contrib-tarball.sh
Sanity check on tarball
-----------------------
Extract the tarball to /tmp/some-folder/resiprocate-1.8.5
cd /tmp/some-folder/resiprocate-1.8.5
./build/debian.sh && make -j 70 check
Distribute the tarball
----------------------
sha256sum resiprocate-1.8.5.tar.gz
Upload the tarball to the pre-release section of the web site
cadaver https://www.resiprocate.org/files/pub/reSIProcate/releases/
mput resiprocate-1.8.5.tar.gz resiprocate-1.8.5.zip resiprocate-contrib-1.8.5.tar.gz resiprocate-contrib-1.8.5.zip
Send a PGP signed email to the developers list announcing that
a release candidate has been built. Other developers may test the tarball.
Include the SHA-256 checksum of each file in the PGP signed email.
Confirm the release
-------------------
Upload the tarball to the official download page
Send a PGP signed email to the resip-announce and users lists
announcing that the release candidate is now an official release.
Include the SHA-256 checksum in the PGP signed email.

6
src/libs/resiprocate/apps/.gitignore vendored Normal file
View File

@@ -0,0 +1,6 @@
/Makefile.in
/Makefile
/.deps
/.libs

View File

@@ -0,0 +1,23 @@
if(BUILD_CLICKTOCALL)
add_subdirectory(clicktocall)
endif()
if(WITH_SSL)
add_subdirectory(sipdial)
endif()
if(BUILD_ICHAT_GW)
add_subdirectory(ichat-gw)
endif()
if(BUILD_TELEPATHY_CM)
add_subdirectory(telepathy)
endif()
if(BUILD_RECONSERVER)
add_subdirectory(reConServer)
endif()
if(NETSNMP_AGENT_FOUND)
add_subdirectory(registration-agent)
endif()
if(USE_GSTREAMER)
add_subdirectory(echoTest)
endif()

View File

@@ -0,0 +1,8 @@
/Makefile.in
/Makefile
/.deps
/.libs
/clicktocall

View File

@@ -0,0 +1,214 @@
#include "rutil/Logger.hxx"
#include "rutil/ParseBuffer.hxx"
#include "AppSubsystem.hxx"
#include "AddressTranslator.hxx"
#include "rutil/WinLeakCheck.hxx"
#define RESIPROCATE_SUBSYSTEM AppSubsystem::CLICKTOCALL
using namespace clicktocall;
using namespace resip;
using namespace std;
namespace clicktocall
{
AddressTranslator::AddressTranslator()
{
}
AddressTranslator::~AddressTranslator()
{
// Destroy all of the filters
for(FilterOpList::iterator it = mFilterOperators.begin(); it != mFilterOperators.end(); it++)
{
if ( it->preq )
{
delete it->preq;
it->preq = 0;
}
}
mFilterOperators.clear();
}
void
AddressTranslator::addTranslation(const resip::Data& matchingPattern,
const resip::Data& rewriteExpression)
{
InfoLog( << "Add translation " << matchingPattern << " -> " << rewriteExpression);
FilterOp filter;
filter.mMatchingPattern = matchingPattern;
filter.mRewriteExpression = rewriteExpression;
if( !filter.mMatchingPattern.empty() )
{
// Note: this code originally used the PCRE (Perl Compatible) regular expression library. The ECMAScript standard is a subset
// of the Perl regular expression syntax. Posix regular expression syntax is quite a bit different (ie: std::regex_contacts::basic or
// std::regex_contacts::extended). To be as backwards compatible with existing regular expressions as possible, we want to
// use the EMCAScript syntax.
const std::regex_constants::syntax_option_type flags = std::regex_constants::ECMAScript;
if( filter.mRewriteExpression.find("$") == Data::npos )
{
flags |= std::regex_constants::nosubs;
}
try
{
filter.preq = new std::regex(filter.mMatchingPattern.c_str(), flags );
}
catch (std::regex_error& e)
{
delete filter.preq;
ErrLog( << "Translation has invalid match expression: "
<< filter.mMatchingPattern );
filter.preq = 0;
}
}
mFilterOperators.push_back( filter );
}
void
AddressTranslator::removeTranslation(const resip::Data& matchingPattern )
{
FilterOpList::iterator it = mFilterOperators.begin();
while ( it != mFilterOperators.end() )
{
if ( it->mMatchingPattern == matchingPattern )
{
FilterOpList::iterator i = it;
it++;
if ( i->preq )
{
delete i->preq;
i->preq = 0;
}
mFilterOperators.erase(i);
}
else
{
it++;
}
}
}
bool
AddressTranslator::translate(const resip::Data& address, resip::Data& translation, bool failIfNoRule)
{
bool rc=false;
DebugLog( << "Translating "<< address);
for (FilterOpList::iterator it = mFilterOperators.begin();
it != mFilterOperators.end(); it++)
{
Data rewrite = it->mRewriteExpression;
Data& match = it->mMatchingPattern;
if ( it->preq )
{
std::cmatch matches;
// Note: Using regex_search instead of regex_match, so that we don't need to fully match
// the string, this is backwards compatible with the previous regexec PCRE implementation
if(!std::regex_search(address.c_str(), matches, *it->preq))
{
// did not match
DebugLog( << " Skipped translation "<< address << " did not match " << match );
continue;
}
DebugLog( << " Matched translation "<< address << " matched " << match );
translation = rewrite;
rc=true;
if ( rewrite.find("$") != Data::npos )
{
for ( int i=1; i<matches.size(); i++)
{
Data subExp(matches[i]);
DebugLog( << " subExpression[" <<i <<"]="<< subExp );
Data result;
{
DataStream s(result);
ParseBuffer pb(translation);
while (true)
{
const char* a = pb.position();
pb.skipToChars( Data("$") + char('0'+i) );
if ( pb.eof() )
{
s << pb.data(a);
break;
}
else
{
s << pb.data(a);
pb.skipN(2);
s << subExp;
}
}
s.flush();
}
translation = result;
}
}
else
{
translation = rewrite;
rc = true;
}
break;
}
}
// If we didn't find a translation and we are not suppossed to fail, then just return address
if(!rc && !failIfNoRule)
{
rc = true;
translation = address;
}
InfoLog( << "Translated "<< address << " to " << translation);
return rc;
}
}
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

View File

@@ -0,0 +1,75 @@
#if !defined(AddressTranslator_hxx)
#define AddressTranslator_hxx
#include <list>
#include <regex>
#include "rutil/Data.hxx"
namespace clicktocall
{
class AddressTranslator
{
public:
AddressTranslator();
~AddressTranslator();
void addTranslation(const resip::Data& matchingPattern,
const resip::Data& rewriteExpression);
void removeTranslation(const resip::Data& matchingPattern);
bool translate(const resip::Data& address, resip::Data& translation, bool failIfNoRule=false);
private:
class FilterOp
{
public:
resip::Data mMatchingPattern;
resip::Data mRewriteExpression;
std::regex *preq;
};
typedef std::list<FilterOp> FilterOpList;
FilterOpList mFilterOperators;
};
}
#endif
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

View File

@@ -0,0 +1,38 @@
#include "AppSubsystem.hxx"
AppSubsystem AppSubsystem::CLICKTOCALL("CLICKTOCALL");
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

View File

@@ -0,0 +1,61 @@
#if !defined(AppSubsystem_hxx)
#define AppSubsystem_hxx
#include <iostream>
#include <rutil/Subsystem.hxx>
/**
This class is used in the logging subsystem to identify
logging messages generated from the ClickToCall server.
Author: Scott Godin (sgodin AT SipSpectrum DOT com)
*/
class AppSubsystem : public resip::Subsystem
{
public:
// Add new systems below
static AppSubsystem CLICKTOCALL;
private:
explicit AppSubsystem(const char* rhs) : resip::Subsystem(rhs) {};
explicit AppSubsystem(const resip::Data& rhs);
AppSubsystem& operator=(const resip::Data& rhs);
};
#endif
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

View File

@@ -0,0 +1,995 @@
#include "B2BSession.hxx"
#include "Server.hxx"
#include "AppSubsystem.hxx"
#include <resip/stack/PlainContents.hxx>
#include <resip/stack/SdpContents.hxx>
#include <resip/stack/SipFrag.hxx>
#include <resip/dum/ServerInviteSession.hxx>
#include <resip/dum/ClientInviteSession.hxx>
#include <resip/dum/ClientSubscription.hxx>
#include <rutil/DnsUtil.hxx>
#include <rutil/Log.hxx>
#include <rutil/Logger.hxx>
#include <rutil/WinLeakCheck.hxx>
using namespace clicktocall;
using namespace resip;
using namespace std;
#define RESIPROCATE_SUBSYSTEM AppSubsystem::CLICKTOCALL
#ifdef BRIEF_MSG_LOGGING
#define LOG_MSG msg.brief()
#define LOG_MSG_WITH_SDP msg.brief() << ", sdp=" << sdp
#define LOG_MSGP msg->brief()
#else
#define LOG_MSG endl << msg
#define LOG_MSG_WITH_SDP endl << msg
#define LOG_MSGP endl << *msg
#endif
#define B2BLOG_PREFIX << "B2BSession[" << mHandle << "] "
namespace clicktocall
{
B2BSession::B2BSession(Server& server) :
AppDialogSet(server.getDialogUsageManager()),
mServer(server),
mDum(server.getDialogUsageManager()),
mPeer(0),
mUACConnectedDialogId(Data::Empty, Data::Empty, Data::Empty),
mWaitingOfferFromPeer(false),
mWaitingAnswerFromPeer(false),
mWaitingNitAnswerFromPeer(false),
mClickToCallState(Undefined),
mClickToCallAnchorEnabled(false),
mClickToCallInitiator(false)
{
mHandle = mServer.registerB2BSession(this);
}
B2BSession::~B2BSession()
{
endPeer();
mServer.unregisterB2BSession(mHandle);
}
void
B2BSession::setPeer(B2BSession* peer)
{
mPeer = peer;
}
B2BSession*
B2BSession::getPeer()
{
return mPeer;
}
void
B2BSession::stealPeer(B2BSession* victimSession)
{
// Assume Peer mapping of victim - and copy some settings
setPeer(victimSession->getPeer());
if(mPeer)
{
mPeer->setPeer(this);
}
// Clear peer mapping in victim session
victimSession->setPeer(0);
}
void
B2BSession::startCall(const Uri& destinationUri, const NameAddr& from, const SdpContents *sdp)
{
// Create a UserProfile for new call
auto userProfile = std::make_shared<UserProfile>(mServer.getMasterProfile());
// Set the From address
userProfile->setDefaultFrom(from);
userProfile->getDefaultFrom().remove(p_tag); // Remove tag (if it exists)
// Create the invite message
auto invitemsg = mDum.makeInviteSession(
NameAddr(destinationUri),
userProfile,
sdp,
this);
// Send the invite message
mDum.send(std::move(invitemsg));
}
void
B2BSession::clickToCall(const resip::Uri& initiator, const resip::Uri& destination, bool anchorCall, const XmlRpcInfo& xmlRpcInfo)
{
resip_assert(mClickToCallState == Undefined);
// Store Click-To-Call request info
mClickToCallInitiator = true;
mClickToCallDestination = destination;
mClickToCallAnchorEnabled = anchorCall;
mXmlRpcInfo = xmlRpcInfo;
transitionClickToCallState(Setup);
// Create local sdp offer
SdpContents sdp;
if(!buildLocalOffer(sdp))
{
ErrLog(<< "B2BSession::clickToCall: unable to build local offer.");
return;
}
NameAddr from = mServer.getMasterProfile()->getDefaultFrom();
from.displayName() = "Click-To-Call: " + destination.user();
startCall(initiator, from, &sdp);
}
void
B2BSession::startClickToCallAnchorLeg(const NameAddr& initiator, const Uri& destination, const XmlRpcInfo& xmlRpcInfo)
{
// Create B2BCall
InfoLog(B2BLOG_PREFIX << "B2BSession::startClickToCallAnchorLeg: Starting second leg of click to call to " << destination);
mXmlRpcInfo = xmlRpcInfo;
transitionClickToCallState(Setup);
startCall(destination, initiator, 0);
}
bool
B2BSession::buildLocalOffer(SdpContents& offer)
{
// Build s=, o=, t=, and c= lines
uint64_t currentTime = Timer::getTimeMicroSec();
unsigned int port=8000; // Placeholder port
// Note: The outbound decorator will take care of filling in the correct IP address before the message is sent
// to the wire.
SdpContents::Session::Origin origin("clicktocall", currentTime /* sessionId */, currentTime /* version */, SdpContents::IP4, "0.0.0.0"); // o=
SdpContents::Session session(0, origin, "-" /* s= */);
session.connection() = SdpContents::Session::Connection(SdpContents::IP4, "0.0.0.0"); // c=
session.addTime(SdpContents::Session::Time(0, 0));
// Build Codecs and media offering
SdpContents::Session::Medium medium("audio", port, 1, "RTP/AVP");
SdpContents::Session::Codec g711ucodec("PCMU", 8000);
g711ucodec.payloadType() = 0; /* RFC3551 */ ;
medium.addCodec(g711ucodec);
medium.addAttribute("inactive");
session.addMedium(medium);
offer.session() = session;
return true;
}
void
B2BSession::endPeer()
{
if(mPeer)
{
mPeer->setPeer(0);
mPeer->end(); // send cancel or bye appropriately
mPeer = 0;
}
}
bool
B2BSession::isUACConnected()
{
return !mUACConnectedDialogId.getCallId().empty();
}
bool
B2BSession::isStaleFork(const DialogId& dialogId)
{
return (!mUACConnectedDialogId.getCallId().empty() && dialogId != mUACConnectedDialogId);
}
void
B2BSession::processReferNotify(const SipMessage& notify)
{
unsigned int code = 400; // Bad Request - default if for some reason a valid sipfrag is not present
SipFrag* frag = dynamic_cast<SipFrag*>(notify.getContents());
if (frag)
{
// Get StatusCode from SipFrag
if (frag->message().isResponse())
{
code = frag->message().header(h_StatusLine).statusCode();
}
}
// If subscription is terminated, due to timeout and we don't have a final response in the SipFrag - treat as error
if(notify.exists(h_SubscriptionState) &&
isEqualNoCase(notify.header(h_SubscriptionState).value(), Symbols::Terminated) &&
notify.header(h_SubscriptionState).exists(p_reason) &&
isEqualNoCase(notify.header(h_SubscriptionState).param(p_reason), getTerminateReasonString(Timeout)) &&
code < 200)
{
// failure
transitionClickToCallState(ReferToDestinationFailed, 408);
end();
}
// Check if success or failure response code was in SipFrag
else if(code >= 180 && code < 200)
{
// proceeding
transitionClickToCallState(ReferToDestinationProceeding);
}
else if(code >= 200 && code < 300)
{
// success
transitionClickToCallState(ReferToDestinationConnected);
end();
}
else if(code >= 300)
{
// failure
transitionClickToCallState(ReferToDestinationFailed, code);
end();
}
}
void
B2BSession::transitionClickToCallState(ClickToCallState newState, unsigned int statusCode)
{
if(newState != mClickToCallState)
{
unsigned int resultCode = 0;
Data resultText;
Data leg = mClickToCallInitiator ? "Initiator" : "Destination";
switch(newState)
{
case Setup:
InfoLog(B2BLOG_PREFIX << "transitionClickToCallState: newState=Setup, initiator=" << mClickToCallInitiator);
break;
case Proceeding:
InfoLog(B2BLOG_PREFIX << "transitionClickToCallState: newState=Proceeding, initiator=" << mClickToCallInitiator);
resultCode = 180;
resultText = mClickToCallInitiator ? "Ringing initiator" : "Ringing destination";
break;
case Connected:
InfoLog(B2BLOG_PREFIX << "transitionClickToCallState: newState=Connected, initiator=" << mClickToCallInitiator);
resultCode = 200;
resultText = mClickToCallInitiator ? "Connected to initiator" : "Connected to destination";
break;
case Failed:
InfoLog(B2BLOG_PREFIX << "transitionClickToCallState: newState=Failed, initiator=" << mClickToCallInitiator);
resultCode = statusCode;
resultText = mClickToCallInitiator ? "Failed to connect to initiator" : "Failed to connect to destination";
break;
case ReferToDestinationProceeding:
InfoLog(B2BLOG_PREFIX << "transitionClickToCallState: newState=ReferToDestinationProceeding, initiator=" << mClickToCallInitiator);
leg = "Destination";
resultCode = 180;
resultText = "Ringing destination";
break;
case ReferToDestinationConnected:
InfoLog(B2BLOG_PREFIX << "transitionClickToCallState: newState=ReferToDestinationConnected, initiator=" << mClickToCallInitiator);
leg = "Destination";
resultCode = 200;
resultText = "Connected to destination";
break;
case ReferToDestinationFailed:
InfoLog(B2BLOG_PREFIX << "transitionClickToCallState: newState=ReferToDestinationFailed, initiator=" << mClickToCallInitiator);
leg = "Destination";
resultCode = statusCode;
resultText = "Failed to connect to destination";
break;
default:
resip_assert(false);
}
mClickToCallState = newState;
if(mXmlRpcInfo.mXmlRpcServer && resultCode != 0)
{
mXmlRpcInfo.mXmlRpcServer->sendResponse(mXmlRpcInfo.mConnectionId, mXmlRpcInfo.mRequestId, Data::Empty, resultCode, resultText, leg);
}
}
}
////////////////////////////////////////////////////////////////////////////////
// InviteSessionHandler ///////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void
B2BSession::onNewSession(ClientInviteSessionHandle h, InviteSession::OfferAnswerType oat, const SipMessage& msg)
{
InfoLog(B2BLOG_PREFIX << "onNewSession(ClientInviteSessionHandle): msg=" << LOG_MSG);
mInviteSessionHandle = h->getSessionHandle();
}
void
B2BSession::onNewSession(ServerInviteSessionHandle h, InviteSession::OfferAnswerType oat, const SipMessage& msg)
{
WarningLog(B2BLOG_PREFIX << "onNewSession(ServerInviteSessionHandle): ClickToCall server does not accept inbound calls - rejecting.");
mInviteSessionHandle = h->getSessionHandle();
h->reject(403 /* Forbidden */);
}
void
B2BSession::onFailure(ClientInviteSessionHandle h, const SipMessage& msg)
{
// Note: Teardown of peer is handled in destructor
InfoLog(B2BLOG_PREFIX << "onFailure: msg=" << LOG_MSG);
}
void
B2BSession::onEarlyMedia(ClientInviteSessionHandle h, const SipMessage& msg, const SdpContents& sdp)
{
InfoLog(B2BLOG_PREFIX << "onEarlyMedia: msg=" << LOG_MSG_WITH_SDP);
}
void
B2BSession::onProvisional(ClientInviteSessionHandle h, const SipMessage& msg)
{
InfoLog(B2BLOG_PREFIX << "onProvisional: msg=" << LOG_MSG);
if(isStaleFork(h->getDialogId())) return;
if(msg.header(h_StatusLine).responseCode() >= 180 && mClickToCallState == Setup)
{
transitionClickToCallState(Proceeding);
}
if(mPeer)
{
if(mPeer->mInviteSessionHandle.isValid())
{
ServerInviteSession* sis = dynamic_cast<ServerInviteSession*>(mPeer->mInviteSessionHandle.get());
if(sis && !sis->isAccepted())
{
sis->provisional(msg.header(h_StatusLine).responseCode());
}
}
}
}
void
B2BSession::onConnected(ClientInviteSessionHandle h, const SipMessage& msg)
{
InfoLog(B2BLOG_PREFIX << "onConnected: msg=" << LOG_MSG);
if(!isUACConnected())
{
// It is possible in forking scenarios to get multiple 200 responses, if this is
// our first 200 response, then this is the leg we accept, store the connected DialogId
mUACConnectedDialogId = h->getDialogId();
// Note: each forked leg will update mInviteSessionHandle (in onNewSession call) - need to set mInviteSessionHandle for final answering leg on 200
mInviteSessionHandle = h->getSessionHandle();
if(mClickToCallState == Setup || mClickToCallState == Proceeding)
{
transitionClickToCallState(Connected);
}
}
else
{
// We already have a connected leg - end this one with a BYE
h->end();
}
}
void
B2BSession::onConnected(InviteSessionHandle h, const SipMessage& msg)
{
InfoLog(B2BLOG_PREFIX << "onConnected: msg=" << LOG_MSG);
if(mClickToCallState == Setup || mClickToCallState == Proceeding)
{
transitionClickToCallState(Connected);
}
}
void
B2BSession::onStaleCallTimeout(ClientInviteSessionHandle h)
{
InfoLog(B2BLOG_PREFIX << "onStaleCallTimeout:");
endPeer();
}
void
B2BSession::onTerminated(InviteSessionHandle h, InviteSessionHandler::TerminatedReason reason, const SipMessage* msg)
{
Data reasonData;
switch(reason)
{
case InviteSessionHandler::RemoteBye:
reasonData = "received a BYE from peer";
break;
case InviteSessionHandler::RemoteCancel:
reasonData = "received a CANCEL from peer";
break;
case InviteSessionHandler::Rejected:
reasonData = "received a rejection from peer";
break;
case InviteSessionHandler::LocalBye:
reasonData = "ended locally via BYE";
break;
case InviteSessionHandler::LocalCancel:
reasonData = "ended locally via CANCEL";
break;
case InviteSessionHandler::Replaced:
reasonData = "ended due to being replaced";
break;
case InviteSessionHandler::Referred:
reasonData = "ended due to being reffered";
break;
case InviteSessionHandler::Error:
reasonData = "ended due to an error";
break;
case InviteSessionHandler::Timeout:
reasonData = "ended due to a timeout";
break;
default:
resip_assert(false);
break;
}
if(msg)
{
InfoLog(B2BLOG_PREFIX << "onTerminated: reason=" << reasonData << ", msg=" << LOG_MSGP);
}
else
{
InfoLog(B2BLOG_PREFIX << "onTerminated: reason=" << reasonData);
}
unsigned int statusCode = 603;
if(msg)
{
if(msg->isResponse())
{
statusCode = msg->header(h_StatusLine).responseCode();
}
}
// If this is a referred call and the refer is still around - then switch back to referrer (ie. failed transfer recovery)
if(mReferringAppDialogSet.isValid() && mPeer)
{
B2BSession* session = (B2BSession*)mReferringAppDialogSet.get();
session->stealPeer(this);
}
if(isStaleFork(h->getDialogId())) return;
// If we have a peer that hasn't been accepted yet - then pass back terminated code, by calling reject now
if(mPeer && mPeer->mInviteSessionHandle.isValid())
{
ServerInviteSession* sis = dynamic_cast<ServerInviteSession*>(mPeer->mInviteSessionHandle.get());
if(sis && !sis->isAccepted())
{
sis->reject(statusCode);
}
}
if(mClickToCallState == Setup || mClickToCallState == Proceeding)
{
transitionClickToCallState(Failed, statusCode);
}
endPeer();
}
void
B2BSession::onRedirected(ClientInviteSessionHandle h, const SipMessage& msg)
{
// We will recurse on redirect requests, so nothing to do here
InfoLog(B2BLOG_PREFIX << "onRedirected: msg=" << LOG_MSG);
}
void
B2BSession::onAnswer(InviteSessionHandle h, const SipMessage& msg, const SdpContents& sdp)
{
InfoLog(B2BLOG_PREFIX << "onAnswer: msg=" << LOG_MSG_WITH_SDP);
if(isStaleFork(h->getDialogId())) return;
if(mPeer)
{
if(mPeer->mInviteSessionHandle.isValid())
{
if(mPeer->mWaitingAnswerFromPeer)
{
mPeer->mInviteSessionHandle->provideAnswer(sdp);
mPeer->mWaitingAnswerFromPeer = false;
}
else if(mPeer->mWaitingOfferFromPeer)
{
mPeer->mInviteSessionHandle->provideOffer(sdp);
mPeer->mWaitingOfferFromPeer = false;
}
ServerInviteSession* sis = dynamic_cast<ServerInviteSession*>(mPeer->mInviteSessionHandle.get());
if(sis && !sis->isAccepted())
{
sis->accept();
}
}
}
else if(mClickToCallInitiator && (mClickToCallState == Setup || mClickToCallState == Proceeding))
{
if(mClickToCallAnchorEnabled)
{
// We are anchoring (B2B'ing) the call - time to start second leg
mPeer = new B2BSession(mServer);
mPeer->setPeer(this);
mPeer->startClickToCallAnchorLeg(msg.header(h_To), mClickToCallDestination, mXmlRpcInfo);
mWaitingOfferFromPeer = true;
}
else
{
// ClickToCall, but do not anchor call - send REFER here instead
h->refer(NameAddr(mClickToCallDestination));
}
}
}
void
B2BSession::onOffer(InviteSessionHandle h, const SipMessage& msg, const SdpContents& sdp)
{
InfoLog(B2BLOG_PREFIX << "onOffer: msg=" << LOG_MSG_WITH_SDP);
if(isStaleFork(h->getDialogId())) return;
if(mPeer)
{
if(mPeer->mInviteSessionHandle.isValid())
{
mPeer->mInviteSessionHandle->provideOffer(sdp);
mPeer->mWaitingOfferFromPeer = false;
mWaitingAnswerFromPeer = true;
}
else
{
resip_assert(false);
}
}
else
{
ErrLog(B2BLOG_PREFIX << "onOffer: No peer, rejecting with 501.");
h->reject(501 /* Not Implemented */);
}
}
void
B2BSession::onOfferRequired(InviteSessionHandle h, const SipMessage& msg)
{
InfoLog(B2BLOG_PREFIX << "onOfferRequired: msg=" << LOG_MSG);
if(isStaleFork(h->getDialogId())) return;
if(mPeer)
{
if(mPeer->mInviteSessionHandle.isValid())
{
mPeer->mInviteSessionHandle->requestOffer();
mWaitingOfferFromPeer = true;
}
else
{
resip_assert(false);
}
}
else
{
ErrLog(B2BLOG_PREFIX << "onOfferRequired: No peer, rejecting with 501.");
h->reject(501 /* Not Implemented */);
}
}
void
B2BSession::onOfferRejected(InviteSessionHandle h, const SipMessage* msg)
{
int statusCode = 488;
WarningCategory* warning=0;
if(isStaleFork(h->getDialogId())) return;
if(msg)
{
InfoLog(B2BLOG_PREFIX << "onOfferRejected: msg=" << LOG_MSGP);
if(msg->exists(h_Warnings))
{
warning = (WarningCategory*)&msg->header(h_Warnings).back();
}
if(msg->isResponse())
{
statusCode = msg->header(h_StatusLine).responseCode();
}
}
else
{
InfoLog(B2BLOG_PREFIX << "onOfferRejected:");
}
if(mPeer)
{
if(mPeer->mInviteSessionHandle.isValid() && mPeer->mWaitingAnswerFromPeer)
{
mPeer->mWaitingAnswerFromPeer = false;
mPeer->mInviteSessionHandle->reject(statusCode, warning);
}
}
}
void
B2BSession::onOfferRequestRejected(InviteSessionHandle h, const SipMessage& msg)
{
InfoLog(B2BLOG_PREFIX << "onOfferRequestRejected: msg=" << LOG_MSG);
// This is called when we are waiting to resend a INVITE with no sdp after a glare condition, and we
// instead receive an inbound INVITE or UPDATE
if(mPeer)
{
if(mPeer->mInviteSessionHandle.isValid() && mPeer->mWaitingOfferFromPeer)
{
// Return glare to peer
mPeer->mInviteSessionHandle->reject(491);
mPeer->mWaitingOfferFromPeer = false;
}
}
}
void
B2BSession::onRemoteSdpChanged(InviteSessionHandle h, const SipMessage& msg, const SdpContents& sdp)
{
/// called when a modified SDP is received in a 2xx response to a
/// session-timer reINVITE. Under normal circumstances where the response
/// SDP is unchanged from current remote SDP no handler is called
/// There is not much we can do about this. If session timers are used then they are managed separately per leg
/// and we have no real mechanism to notify the other peer of new SDP without starting a new offer/answer negotiation
InfoLog(B2BLOG_PREFIX << "onRemoteSdpChanged: msg=" << LOG_MSG_WITH_SDP);
}
void
B2BSession::onInfo(InviteSessionHandle h, const SipMessage& msg)
{
InfoLog(B2BLOG_PREFIX << "onInfo: msg=" << LOG_MSG);
if(mPeer)
{
if(mPeer->mInviteSessionHandle.isValid() && msg.getContents())
{
mPeer->mInviteSessionHandle->info(*msg.getContents());
mWaitingNitAnswerFromPeer = true;
}
}
else
{
h->acceptNIT();
}
}
void
B2BSession::onInfoSuccess(InviteSessionHandle h, const SipMessage& msg)
{
InfoLog(B2BLOG_PREFIX << "onInfoSuccess: msg=" << LOG_MSG);
if(mPeer)
{
if(mPeer->mInviteSessionHandle.isValid() && mPeer->mWaitingNitAnswerFromPeer)
{
mPeer->mInviteSessionHandle->acceptNIT(msg.header(h_StatusLine).responseCode(), msg.getContents());
}
}
}
void
B2BSession::onInfoFailure(InviteSessionHandle h, const SipMessage& msg)
{
InfoLog(B2BLOG_PREFIX << "onInfoFailure: msg=" << LOG_MSG);
if(mPeer)
{
if(mPeer->mInviteSessionHandle.isValid() && mPeer->mWaitingNitAnswerFromPeer)
{
mPeer->mInviteSessionHandle->rejectNIT(msg.header(h_StatusLine).responseCode());
}
}
}
void
B2BSession::onRefer(InviteSessionHandle h, ServerSubscriptionHandle ss, const SipMessage& msg)
{
InfoLog(B2BLOG_PREFIX << "onRefer: msg=" << LOG_MSG);
// If no peer (for some reason), then reject request
if(!mPeer)
{
ss->send(ss->reject(403));
return;
}
// Recurse on the REFER - do not pass to other leg
try
{
// Accept the Refer
ss->send(ss->accept(202 /* Refer Accepted */));
B2BSession* newPeer = new B2BSession(mServer);
mPeer->mWaitingOfferFromPeer = true;
// Map other leg to this new one
newPeer->stealPeer(this);
newPeer->mReferringAppDialogSet = getHandle();
auto invitemsg = mDum.makeInviteSessionFromRefer(msg, ss->getHandle(), 0 /* SdpOffer */, newPeer);
mDum.send(std::move(invitemsg));
}
catch(BaseException &e)
{
WarningLog(B2BLOG_PREFIX << "onRefer exception: " << e);
}
catch(...)
{
WarningLog(B2BLOG_PREFIX << "onRefer unknown exception");
}
}
void
B2BSession::onReferAccepted(InviteSessionHandle h, ClientSubscriptionHandle csh, const SipMessage& msg)
{
InfoLog(B2BLOG_PREFIX << "onReferAccepted: msg=" << LOG_MSG);
}
void
B2BSession::onReferRejected(InviteSessionHandle h, const SipMessage& msg)
{
InfoLog(B2BLOG_PREFIX << "onReferRejected: msg=" << LOG_MSG);
// Endpoint doesn't support REFER - Fallback to anchoring Click-To-Call
mClickToCallAnchorEnabled = true;
mPeer = new B2BSession(mServer);
mPeer->setPeer(this);
mPeer->startClickToCallAnchorLeg(msg.header(h_From), mClickToCallDestination, mXmlRpcInfo);
mWaitingOfferFromPeer = true;
}
bool
B2BSession::doReferNoSub(const SipMessage& msg)
{
// If no peer (for some reason), then return false
if(!mPeer)
{
return false;
}
B2BSession* newPeer = new B2BSession(mServer);
mPeer->mWaitingOfferFromPeer = true;
// Map other leg to this new one
newPeer->stealPeer(this);
newPeer->mReferringAppDialogSet = getHandle();
// Build the Invite
auto invitemsg = mDum.makeInviteSessionFromRefer(msg, getUserProfile(), 0 /* Sdp Offer */, newPeer);
mDum.send(std::move(invitemsg));
return true;
}
void
B2BSession::onReferNoSub(InviteSessionHandle h, const SipMessage& msg)
{
InfoLog(B2BLOG_PREFIX << "onReferNoSub: msg=" << LOG_MSG);
// If no peer (for some reason), then reject request
if(!mPeer)
{
h->rejectReferNoSub(403);
return;
}
// Accept the Refer
h->acceptReferNoSub(202 /* Refer Accepted */);
doReferNoSub(msg);
}
void
B2BSession::onMessage(InviteSessionHandle h, const SipMessage& msg)
{
InfoLog(B2BLOG_PREFIX << "onMessage: msg=" << LOG_MSG);
if(mPeer)
{
if(mPeer->mInviteSessionHandle.isValid() && msg.getContents())
{
mPeer->mInviteSessionHandle->message(*msg.getContents());
mWaitingNitAnswerFromPeer = true;
}
}
else
{
h->acceptNIT();
}
}
void
B2BSession::onMessageSuccess(InviteSessionHandle h, const SipMessage& msg)
{
InfoLog(B2BLOG_PREFIX << "onMessageSuccess: msg=" << LOG_MSG);
if(mPeer)
{
if(mPeer->mInviteSessionHandle.isValid() && mPeer->mWaitingNitAnswerFromPeer)
{
mPeer->mInviteSessionHandle->acceptNIT(msg.header(h_StatusLine).responseCode(), msg.getContents());
}
}
}
void
B2BSession::onMessageFailure(InviteSessionHandle h, const SipMessage& msg)
{
InfoLog(B2BLOG_PREFIX << "onMessageFailure: msg=" << LOG_MSG);
if(mPeer)
{
if(mPeer->mInviteSessionHandle.isValid() && mPeer->mWaitingNitAnswerFromPeer)
{
mPeer->mInviteSessionHandle->rejectNIT(msg.header(h_StatusLine).responseCode());
}
}
}
void
B2BSession::onForkDestroyed(ClientInviteSessionHandle h)
{
InfoLog(B2BLOG_PREFIX << "onForkDestroyed:");
}
////////////////////////////////////////////////////////////////////////////////
// DialogSetHandler ///////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void
B2BSession::onTrying(AppDialogSetHandle h, const SipMessage& msg)
{
InfoLog(B2BLOG_PREFIX << "onTrying: msg=" << LOG_MSG);
}
void
B2BSession::onNonDialogCreatingProvisional(AppDialogSetHandle h, const SipMessage& msg)
{
InfoLog(B2BLOG_PREFIX << "onNonDialogCreatingProvisional: msg=" << LOG_MSG);
if(isUACConnected()) return;
if(mPeer)
{
if(mPeer->mInviteSessionHandle.isValid())
{
ServerInviteSession* sis = dynamic_cast<ServerInviteSession*>(mPeer->mInviteSessionHandle.get());
if(sis && !sis->isAccepted())
{
sis->provisional(msg.header(h_StatusLine).responseCode());
}
}
}
}
////////////////////////////////////////////////////////////////////////////////
// ClientSubscriptionHandler ///////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void
B2BSession::onUpdatePending(ClientSubscriptionHandle h, const SipMessage& msg, bool outOfOrder)
{
InfoLog(B2BLOG_PREFIX << "onUpdatePending(ClientSubscriptionHandle): " << LOG_MSG);
if (msg.exists(h_Event) && msg.header(h_Event).value() == "refer")
{
h->acceptUpdate();
processReferNotify(msg);
}
else
{
h->rejectUpdate(400, Data("Only notifies for refers are allowed."));
}
}
void
B2BSession::onUpdateActive(ClientSubscriptionHandle h, const SipMessage& msg, bool outOfOrder)
{
InfoLog(B2BLOG_PREFIX << "onUpdateActive(ClientSubscriptionHandle): " << LOG_MSG);
if (msg.exists(h_Event) && msg.header(h_Event).value() == "refer")
{
h->acceptUpdate();
processReferNotify(msg);
}
else
{
h->rejectUpdate(400, Data("Only notifies for refers are allowed."));
}
}
void
B2BSession::onUpdateExtension(ClientSubscriptionHandle h, const SipMessage& msg, bool outOfOrder)
{
InfoLog(B2BLOG_PREFIX << "onUpdateExtension(ClientSubscriptionHandle): " << LOG_MSG);
if (msg.exists(h_Event) && msg.header(h_Event).value() == "refer")
{
h->acceptUpdate();
processReferNotify(msg);
}
else
{
h->rejectUpdate(400, Data("Only notifies for refers are allowed."));
}
}
void
B2BSession::onNotifyNotReceived(resip::ClientSubscriptionHandle h)
{
InfoLog(B2BLOG_PREFIX << "onNotifyNotReceived(ClientSubscriptionHandle)");
transitionClickToCallState(ReferToDestinationFailed, 408);
end();
}
void
B2BSession::onTerminated(ClientSubscriptionHandle h, const SipMessage* msg)
{
if(msg)
{
InfoLog(B2BLOG_PREFIX << "onTerminated(ClientSubscriptionHandle): " << LOG_MSGP);
//Note: Final notify is sometimes only passed in the onTerminated callback
if (msg->isRequest() && msg->exists(h_Event) && msg->header(h_Event).value() == "refer")
{
processReferNotify(*msg);
}
}
else
{
InfoLog(B2BLOG_PREFIX << "onTerminated(ClientSubscriptionHandle)");
}
}
void
B2BSession::onNewSubscription(ClientSubscriptionHandle h, const SipMessage& msg)
{
InfoLog(B2BLOG_PREFIX << "onNewSubscription(ClientSubscriptionHandle): " << LOG_MSG);
}
int
B2BSession::onRequestRetry(ClientSubscriptionHandle h, int retryMinimum, const SipMessage& msg)
{
InfoLog(B2BLOG_PREFIX << "onRequestRetry(ClientSubscriptionHandle): " << LOG_MSG);
return -1;
}
}
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

View File

@@ -0,0 +1,159 @@
#if !defined(B2BSession_hxx)
#define B2BSession_hxx
#include <rutil/Log.hxx>
#include <resip/dum/DialogUsageManager.hxx>
#include <resip/dum/InviteSessionHandler.hxx>
#include <resip/dum/DialogSetHandler.hxx>
#include <resip/dum/AppDialogSet.hxx>
#include "XmlRpcServer.hxx"
namespace clicktocall
{
class Server;
typedef unsigned int B2BSessionHandle;
class B2BSession : public resip::AppDialogSet
{
public:
B2BSession(Server& server);
virtual ~B2BSession();
void setPeer(B2BSession* peer);
B2BSession* getPeer();
void stealPeer(B2BSession* victimSession);
B2BSessionHandle getB2BSessionHandle() const { return mHandle; }
void clickToCall(const resip::Uri& initiator, const resip::Uri& destination, bool anchorCall, const XmlRpcInfo& xmlRpcInfo);
void startCall(const resip::Uri& destinationUri, const resip::NameAddr& from, const resip::SdpContents *sdp);
protected:
friend class Server;
// Invite Session Handler /////////////////////////////////////////////////////
virtual void onNewSession(resip::ClientInviteSessionHandle h, resip::InviteSession::OfferAnswerType oat, const resip::SipMessage& msg);
virtual void onNewSession(resip::ServerInviteSessionHandle h, resip::InviteSession::OfferAnswerType oat, const resip::SipMessage& msg);
virtual void onFailure(resip::ClientInviteSessionHandle h, const resip::SipMessage& msg);
virtual void onEarlyMedia(resip::ClientInviteSessionHandle, const resip::SipMessage&, const resip::SdpContents&);
virtual void onProvisional(resip::ClientInviteSessionHandle, const resip::SipMessage& msg);
virtual void onConnected(resip::ClientInviteSessionHandle h, const resip::SipMessage& msg);
virtual void onConnected(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual void onStaleCallTimeout(resip::ClientInviteSessionHandle);
virtual void onTerminated(resip::InviteSessionHandle h, resip::InviteSessionHandler::TerminatedReason reason, const resip::SipMessage* msg);
virtual void onRedirected(resip::ClientInviteSessionHandle, const resip::SipMessage& msg);
virtual void onAnswer(resip::InviteSessionHandle, const resip::SipMessage& msg, const resip::SdpContents&);
virtual void onOffer(resip::InviteSessionHandle handle, const resip::SipMessage& msg, const resip::SdpContents& offer);
virtual void onOfferRequired(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual void onOfferRejected(resip::InviteSessionHandle, const resip::SipMessage* msg);
virtual void onOfferRequestRejected(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual void onRemoteSdpChanged(resip::InviteSessionHandle, const resip::SipMessage& msg, const resip::SdpContents& sdp);
virtual void onInfo(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual void onInfoSuccess(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual void onInfoFailure(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual void onRefer(resip::InviteSessionHandle, resip::ServerSubscriptionHandle, const resip::SipMessage& msg);
virtual void onReferAccepted(resip::InviteSessionHandle, resip::ClientSubscriptionHandle, const resip::SipMessage& msg);
virtual void onReferRejected(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual bool doReferNoSub(const resip::SipMessage& msg);
virtual void onReferNoSub(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual void onMessage(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual void onMessageSuccess(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual void onMessageFailure(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual void onForkDestroyed(resip::ClientInviteSessionHandle);
// DialogSetHandler //////////////////////////////////////////////
virtual void onTrying(resip::AppDialogSetHandle, const resip::SipMessage& msg);
virtual void onNonDialogCreatingProvisional(resip::AppDialogSetHandle, const resip::SipMessage& msg);
// ClientSubscriptionHandler ///////////////////////////////////////////////////
virtual void onUpdatePending(resip::ClientSubscriptionHandle h, const resip::SipMessage& notify, bool outOfOrder);
virtual void onUpdateActive(resip::ClientSubscriptionHandle h, const resip::SipMessage& notify, bool outOfOrder);
virtual void onUpdateExtension(resip::ClientSubscriptionHandle h, const resip::SipMessage& notify, bool outOfOrder);
virtual void onNotifyNotReceived(resip::ClientSubscriptionHandle h);
virtual void onTerminated(resip::ClientSubscriptionHandle h, const resip::SipMessage* notify);
virtual void onNewSubscription(resip::ClientSubscriptionHandle h, const resip::SipMessage& notify);
virtual int onRequestRetry(resip::ClientSubscriptionHandle h, int retryMinimum, const resip::SipMessage& notify);
private:
bool buildLocalOffer(resip::SdpContents& sdp);
void startClickToCallAnchorLeg(const resip::NameAddr& initiator, const resip::Uri& destination, const XmlRpcInfo& xmlRpcInfo);
void endPeer();
bool isUACConnected();
bool isStaleFork(const resip::DialogId& dialogId);
void processReferNotify(const resip::SipMessage& notify);
Server& mServer;
resip::DialogUsageManager& mDum;
B2BSession* mPeer;
resip::InviteSessionHandle mInviteSessionHandle;
B2BSessionHandle mHandle;
resip::AppDialogSetHandle mReferringAppDialogSet;
// State information
resip::DialogId mUACConnectedDialogId;
bool mWaitingOfferFromPeer;
bool mWaitingAnswerFromPeer;
bool mWaitingNitAnswerFromPeer;
// Click-to-Call Info
typedef enum
{
Undefined, // Not used
Setup,
Proceeding,
Connected,
Failed,
ReferToDestinationProceeding,
ReferToDestinationConnected,
ReferToDestinationFailed
} ClickToCallState;
ClickToCallState mClickToCallState;
void transitionClickToCallState(ClickToCallState newState, unsigned int statusCode=0);
resip::Uri mClickToCallDestination;
bool mClickToCallAnchorEnabled;
bool mClickToCallInitiator;
XmlRpcInfo mXmlRpcInfo;
};
}
#endif
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

View File

@@ -0,0 +1,42 @@
set(INCLUDES
ConfigParser.hxx
Version.hxx
WebAdminThread.hxx
XmlRpcServerBase.hxx
HttpBase.hxx
XmlRpcConnection.hxx
AppSubsystem.hxx
XmlRpcServerThread.hxx
B2BSession.hxx
AddressTranslator.hxx
WebAdmin.hxx
XmlRpcServer.hxx
HttpConnection.hxx
Server.hxx
ClickToCallCmds.hxx
)
add_executable(clicktocall
AddressTranslator.cxx
AppSubsystem.cxx
B2BSession.cxx
clicktocall.cxx
ConfigParser.cxx
HttpBase.cxx
HttpConnection.cxx
Server.cxx
WebAdmin.cxx
WebAdminThread.cxx
XmlRpcConnection.cxx
XmlRpcServerBase.cxx
XmlRpcServer.cxx
XmlRpcServerThread.cxx
${INCLUDES}
)
target_include_directories(clicktocall PRIVATE ${PCRE_INCLUDE_DIRS})
target_link_libraries(clicktocall PUBLIC dum ${PCRE_LIBRARIES})
install(TARGETS clicktocall DESTINATION ${CMAKE_INSTALL_SBINDIR})
install_and_preserve_hierarchy(${CMAKE_INSTALL_INCLUDEDIR}/clicktocall ${INCLUDES})

View File

@@ -0,0 +1,80 @@
#if !defined(ClickToCallCmds_hxx)
#define ClickToCallCmds_hxx
#include <resip/dum/DumCommand.hxx>
#include "Server.hxx"
#include "B2BSession.hxx"
#define RESIPROCATE_SUBSYSTEM AppSubsystem::CLICKTOCALL
namespace clicktocall
{
/**
The classes defined here are used to pass commands from the
application thread to the DUM thread (process loop).
This ensures thread safety of the external Server methods.
Author: Scott Godin (sgodin AT SipSpectrum DOT com)
*/
class ClickToCallCmd : public resip::DumCommand
{
public:
ClickToCallCmd(Server& server, const resip::Uri& initiator, const resip::Uri& destination, bool anchorCall,
const XmlRpcInfo& xmlRpcInfo)
: mServer(server), mInitiator(initiator), mDestination(destination), mAnchorCall(anchorCall),
mXmlRpcInfo(xmlRpcInfo) {}
virtual void executeCommand()
{
mServer.clickToCallImpl(mInitiator, mDestination, mAnchorCall, mXmlRpcInfo);
}
resip::Message* clone() const { resip_assert(0); return 0; }
EncodeStream& encode(EncodeStream& strm) const { strm << " ClickToCallCmd: "; return strm; }
EncodeStream& encodeBrief(EncodeStream& strm) const { return encode(strm); }
private:
Server& mServer;
resip::Uri mInitiator;
resip::Uri mDestination;
bool mAnchorCall;
XmlRpcInfo mXmlRpcInfo;
};
}
#endif
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

View File

@@ -0,0 +1,333 @@
#include "ConfigParser.hxx"
#include "Server.hxx"
#include "AppSubsystem.hxx"
#include <iostream>
#include <fstream>
#include <iterator>
#include <rutil/DnsUtil.hxx>
#include <rutil/Log.hxx>
#include <rutil/Logger.hxx>
#include <rutil/WinLeakCheck.hxx>
using namespace clicktocall;
using namespace resip;
using namespace std;
#define RESIPROCATE_SUBSYSTEM AppSubsystem::CLICKTOCALL
namespace clicktocall
{
ConfigParser::ConfigParser(int argc, char** argv) :
// Defaults
mSipPort(5072),
mTlsPort(5073),
mTlsDomain(DnsUtil::getLocalHostName()),
mKeepAlives(true),
mLogLevel("INFO"),
mLogFilename("clicktocall.log"),
mLogFileMaxLines(50000), // 50000 is about 5M size
mXmlRpcPort(5094),
mHttpPort(5095),
mHttpAuth(false),
mHttpAuthPwd("admin")
{
// Parse config file first
parseConfigFile("clicktocall.config");
// Parse command line options
// Note: command line overrides config file setting
parseCommandLine(argc, argv);
}
ConfigParser::~ConfigParser()
{
}
void
ConfigParser::parseCommandLine(int argc, char** argv)
{
// Loop through command line arguments and process them
for(int i = 1; i < argc; i++)
{
Data commandName(argv[i]);
// Process all commandNames that don't take values
if(isEqualNoCase(commandName, "-?") ||
isEqualNoCase(commandName, "--?") ||
isEqualNoCase(commandName, "--help") ||
isEqualNoCase(commandName, "/?"))
{
cout << "Command line options are:" << endl;
cout << " -a <IP Address> - bind SIP transports to this IP address" << endl;
cout << " -d <DNS servers> - comma seperated list of DNS servers, overrides OS detected list" << endl;
cout << " -ci <ClickToCall identity> - used in From header of click-to-call requests to initiator" << endl;
cout << " -sp <port num> - local port number to use for SIP messaging (UDP/TCP)" << endl;
cout << " -tp <port num> - local port number to use for TLS SIP messaging" << endl;
cout << " -td <domain name> - domain name to use for TLS server connections" << endl;
cout << " -nk - no keepalives, set this to disable sending of keepalives" << endl;
cout << " -op <SIP URI> - URI of a proxy server to use a SIP outbound proxy" << endl;
cout << " -l <NONE|CRIT|ERR|WARNING|INFO|DEBUG|STACK> - logging level" << endl;
cout << endl;
cout << "Sample Command line:" << endl;
cout << "clicktocall -a 192.168.1.100 -l DEBUG" << endl;
exit(0);
}
else if(isEqualNoCase(commandName, "-nk"))
{
mKeepAlives = false;
}
else if(commandName.at(0) == '-')
{
commandName = commandName.substr(1); // Remove -
// Process commands that have values
Data commandValue(i+1 < argc ? argv[i+1] : Data::Empty);
if(commandValue.empty() || commandValue.at(0) == '-')
{
cerr << "Invalid command line parameters!" << endl;
exit(-1);
}
i++; // increment argument
//cout << "Command Line Name='" << commandName << "' value='" << commandValue << "'" << endl;
if(!processOption(commandName.lowercase(), commandValue))
{
cerr << "Invalid command line parameters!" << endl;
exit(-1);
}
}
else
{
cerr << "Invalid command line parameters!" << endl;
exit(-1);
}
}
}
void
ConfigParser::parseConfigFile(const Data& filename)
{
ifstream configFile(filename.c_str());
string sline;
while(getline(configFile, sline))
{
Data line(sline);
Data name;
Data value;
ParseBuffer pb(line);
pb.skipWhitespace();
const char * anchor = pb.position();
if(pb.eof() || *anchor == '#') continue; // if line is a comment or blank then skip it
// Look for =
pb.skipToOneOf("= \t");
if(!pb.eof())
{
pb.data(name,anchor);
if(*pb.position()!='=')
{
pb.skipToChar('=');
}
pb.skipChar('=');
pb.skipWhitespace();
anchor = pb.position();
if(!pb.eof())
{
pb.skipToEnd();
pb.data(value, anchor);
}
//cout << "Config file Name='" << name << "' value='" << value << "'" << endl;
processOption(name.lowercase(), value);
}
}
}
bool
ConfigParser::processOption(const Data& name, const Data& value)
{
bool result = true;
if(name == "a" || name == "ipaddress")
{
mAddress = value;
}
else if(name == "d" || name == "dnsservers")
{
if(!value.empty()) mDnsServers.clear(); // allow command line to override config file, since list is added to
// DNS Servers
ParseBuffer pb(value);
Data dnsServer;
while(!value.empty() && !pb.eof())
{
pb.skipWhitespace();
const char *start = pb.position();
pb.skipToOneOf(ParseBuffer::Whitespace, ";,"); // allow white space
pb.data(dnsServer, start);
if(DnsUtil::isIpV4Address(dnsServer))
{
mDnsServers.push_back(Tuple(dnsServer, 0, UNKNOWN_TRANSPORT).toGenericIPAddress());
}
else
{
cerr << "Tried to add dns server, but invalid format: " << value << endl;
result = false;
}
if(!pb.eof())
{
pb.skipChar();
}
}
}
else if(name == "ci" || name == "clicktocallidentity")
{
result = assignNameAddr("click to call identity", value, mClickToCallIdentity);
}
else if(name == "sp" || name == "udptcpport")
{
mSipPort = (unsigned short)value.convertUnsignedLong();
}
else if(name == "tp" || name == "tlsport")
{
mTlsPort = (unsigned short)value.convertUnsignedLong();
}
else if(name == "td" || name == "tlsdomain")
{
mTlsDomain = value;
}
else if(name == "keepalives")
{
if(value == "1" || value == "true" || value == "on" || value == "enable")
{
mKeepAlives = true;
}
else if(value == "0" || value == "false" || value == "off" || value == "disable")
{
mKeepAlives = false;
}
}
else if(name == "op" || name == "outboundproxy")
{
result = assignNameAddr("outbound proxy", value, mOutboundProxy);
}
else if(name == "l" || name == "loglevel")
{
mLogLevel = value;
}
else if(name == "logfilename")
{
mLogFilename = value;
}
else if(name == "logfilemaxlines")
{
mLogFileMaxLines = value.convertUnsignedLong();
}
else if(name == "xmlrpcport")
{
mXmlRpcPort = (unsigned short)value.convertUnsignedLong();
}
else if(name == "httpport")
{
mHttpPort = (unsigned short)value.convertUnsignedLong();
}
else if(name == "httpauth")
{
if(value == "1" || value == "true" || value == "on" || value == "enable")
{
mHttpAuth = true;
}
else if(value == "0" || value == "false" || value == "off" || value == "disable")
{
mHttpAuth = false;
}
}
else if(name == "httpauthpwd")
{
mHttpAuthPwd = value;
}
else if(name == "translationpattern")
{
mAddressTranslations.push_back(std::make_pair(value, Data::Empty));
}
else if(name == "translationoutput")
{
if(!mAddressTranslations.empty())
{
mAddressTranslations.back().second = value;
}
}
else
{
result = false;
}
return result;
}
bool
ConfigParser::assignNameAddr(const Data& settingName, const Data& settingValue, NameAddr& nameAddr)
{
try
{
if(!settingValue.empty())
{
NameAddr tempNameAddr(settingValue);
nameAddr = tempNameAddr;
}
}
catch(resip::BaseException& e)
{
// Try adding sip: to address to see if it will be valid
try
{
NameAddr tempNameAddr(Data("sip:" + settingValue));
nameAddr = tempNameAddr;
}
catch(resip::BaseException&)
{
cerr << "Invalid " << settingName << " NameAddr format=" << settingValue << ": " << e << endl;
return false;
}
}
return true;
}
}
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

View File

@@ -0,0 +1,80 @@
#if !defined(ConfigParser_hxx)
#define ConfigParser_hxx
#include <list>
#include <resip/dum/MasterProfile.hxx>
#include <rutil/dns/DnsStub.hxx>
#include <rutil/Log.hxx>
namespace clicktocall
{
class ConfigParser
{
public:
ConfigParser(int argc, char** argv);
virtual ~ConfigParser();
void parseCommandLine(int argc, char** argv);
void parseConfigFile(const resip::Data& filename);
bool processOption(const resip::Data& name, const resip::Data& value);
bool assignNameAddr(const resip::Data& settingName, const resip::Data& settingValue, resip::NameAddr& nameAddr);
resip::Data mAddress;
resip::DnsStub::NameserverList mDnsServers;
resip::NameAddr mClickToCallIdentity;
unsigned short mSipPort;
unsigned short mTlsPort;
resip::Data mTlsDomain;
resip::NameAddr mOutboundProxy;
bool mKeepAlives;
resip::Data mLogLevel;
resip::Data mLogFilename;
unsigned int mLogFileMaxLines;
unsigned short mXmlRpcPort;
unsigned short mHttpPort;
bool mHttpAuth;
resip::Data mHttpAuthPwd;
typedef std::list<std::pair<resip::Data,resip::Data> > TranslationList;
TranslationList mAddressTranslations;
};
}
#endif
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

View File

@@ -0,0 +1,258 @@
#include "rutil/ResipAssert.h"
#include <rutil/Data.hxx>
#include <rutil/Socket.hxx>
#include <resip/stack/Symbols.hxx>
#include <rutil/TransportType.hxx>
#include <rutil/Logger.hxx>
#include <resip/stack/Tuple.hxx>
#include <rutil/DnsUtil.hxx>
#include <rutil/ParseBuffer.hxx>
#include <resip/stack/Transport.hxx>
#include "AppSubsystem.hxx"
#include "HttpBase.hxx"
#include "HttpConnection.hxx"
#include "WebAdmin.hxx"
#include <rutil/WinLeakCheck.hxx>
using namespace clicktocall;
using namespace resip;
using namespace std;
#define RESIPROCATE_SUBSYSTEM AppSubsystem::CLICKTOCALL
HttpBase::~HttpBase()
{
#if defined(WIN32)
closesocket(mFd);
#else
close(mFd);
#endif
mFd=0;
for( int i=0; i<MaxConnections; i++)
{
if ( mConnection[i] )
{
delete mConnection[i] ; mConnection[i]=0;
}
}
}
HttpBase::HttpBase( int port, IpVersion ipVer, const Data& realm ):
mRealm(realm),
nextConnection(0),
mTuple(Data::Empty,port,ipVer,TCP,Data::Empty)
{
sane = true;
for ( int i=0 ; i<MaxConnections; i++)
{
mConnection[i]=0;
}
#ifdef USE_IPV6
mFd = ::socket(ipVer == V4 ? PF_INET : PF_INET6, SOCK_STREAM, 0);
#else
mFd = ::socket(PF_INET, SOCK_STREAM, 0);
#endif
if ( mFd == INVALID_SOCKET )
{
int e = getErrno();
ErrLog (<< "Failed to create socket: " << strerror(e));
sane = false;
return;
}
DebugLog (<< "Creating fd=" << (int)mFd
<< (ipVer == V4 ? " V4/" : " V6/") );
int on = 1;
#if !defined(WIN32)
if ( ::setsockopt ( mFd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) )
#else
if ( ::setsockopt ( mFd, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)) )
#endif
{
int e = getErrno();
ErrLog (<< "Couldn't set sockoptions SO_REUSEPORT | SO_REUSEADDR: " << strerror(e));
sane = false;
return;
}
DebugLog (<< "Binding to " << Tuple::inet_ntop(mTuple));
if ( ::bind( mFd, &mTuple.getMutableSockaddr(), mTuple.length()) == SOCKET_ERROR )
{
int e = getErrno();
if ( e == EADDRINUSE )
{
ErrLog (<< mTuple << " already in use ");
}
else
{
ErrLog (<< "Could not bind to " << mTuple);
}
sane = false;
return;
}
bool ok = makeSocketNonBlocking(mFd);
if ( !ok )
{
ErrLog (<< "Could not make HTTP socket non-blocking " << port );
sane = false;
return;
}
// do the listen, seting the maximum queue size for compeletly established
// sockets -- on linux, tcp_max_syn_backlog should be used for the incomplete
// queue size(see man listen)
int e = listen(mFd,5 );
if (e != 0 )
{
int e = getErrno();
InfoLog (<< "Failed listen " << strerror(e));
sane = false;
return;
}
}
void
HttpBase::buildFdSet(FdSet& fdset)
{
fdset.setRead( mFd );
for( int i=0; i<MaxConnections; i++)
{
if ( mConnection[i] )
{
mConnection[i]->buildFdSet(fdset);
}
}
}
void
HttpBase::process(FdSet& fdset)
{
if (fdset.readyToRead(mFd))
{
Tuple tuple(mTuple);
struct sockaddr& peer = tuple.getMutableSockaddr();
socklen_t peerLen = tuple.length();
Socket sock = accept( mFd, &peer, &peerLen);
if ( sock == SOCKET_ERROR )
{
int e = getErrno();
switch (e)
{
case EWOULDBLOCK:
return;
default:
ErrLog(<< "Some error reading from socket: " << e);
}
return;
}
makeSocketNonBlocking(sock);
int c = nextConnection;
nextConnection = ( nextConnection+1 ) % MaxConnections;
if ( mConnection[c] )
{
delete mConnection[c]; mConnection[c] = 0;
}
mConnection[c] = new HttpConnection(*this,sock);
DebugLog (<< "Received TCP connection as connection=" << c << " fd=" << (int)sock);
}
for( int i=0; i<MaxConnections; i++)
{
if ( mConnection[i] )
{
bool ok = mConnection[i]->process(fdset);
if ( !ok )
{
delete mConnection[i]; mConnection[i]=0;
}
}
}
}
void HttpBase::setPage( const Data& page, int pageNumber, int response, const Mime& type )
{
for ( int i=0 ; i<MaxConnections; i++)
{
if ( mConnection[i] )
{
if ( mConnection[i]->mPageNumber == pageNumber )
{
mConnection[i]->setPage( page,response,type );
}
}
}
}
bool HttpBase::isSane()
{
return sane;
}
/* ====================================================================
* The Vovida Software License, Version 1.0
*
* Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The names "VOCAL", "Vovida Open Communication Application Library",
* and "Vovida Open Communication Application Library (VOCAL)" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact vocal@vovida.org.
*
* 4. Products derived from this software may not be called "VOCAL", nor
* may "VOCAL" appear in their name, without prior written
* permission of Vovida Networks, Inc.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
* NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
* IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* ====================================================================
*
* This software consists of voluntary contributions made by Vovida
* Networks, Inc. and many individuals on behalf of Vovida Networks,
* Inc. For more information on Vovida Networks, Inc., please see
* <http://www.vovida.org/>.
*
*/

View File

@@ -0,0 +1,104 @@
#if !defined(HttpBase_hxx)
#define HttpBase_hxx
#include <rutil/Data.hxx>
#include <rutil/Socket.hxx>
#include <rutil/TransportType.hxx>
#include <resip/stack/Tuple.hxx>
#include <resip/stack/Mime.hxx>
namespace clicktocall
{
class HttpConnection;
class HttpBase
{
friend class HttpConnection;
public:
HttpBase( int port, resip::IpVersion version, const resip::Data& realm );
virtual ~HttpBase();
void buildFdSet(resip::FdSet& fdset);
void process(resip::FdSet& fdset);
bool isSane();
protected:
virtual void buildPage( const resip::Data& uri,
int pageNumber,
const resip::Data& user,
const resip::Data& password )=0;
void setPage( const resip::Data& page,
int pageNumber,
int response=200,
const resip::Mime& pType = resip::Mime("text","html") );
const resip::Data mRealm;
private:
static const int MaxConnections = 30;
resip::Socket mFd;
int nextConnection;
resip::Tuple mTuple;
bool sane;
HttpConnection* mConnection[MaxConnections];
};
}
#endif
/* ====================================================================
* The Vovida Software License, Version 1.0
*
* Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The names "VOCAL", "Vovida Open Communication Application Library",
* and "Vovida Open Communication Application Library (VOCAL)" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact vocal@vovida.org.
*
* 4. Products derived from this software may not be called "VOCAL", nor
* may "VOCAL" appear in their name, without prior written
* permission of Vovida Networks, Inc.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
* NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
* IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* ====================================================================
*
* This software consists of voluntary contributions made by Vovida
* Networks, Inc. and many individuals on behalf of Vovida Networks,
* Inc. For more information on Vovida Networks, Inc., please see
* <http://www.vovida.org/>.
*
*/

View File

@@ -0,0 +1,421 @@
#include "rutil/ResipAssert.h"
#include <rutil/Data.hxx>
#include <rutil/Socket.hxx>
#include <resip/stack/Symbols.hxx>
#include <rutil/TransportType.hxx>
#include <rutil/Logger.hxx>
#include <resip/stack/Tuple.hxx>
#include <rutil/DnsUtil.hxx>
#include <rutil/ParseBuffer.hxx>
#include "Version.hxx"
#include "AppSubsystem.hxx"
#include "Server.hxx"
#include "HttpBase.hxx"
#include "HttpConnection.hxx"
using namespace clicktocall;
using namespace resip;
using namespace std;
#define RESIPROCATE_SUBSYSTEM AppSubsystem::CLICKTOCALL
int HttpConnection::nextPageNumber=1;
HttpConnection::HttpConnection( HttpBase& base, resip::Socket pSock ):
mHttpBase( base ),
mPageNumber(nextPageNumber++),
mSock(pSock),
mParsedRequest(false)
{
resip_assert( mSock > 0 );
}
HttpConnection::~HttpConnection()
{
resip_assert( mSock > 0 );
#ifdef WIN32
closesocket(mSock); mSock=0;
#else
close(mSock); mSock=0;
#endif
}
void
HttpConnection::buildFdSet(FdSet& fdset)
{
if ( !mTxBuffer.empty() )
{
fdset.setWrite(mSock);
}
fdset.setRead(mSock);
}
bool
HttpConnection::process(FdSet& fdset)
{
if ( fdset.hasException(mSock) )
{
int errNum = 0;
int errNumSize = sizeof(errNum);
getsockopt(mSock,SOL_SOCKET,SO_ERROR,(char *)&errNum,(socklen_t *)&errNumSize);
InfoLog (<< "Exception reading from socket "
<< (int)mSock << " code: " << errNum << "; closing connection");
return false;
}
if ( fdset.readyToRead( mSock ) )
{
bool ok = processSomeReads();
if ( !ok )
{
return false;
}
}
if ( (!mTxBuffer.empty()) && fdset.readyToWrite( mSock ) )
{
bool ok = processSomeWrites();
if ( !ok )
{
return false;
}
}
return true;
}
void
HttpConnection::setPage(const Data& pPage,int response,const Mime& pType)
{
Data page(pPage);
switch (response)
{
case 401:
{
mTxBuffer += "HTTP/1.0 401 Unauthorized"; mTxBuffer += Symbols::CRLF;
page = ("<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">"
"<html><head>"
"<title>401 Unauthorized</title>"
"</head><body>"
"<h1>Unauthorized</h1>"
"</body></html>" );
}
break;
case 404:
{
mTxBuffer += "HTTP/1.0 404 Not Found"; mTxBuffer += Symbols::CRLF;
page = ("<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">"
"<html><head>"
"<title>404 Not Found</title>"
"</head><body>"
"<h1>Unauthorized</h1>"
"</body></html>" );
}
break;
case 301:
{
mTxBuffer += "HTTP/1.0 301 Moved Permanently"; mTxBuffer += Symbols::CRLF;
mTxBuffer += "Location: http:/index.html"; mTxBuffer += Symbols::CRLF;
page = ("<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">"
"<html><head>"
"<title>301 Moved Permanently</title>"
"</head><body>"
"<h1>Moved</h1>"
"</body></html>" );
}
break;
case 200:
{
mTxBuffer += "HTTP/1.0 200 OK" ; mTxBuffer += Symbols::CRLF;
}
break;
default:
{
resip_assert(0);
Data resp;
{
DataStream s(resp);
s << response;
s.flush();
}
mTxBuffer += "HTTP/1.0 ";
mTxBuffer += resp;
mTxBuffer += "OK" ; mTxBuffer += Symbols::CRLF;
}
break;
}
Data len;
{
DataStream s(len);
s << page.size();
s.flush();
}
mTxBuffer += "WWW-Authenticate: Basic realm=\"";
if ( mHttpBase.mRealm.empty() )
{
mTxBuffer += resip::DnsUtil::getLocalHostName();
}
else
{
mTxBuffer += mHttpBase.mRealm;
}
mTxBuffer += "\" ";
mTxBuffer += Symbols::CRLF;
mTxBuffer += "Server: clicktocall " ;
mTxBuffer += Data(CLICKTOCALL_VERSION_STRING);
mTxBuffer += Symbols::CRLF;
mTxBuffer += "Mime-version: 1.0 " ; mTxBuffer += Symbols::CRLF;
mTxBuffer += "Pragma: no-cache " ; mTxBuffer += Symbols::CRLF;
mTxBuffer += "Content-Length: "; mTxBuffer += len; mTxBuffer += Symbols::CRLF;
mTxBuffer += "Content-Type: " ;
mTxBuffer += pType.type() ;
mTxBuffer +="/" ;
mTxBuffer += pType.subType() ; mTxBuffer += Symbols::CRLF;
mTxBuffer += Symbols::CRLF;
mTxBuffer += page;
}
bool
HttpConnection::processSomeReads()
{
const int bufSize = 8000;
char buf[bufSize];
#if defined(WIN32)
int bytesRead = ::recv(mSock, buf, bufSize, 0);
#else
int bytesRead = ::read(mSock, buf, bufSize);
#endif
if (bytesRead == INVALID_SOCKET)
{
int e = getErrno();
switch (e)
{
case EAGAIN:
InfoLog (<< "No data ready to read");
return true;
case EINTR:
InfoLog (<< "The call was interrupted by a signal before any data was read.");
break;
case EIO:
InfoLog (<< "I/O error");
break;
case EBADF:
InfoLog (<< "fd is not a valid file descriptor or is not open for reading.");
break;
case EINVAL:
InfoLog (<< "fd is attached to an object which is unsuitable for reading.");
break;
case EFAULT:
InfoLog (<< "buf is outside your accessible address space.");
break;
default:
InfoLog (<< "Some other error");
break;
}
InfoLog (<< "Failed read on " << (int)mSock << " " << strerror(e));
return false;
}
else if (bytesRead == 0)
{
InfoLog (<< "Connection closed by remote " );
return false;
}
//DebugLog (<< "HttpConnection::processSomeReads() "
// << " read=" << bytesRead);
mRxBuffer += Data( buf, bytesRead );
tryParse();
return true;
}
void
HttpConnection::tryParse()
{
//DebugLog (<< "parse " << mRxBuffer );
ParseBuffer pb(mRxBuffer);
pb.skipToChar(Symbols::SPACE[0]);
const char* start = pb.skipWhitespace();
pb.skipToChar(Symbols::SPACE[0]);
if (pb.eof())
{
// parse failed - just return
return;
}
Data uri;
pb.data( uri, start );
DebugLog (<< "parse found URI " << uri );
mParsedRequest = true;
Data user;
Data password;
try
{
pb.skipToChars( "Authorization" );
if ( !pb.eof() )
{
if ( pb.eof() ) DebugLog( << "Did not find Authorization header" );
pb.skipToChars( "Basic" ); pb.skipN(6);
if ( pb.eof() ) DebugLog( << "Did not find Authorization basic " );
pb.skipWhitespace();
if ( pb.eof() ) DebugLog( << "Something weird in Auhtorization header " );
if ( !pb.eof() )
{
const char* a = pb.position();
pb.skipNonWhitespace();
Data buf = pb.data(a);
DebugLog (<< "parse found basic base64 auth data of " << buf );
Data auth = buf.base64decode();
//DebugLog (<< "parse found basic auth data of " << auth );
ParseBuffer p(auth);
const char* a1 = p.position();
p.skipToChar(':');
user = p.data(a1);
const char* a2 = p.skipChar(':');
p.skipToEnd();
password = p.data(a2);
//DebugLog (<< "parse found basic auth data with user=" << user
// << " password=" << password );
}
}
}
catch ( ... )
{
ErrLog (<< "Some problem finding Authorization header in HTTP request" );
}
mHttpBase.buildPage(uri,mPageNumber,user,password);
}
bool
HttpConnection::processSomeWrites()
{
if ( mTxBuffer.empty() )
{
return true;
}
//DebugLog (<< "Writing " << mTxBuffer );
#if defined(WIN32)
int bytesWritten = ::send( mSock, mTxBuffer.data(), (int)mTxBuffer.size(), 0);
#else
int bytesWritten = ::write(mSock, mTxBuffer.data(), mTxBuffer.size() );
#endif
if (bytesWritten == INVALID_SOCKET)
{
int e = getErrno();
InfoLog (<< "HttpConnection failed write on " << mSock << " " << strerror(e));
return false;
}
if (bytesWritten == (int)mTxBuffer.size() )
{
DebugLog (<< "Wrote it all" );
mTxBuffer = Data::Empty;
return false; // return false causes connection to close and clean up
}
else
{
Data rest = mTxBuffer.substr(bytesWritten);
mTxBuffer = rest;
DebugLog( << "Wrote " << bytesWritten << " bytes - still need to do " << mTxBuffer );
}
return true;
}
/* ====================================================================
* The Vovida Software License, Version 1.0
*
* Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The names "VOCAL", "Vovida Open Communication Application Library",
* and "Vovida Open Communication Application Library (VOCAL)" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact vocal@vovida.org.
*
* 4. Products derived from this software may not be called "VOCAL", nor
* may "VOCAL" appear in their name, without prior written
* permission of Vovida Networks, Inc.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
* NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
* IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* ====================================================================
*
* This software consists of voluntary contributions made by Vovida
* Networks, Inc. and many individuals on behalf of Vovida Networks,
* Inc. For more information on Vovida Networks, Inc., please see
* <http://www.vovida.org/>.
*
*/

View File

@@ -0,0 +1,97 @@
#if !defined(HttpConnection_hxx)
#define HttpConnection_hxx
#include <rutil/Data.hxx>
#include <rutil/Socket.hxx>
#include <rutil/TransportType.hxx>
#include <resip/stack/Tuple.hxx>
#include <resip/stack/Mime.hxx>
#include "HttpBase.hxx"
namespace clicktocall
{
class HttpConnection
{
friend class HttpBase;
public:
HttpConnection( HttpBase& webAdmin, resip::Socket pSock );
~HttpConnection();
void buildFdSet(resip::FdSet& fdset);
bool process(resip::FdSet& fdset);
void setPage(const resip::Data& page,
int response,
const resip::Mime& pType );
private:
bool processSomeReads();
bool processSomeWrites();
void tryParse();
HttpBase& mHttpBase;
const int mPageNumber;
static int nextPageNumber;
resip::Socket mSock;
resip::Data mRxBuffer;
resip::Data mTxBuffer;
bool mParsedRequest;
};
}
#endif
/* ====================================================================
* The Vovida Software License, Version 1.0
*
* Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The names "VOCAL", "Vovida Open Communication Application Library",
* and "Vovida Open Communication Application Library (VOCAL)" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact vocal@vovida.org.
*
* 4. Products derived from this software may not be called "VOCAL", nor
* may "VOCAL" appear in their name, without prior written
* permission of Vovida Networks, Inc.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
* NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
* IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* ====================================================================
*
* This software consists of voluntary contributions made by Vovida
* Networks, Inc. and many individuals on behalf of Vovida Networks,
* Inc. For more information on Vovida Networks, Inc., please see
* <http://www.vovida.org/>.
*
*/

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,271 @@
#if !defined(Server_hxx)
#define Server_hxx
#include <map>
#include <resip/stack/TransactionUser.hxx>
#include <resip/stack/EventStackThread.hxx>
#include <resip/stack/UdpTransport.hxx>
#include <resip/dum/MasterProfile.hxx>
#include <resip/dum/DumShutdownHandler.hxx>
#include <resip/dum/DialogUsageManager.hxx>
#include <resip/dum/InviteSessionHandler.hxx>
#include <resip/dum/DialogSetHandler.hxx>
#include <resip/dum/OutOfDialogHandler.hxx>
#include <resip/dum/RedirectHandler.hxx>
#include <resip/dum/SubscriptionHandler.hxx>
#include <rutil/Log.hxx>
#include <rutil/Mutex.hxx>
#include "ConfigParser.hxx"
#include "B2BSession.hxx"
#include "AddressTranslator.hxx"
#include "WebAdmin.hxx"
#include "WebAdminThread.hxx"
#include "XmlRpcServer.hxx"
#include "XmlRpcServerThread.hxx"
#include <memory>
#ifdef WIN32
#define sleepMs(t) Sleep(t)
#else
#define sleepMs(t) usleep(t*1000)
#endif
namespace clicktocall
{
class ShutdownCmd;
class B2BSession;
class Server : public ConfigParser,
public resip::DumShutdownHandler,
public resip::InviteSessionHandler,
public resip::DialogSetHandler,
public resip::OutOfDialogHandler,
public resip::RedirectHandler,
public resip::ClientSubscriptionHandler,
public resip::ServerSubscriptionHandler
{
public:
Server(int argc, char** argv);
virtual ~Server();
/**
Starts the SIP stack thread.
@note This should be called before calling process() in a loop
*/
void startup();
/**
This should be called in a loop to give process cycles to the server.
@param timeoutMs Will return after timeoutMs if nothing to do.
Application can do some work, but should call
process again ASAP.
*/
void process(int timeoutMs); // call this in a loop
/**
Used to initiate a shutdown of the server. This function blocks
until the shutdown is complete.
@note There should not be an active process request when this
is called.
*/
void shutdown();
// Utility Methods ////////////////////////////////////////////////////////////
typedef enum
{
SubsystemAll,
SubsystemContents,
SubsystemDns,
SubsystemDum,
SubsystemSdp,
SubsystemSip,
SubsystemTransaction,
SubsystemTransport,
SubsystemStats,
SubsystemClickToCall
} LoggingSubsystem;
/**
Static method that sets the logging level for a particular subsystem,
or all subsystems.
@param level Logging level to set
@param subsystem Subsystem to set level on
@note: Use Server::SubsystemAll to set the logging level on all
subsystems
*/
static void setLogLevel(resip::Log::Level level, LoggingSubsystem subsystem=SubsystemAll);
/**
Click-To-Call - Requests server to place a call first to the initiator, once the initiator
answers the call the destination is contacted. If anchorCall is true, then the server
stays in the call path (B2BUA). If anchorCall is false then a REFER message is sent
to the initiator once answered, to direct the endpoint to the destination outside of
this server.
@param initiator First party contacted
@param destination Second part contacted
@param anchorCall Set to true to keep server in call path
@param xmlRpcInfo Set to non-zero if request was received from XML RPC interface - used for progress notification
*/
void clickToCall(const resip::Uri& initiator, const resip::Uri& destination, bool anchorCall, XmlRpcInfo* xmlRpcServer = 0);
bool translateAddress(const resip::Data& address, resip::Data& translation, bool failIfNoRule=false);
protected:
std::shared_ptr<resip::MasterProfile>& getMasterProfile() noexcept { return mProfile; }
// Shutdown Handler ////////////////////////////////////////////////////////////
void onDumCanBeDeleted();
// Invite Session Handler /////////////////////////////////////////////////////
virtual void onNewSession(resip::ClientInviteSessionHandle h, resip::InviteSession::OfferAnswerType oat, const resip::SipMessage& msg);
virtual void onNewSession(resip::ServerInviteSessionHandle h, resip::InviteSession::OfferAnswerType oat, const resip::SipMessage& msg);
virtual void onFailure(resip::ClientInviteSessionHandle h, const resip::SipMessage& msg);
virtual void onEarlyMedia(resip::ClientInviteSessionHandle, const resip::SipMessage&, const resip::SdpContents&);
virtual void onProvisional(resip::ClientInviteSessionHandle, const resip::SipMessage& msg);
virtual void onConnected(resip::ClientInviteSessionHandle h, const resip::SipMessage& msg);
virtual void onConnected(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual void onStaleCallTimeout(resip::ClientInviteSessionHandle);
virtual void onTerminated(resip::InviteSessionHandle h, resip::InviteSessionHandler::TerminatedReason reason, const resip::SipMessage* msg);
virtual void onRedirected(resip::ClientInviteSessionHandle, const resip::SipMessage& msg);
virtual void onAnswer(resip::InviteSessionHandle, const resip::SipMessage& msg, const resip::SdpContents&);
virtual void onOffer(resip::InviteSessionHandle handle, const resip::SipMessage& msg, const resip::SdpContents& offer);
virtual void onOfferRequired(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual void onOfferRejected(resip::InviteSessionHandle, const resip::SipMessage* msg);
virtual void onOfferRequestRejected(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual void onRemoteSdpChanged(resip::InviteSessionHandle, const resip::SipMessage& msg, const resip::SdpContents& sdp);
virtual void onInfo(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual void onInfoSuccess(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual void onInfoFailure(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual void onRefer(resip::InviteSessionHandle, resip::ServerSubscriptionHandle, const resip::SipMessage& msg);
virtual void onReferAccepted(resip::InviteSessionHandle, resip::ClientSubscriptionHandle, const resip::SipMessage& msg);
virtual void onReferRejected(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual void onReferNoSub(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual void onMessage(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual void onMessageSuccess(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual void onMessageFailure(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual void onForkDestroyed(resip::ClientInviteSessionHandle);
// DialogSetHandler //////////////////////////////////////////////
virtual void onTrying(resip::AppDialogSetHandle, const resip::SipMessage& msg);
virtual void onNonDialogCreatingProvisional(resip::AppDialogSetHandle, const resip::SipMessage& msg);
// ClientSubscriptionHandler ///////////////////////////////////////////////////
virtual void onUpdatePending(resip::ClientSubscriptionHandle h, const resip::SipMessage& notify, bool outOfOrder);
virtual void onUpdateActive(resip::ClientSubscriptionHandle h, const resip::SipMessage& notify, bool outOfOrder);
virtual void onUpdateExtension(resip::ClientSubscriptionHandle, const resip::SipMessage& notify, bool outOfOrder);
virtual void onNotifyNotReceived(resip::ClientSubscriptionHandle h);
virtual void onTerminated(resip::ClientSubscriptionHandle h, const resip::SipMessage* notify);
virtual void onNewSubscription(resip::ClientSubscriptionHandle h, const resip::SipMessage& notify);
virtual int onRequestRetry(resip::ClientSubscriptionHandle h, int retryMinimum, const resip::SipMessage& notify);
// ServerSubscriptionHandler ///////////////////////////////////////////////////
virtual void onNewSubscription(resip::ServerSubscriptionHandle, const resip::SipMessage& sub);
virtual void onNewSubscriptionFromRefer(resip::ServerSubscriptionHandle, const resip::SipMessage& sub);
virtual void onRefresh(resip::ServerSubscriptionHandle, const resip::SipMessage& sub);
virtual void onTerminated(resip::ServerSubscriptionHandle);
virtual void onNotifyRejected(resip::ServerSubscriptionHandle, const resip::SipMessage& msg);
virtual void onError(resip::ServerSubscriptionHandle, const resip::SipMessage& msg);
virtual void onExpiredByClient(resip::ServerSubscriptionHandle, const resip::SipMessage& sub, resip::SipMessage& notify);
virtual void onExpired(resip::ServerSubscriptionHandle, resip::SipMessage& notify);
virtual bool hasDefaultExpires() const;
virtual uint32_t getDefaultExpires() const;
// OutOfDialogHandler //////////////////////////////////////////////////////////
virtual void onSuccess(resip::ClientOutOfDialogReqHandle, const resip::SipMessage& response);
virtual void onFailure(resip::ClientOutOfDialogReqHandle, const resip::SipMessage& response);
virtual void onReceivedRequest(resip::ServerOutOfDialogReqHandle, const resip::SipMessage& request);
// RedirectHandler /////////////////////////////////////////////////////////////
virtual void onRedirectReceived(resip::AppDialogSetHandle, const resip::SipMessage& response);
virtual bool onTryingNextTarget(resip::AppDialogSetHandle, const resip::SipMessage& request);
private:
friend class ShutdownCmd;
friend class B2BSession;
resip::DialogUsageManager& getDialogUsageManager();
void post(resip::ApplicationMessage& message, unsigned int ms=0);
void shutdownImpl();
friend class ClickToCallCmd;
void clickToCallImpl(const resip::Uri& initiator, const resip::Uri& destination, bool anchorCall, const XmlRpcInfo& xmlRpcInfo);
std::shared_ptr<resip::MasterProfile> mProfile;
resip::Security* mSecurity;
resip::FdPollGrp *mPollGrp;
resip::EventThreadInterruptor *mEventInterruptor;
resip::SipStack mStack;
resip::DialogUsageManager mDum;
resip::EventStackThread mStackThread;
volatile bool mDumShutdown;
typedef std::map<B2BSessionHandle, B2BSession*> B2BSessionMap;
B2BSessionMap mB2BSessions;
B2BSessionHandle mCurrentB2BSessionHandle;
B2BSession* getB2BSession(const B2BSessionHandle& handle) const;
B2BSessionHandle registerB2BSession(B2BSession *);
void unregisterB2BSession(const B2BSessionHandle& handle);
bool mIsV6Avail;
WebAdmin* mWebAdminV4;
WebAdmin* mWebAdminV6;
WebAdminThread* mWebAdminThread;
XmlRpcServer* mXmlRpcServerV4;
XmlRpcServer* mXmlRpcServerV6;
XmlRpcServerThread* mXmlRpcServerThread;
AddressTranslator mAddressTranslator;
std::map<resip::DialogSetId,B2BSession*> mActiveSessions;
};
}
#endif
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

View File

@@ -0,0 +1,36 @@
#define CLICKTOCALL_VERSION_STRING "0.1"
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

View File

@@ -0,0 +1,331 @@
#include "rutil/ResipAssert.h"
#include <time.h>
#include <resip/stack/Symbols.hxx>
#include <resip/stack/Tuple.hxx>
#include <rutil/Data.hxx>
#include <rutil/DnsUtil.hxx>
#include <rutil/Logger.hxx>
#include <rutil/MD5Stream.hxx>
#include <rutil/ParseBuffer.hxx>
#include <rutil/Socket.hxx>
#include <rutil/Timer.hxx>
#include <rutil/TransportType.hxx>
#include "AppSubsystem.hxx"
#include "HttpBase.hxx"
#include "HttpConnection.hxx"
#include "WebAdmin.hxx"
#include "Server.hxx"
using namespace clicktocall;
using namespace resip;
using namespace std;
#define RESIPROCATE_SUBSYSTEM AppSubsystem::CLICKTOCALL
WebAdmin::WebAdmin(Server& server,
bool noChal,
const Data& realm, // this realm is used for http challenges
const Data& adminPassword,
int port,
IpVersion version ):
HttpBase(port, version, realm),
mServer(server),
mNoWebChallenges(noChal),
mAdminPassword(adminPassword)
{
}
void
WebAdmin::buildPage( const Data& uri,
int pageNumber,
const resip::Data& pUser,
const resip::Data& pPassword )
{
ParseBuffer pb(uri);
DebugLog (<< "Parsing URL" << uri );
const char* anchor = pb.skipChar('/');
pb.skipToChar('?');
Data pageName;
pb.data(pageName,anchor);
DebugLog (<< " got page name: " << pageName );
// if this is not a valid page, redirect it
if (pageName != Data("index.html") &&
pageName != Data("clicktocall.html"))
{
setPage( resip::Data::Empty, pageNumber, 301 );
return;
}
// pages anyone can use
if ( pageName == Data("index.html") )
{
setPage( buildDefaultPage(), pageNumber, 200);
return;
}
Data authenticatedUser;
if (mNoWebChallenges)
{
// don't do authentication - give everyone admin privilages
authenticatedUser = Data("admin");
}
else
{
// all pages after this, user must authenticate
if ( pUser.empty() )
{
setPage( resip::Data::Empty, pageNumber,401 );
return;
}
MD5Stream dba1;
dba1 << "admin" // username
<< Symbols::COLON
<< Data::Empty // realm
<< Symbols::COLON
<< mAdminPassword;
Data dbA1 = dba1.getHex();
if ( !dbA1.empty() )
{
MD5Stream a1;
a1 << pUser // username
<< Symbols::COLON
<< Data::Empty // realm
<< Symbols::COLON
<< pPassword;
Data compA1 = a1.getHex();
if ( dbA1 == compA1 )
{
authenticatedUser = pUser;
}
else
{
InfoLog( << "user " << pUser << " failed to authenticate to web server" );
DebugLog( << " compA1="<<compA1<< " dbA1="<<dbA1 );
setPage( resip::Data::Empty, pageNumber,401 );
return;
}
}
else //No A1, so we must assume this user does not exist.
{
setPage( "User does not exist.", pageNumber,401 );
return;
}
}
// parse any URI tags from form entry
mHttpParams.clear();
if (!pb.eof())
{
pb.skipChar('?');
while ( !pb.eof() )
{
const char* anchor1 = pb.position();
pb.skipToChar('=');
Data key;
pb.data(key,anchor1);
const char* anchor2 = pb.skipChar('=');
pb.skipToChar('&');
Data value;
pb.data(value,anchor2);
if ( !pb.eof() )
{
pb.skipChar('&');
}
if ( !key.empty() && !value.empty() ) // make sure both exist
{
DebugLog (<< " key=" << key << " value=" << value << " & unencoded form: " << value.urlDecoded() );
mHttpParams[key] = value.urlDecoded(); // add other parameters to the Map
}
}
}
DebugLog( << "building page for user=" << authenticatedUser );
Data page;
if ( authenticatedUser == Data("admin") )
{
DataStream s(page);
buildPageOutlinePre(s);
// admin only pages
if ( pageName == Data("clicktocall.html")) buildClickToCallPage(s);
buildPageOutlinePost(s);
s.flush();
}
resip_assert( !authenticatedUser.empty() );
resip_assert( !page.empty() );
setPage( page, pageNumber,200 );
}
Data
WebAdmin::buildDefaultPage()
{
Data ret;
{
DataStream s(ret);
s <<
"<?xml version=\"1.0\" encoding=\"utf-8\"?>" << endl <<
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">" << endl <<
"<html xmlns=\"http://www.w3.org/1999/xhtml\">" << endl <<
"<head>" << endl <<
"<meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\" />" << endl <<
"<title>ClickToCall Server Login</title>" << endl <<
"</head>" << endl <<
"<body bgcolor=\"#ffffff\">" << endl <<
" <p>Click-To-Call HTML Server</p>" << endl <<
"</body>" << endl <<
"</html>" << endl;
s.flush();
}
return ret;
}
void
WebAdmin::buildPageOutlinePre(DataStream& s)
{
s <<
"<?xml version=\"1.0\" encoding=\"utf-8\"?>" << endl <<
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">" << endl <<
"<html xmlns=\"http://www.w3.org/1999/xhtml\">" << endl <<
"<head>" << endl <<
"<meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\" />" << endl <<
"<title>ClickToCall Server</title>" << endl <<
"</head>" << endl <<
"<body bgcolor=\"#ffffff\">" << endl;
}
void
WebAdmin::buildPageOutlinePost(DataStream& s)
{
s << "</body>" << endl <<
"</html>" << endl;
}
void
WebAdmin::buildClickToCallPage(DataStream& s)
{
Data initiator;
Data destination;
bool anchor = false;
Dictionary::iterator pos;
pos = mHttpParams.find("initiator");
if (pos != mHttpParams.end())
{
initiator = pos->second;
}
pos = mHttpParams.find("destination");
if (pos != mHttpParams.end())
{
destination = pos->second;
}
pos = mHttpParams.find("anchor");
if (pos != mHttpParams.end())
{
if(isEqualNoCase(pos->second, "true"))
{
anchor = true;
}
}
s << "<p><em>ClickToCall:</em> initiator=" << initiator << ", destination=" << destination << (anchor ? " (anchored)" : "") << "</p>" << endl;
if(!initiator.empty() && !destination.empty())
{
Data initiatorTranslation;
Data destinationTranslation;
if(mServer.translateAddress(initiator, initiatorTranslation, true /* fail if no rule */) &&
mServer.translateAddress(destination, destinationTranslation, true /* fail if no rule */))
{
try
{
Uri initiatorUri(initiatorTranslation);
Uri destinationUri(destinationTranslation);
mServer.clickToCall(initiatorUri, destinationUri, anchor);
s << "<p>Initiating ClickToCall from " << initiatorUri << "(" << initiator << ") to " << destinationUri << "(" << destination << (anchor ? ") (anchored)" : ") (unanchored)") << "...</p>" << endl;
}
catch(resip::BaseException& e)
{
s << "<p>Invalid URI format in initiator " << initiatorTranslation << "(" << initiator << ") or destination " << destinationTranslation << "(" << destination << "): " << e << "</p>" << endl;
}
}
else
{
s << "<p>No translation rule for either initiator " << initiator << " or destination " << destination << ".</p>" << endl;
}
}
else
{
s << "<p>Missing initiator or destination URL parameters.</p>" << endl;
}
}
/* ====================================================================
* The Vovida Software License, Version 1.0
*
* Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The names "VOCAL", "Vovida Open Communication Application Library",
* and "Vovida Open Communication Application Library (VOCAL)" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact vocal@vovida.org.
*
* 4. Products derived from this software may not be called "VOCAL", nor
* may "VOCAL" appear in their name, without prior written
* permission of Vovida Networks, Inc.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
* NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
* IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* ====================================================================
*/

View File

@@ -0,0 +1,106 @@
#if !defined(WebAdmin_hxx)
#define WebAdmin_hxx
#include <map>
#include <rutil/Data.hxx>
#include <rutil/TransportType.hxx>
#include <resip/stack/Tuple.hxx>
#include "HttpBase.hxx"
namespace resip
{
class DataStream;
}
namespace clicktocall
{
class Server;
typedef std::map<resip::Data, resip::Data> Dictionary;
class WebAdmin: public HttpBase
{
public:
WebAdmin(Server& server,
bool noWebChallenges,
const resip::Data& realm,
const resip::Data& adminPassword,
int port=5090,
resip::IpVersion version=resip::V4);
protected:
virtual void buildPage( const resip::Data& uri,
int pageNumber,
const resip::Data& user,
const resip::Data& password);
private:
resip::Data buildDefaultPage();
void buildPageOutlinePre(resip::DataStream& s);
void buildPageOutlinePost(resip::DataStream& s);
void buildClickToCallPage(resip::DataStream& s);
Server& mServer;
bool mNoWebChallenges;
resip::Data mAdminPassword;
Dictionary mHttpParams;
};
}
#endif
/* ====================================================================
* The Vovida Software License, Version 1.0
*
* Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The names "VOCAL", "Vovida Open Communication Application Library",
* and "Vovida Open Communication Application Library (VOCAL)" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact vocal@vovida.org.
*
* 4. Products derived from this software may not be called "VOCAL", nor
* may "VOCAL" appear in their name, without prior written
* permission of Vovida Networks, Inc.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
* NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
* IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* ====================================================================
*
* This software consists of voluntary contributions made by Vovida
* Networks, Inc. and many individuals on behalf of Vovida Networks,
* Inc. For more information on Vovida Networks, Inc., please see
* <http://www.vovida.org/>.
*
*/

View File

@@ -0,0 +1,99 @@
#include <rutil/Socket.hxx>
#include <rutil/Logger.hxx>
#include "AppSubsystem.hxx"
#include "WebAdmin.hxx"
#include "WebAdminThread.hxx"
#define RESIPROCATE_SUBSYSTEM AppSubsystem::CLICKTOCALL
using namespace clicktocall;
using namespace resip;
using namespace std;
WebAdminThread::WebAdminThread(const std::list<WebAdmin*>& webAdminList)
: mWebAdminList(webAdminList)
{
}
void
WebAdminThread::thread()
{
while (!isShutdown())
{
try
{
FdSet fdset;
std::list<WebAdmin*>::iterator it = mWebAdminList.begin();
for(;it!=mWebAdminList.end();it++)
{
(*it)->buildFdSet(fdset);
}
fdset.selectMilliSeconds( 10*1000 );
it = mWebAdminList.begin();
for(;it!=mWebAdminList.end();it++)
{
(*it)->process(fdset);
}
}
catch (...)
{
ErrLog (<< "Unhandled exception: " );
}
}
}
/* ====================================================================
* The Vovida Software License, Version 1.0
*
* Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The names "VOCAL", "Vovida Open Communication Application Library",
* and "Vovida Open Communication Application Library (VOCAL)" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact vocal@vovida.org.
*
* 4. Products derived from this software may not be called "VOCAL", nor
* may "VOCAL" appear in their name, without prior written
* permission of Vovida Networks, Inc.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
* NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
* IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* ====================================================================
*
* This software consists of voluntary contributions made by Vovida
* Networks, Inc. and many individuals on behalf of Vovida Networks,
* Inc. For more information on Vovida Networks, Inc., please see
* <http://www.vovida.org/>.
*
*/

View File

@@ -0,0 +1,77 @@
#if !defined(WebAdminThread_hxx)
#define WebAdminThread_hxx
#include <list>
#include <rutil/ThreadIf.hxx>
#include <rutil/Socket.hxx>
namespace clicktocall
{
class WebAdmin;
class WebAdminThread : public resip::ThreadIf
{
public:
WebAdminThread(const std::list<WebAdmin*>& webAdminList);
protected:
private:
virtual void thread();
std::list<WebAdmin*> mWebAdminList;
};
}
#endif
/* ====================================================================
* The Vovida Software License, Version 1.0
*
* Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The names "VOCAL", "Vovida Open Communication Application Library",
* and "Vovida Open Communication Application Library (VOCAL)" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact vocal@vovida.org.
*
* 4. Products derived from this software may not be called "VOCAL", nor
* may "VOCAL" appear in their name, without prior written
* permission of Vovida Networks, Inc.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
* NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
* IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* ====================================================================
*
* This software consists of voluntary contributions made by Vovida
* Networks, Inc. and many individuals on behalf of Vovida Networks,
* Inc. For more information on Vovida Networks, Inc., please see
* <http://www.vovida.org/>.
*
*/

View File

@@ -0,0 +1,298 @@
#include "rutil/ResipAssert.h"
#include <rutil/Data.hxx>
#include <rutil/Socket.hxx>
#include <resip/stack/Symbols.hxx>
#include <rutil/TransportType.hxx>
#include <rutil/Logger.hxx>
#include <resip/stack/Tuple.hxx>
#include <rutil/DnsUtil.hxx>
#include <rutil/ParseBuffer.hxx>
#include "Version.hxx"
#include "AppSubsystem.hxx"
#include "Server.hxx"
#include "XmlRpcServerBase.hxx"
#include "XmlRpcConnection.hxx"
using namespace clicktocall;
using namespace resip;
using namespace std;
#define RESIPROCATE_SUBSYSTEM AppSubsystem::CLICKTOCALL
unsigned int XmlRpcConnection::NextConnectionId = 1;
XmlRpcConnection::XmlRpcConnection(XmlRpcServerBase& server, resip::Socket sock):
mXmlRcpServer(server),
mConnectionId(NextConnectionId++),
mNextRequestId(1),
mSock(sock)
{
resip_assert(mSock > 0);
}
XmlRpcConnection::~XmlRpcConnection()
{
resip_assert(mSock > 0);
#ifdef WIN32
closesocket(mSock);
#else
close(mSock);
#endif
mSock=0;
}
void
XmlRpcConnection::buildFdSet(FdSet& fdset)
{
if (!mTxBuffer.empty())
{
fdset.setWrite(mSock);
}
fdset.setRead(mSock);
}
bool
XmlRpcConnection::process(FdSet& fdset)
{
if (fdset.hasException(mSock))
{
int errNum = 0;
int errNumSize = sizeof(errNum);
getsockopt(mSock,SOL_SOCKET,SO_ERROR,(char *)&errNum,(socklen_t *)&errNumSize);
InfoLog (<< "XmlRpcConnection::process: Exception reading from socket "
<< (int)mSock << " code: " << errNum << "; closing connection");
return false;
}
if (fdset.readyToRead(mSock))
{
bool ok = processSomeReads();
if (!ok)
{
return false;
}
}
if ((!mTxBuffer.empty()) && fdset.readyToWrite(mSock))
{
bool ok = processSomeWrites();
if (!ok)
{
return false;
}
}
return true;
}
bool
XmlRpcConnection::processSomeReads()
{
const int bufSize = 8000;
char buf[bufSize];
#if defined(WIN32)
int bytesRead = ::recv(mSock, buf, bufSize, 0);
#else
int bytesRead = ::read(mSock, buf, bufSize);
#endif
if (bytesRead == INVALID_SOCKET)
{
int e = getErrno();
XmlRpcServerBase::logSocketError(e);
InfoLog (<< "XmlRpcConnection::processSomeReads: Failed read on " << (int)mSock);
return false;
}
else if(bytesRead == 0)
{
InfoLog (<< "XmlRpcConnection::processSomeReads: Connection closed by remote");
return false;
}
//DebugLog (<< "XmlRpcConnection::processSomeReads: read=" << bytesRead);
mRxBuffer += Data( buf, bytesRead );
while(tryParse());
return true;
}
bool
XmlRpcConnection::tryParse()
{
ParseBuffer pb(mRxBuffer);
Data initialTag;
const char* start = pb.position();
pb.skipWhitespace();
pb.skipToChar('<');
if(!pb.eof())
{
pb.skipChar();
const char* anchor = pb.position();
pb.skipToChar('>');
if(!pb.eof())
{
initialTag = pb.data(anchor);
// Find end of initial tag
pb.skipToChars("</" + initialTag + ">");
if (!pb.eof())
{
pb.skipN(initialTag.size() + 3); // Skip past </InitialTag>
mRequests[mNextRequestId] = pb.data(start);
mXmlRcpServer.handleRequest(mConnectionId, mNextRequestId, mRequests[mNextRequestId]);
mNextRequestId++;
// Remove processed data from RxBuffer
pb.skipWhitespace();
if(!pb.eof())
{
anchor = pb.position();
pb.skipToEnd();
mRxBuffer = pb.data(anchor);
return true;
}
else
{
mRxBuffer.clear();
}
}
}
}
return false;
}
bool
XmlRpcConnection::processSomeWrites()
{
if (mTxBuffer.empty())
{
return true;
}
//DebugLog (<< "XmlRpcConnection::processSomeWrites: Writing " << mTxBuffer );
#if defined(WIN32)
int bytesWritten = ::send(mSock, mTxBuffer.data(), (int)mTxBuffer.size(), 0);
#else
int bytesWritten = ::write(mSock, mTxBuffer.data(), mTxBuffer.size() );
#endif
if (bytesWritten == INVALID_SOCKET)
{
int e = getErrno();
XmlRpcServerBase::logSocketError(e);
InfoLog (<< "XmlRpcConnection::processSomeWrites - failed write on " << mSock << " " << strerror(e));
return false;
}
if (bytesWritten == (int)mTxBuffer.size())
{
DebugLog (<< "XmlRpcConnection::processSomeWrites - Wrote it all" );
mTxBuffer = Data::Empty;
//return false; // return false causes connection to close and clean up
return true; // keep connection up
}
else
{
Data rest = mTxBuffer.substr(bytesWritten);
mTxBuffer = rest;
DebugLog( << "XmlRpcConnection::processSomeWrites - Wrote " << bytesWritten << " bytes - still need to do " << mTxBuffer );
}
return true;
}
bool
XmlRpcConnection::sendResponse(unsigned int requestId, const Data& responseData, bool isFinal)
{
RequestMap::iterator it = mRequests.find(requestId);
if(it != mRequests.end())
{
Data& request = it->second;
Data response(request.size() + responseData.size() + 30, Data::Preallocate);
ParseBuffer pb(request);
// A response is formed by starting with the request and inserting the
// ResponseData between <Response> tags at the same level as the <Request> tags
const char* start = pb.position();
pb.skipToChars("</Request>");
if (!pb.eof())
{
pb.skipN(10); // Skip past </Request>
pb.skipWhitespace();
// Response starts with request message up to end of Request tag
response = pb.data(start);
// Add in response data
response += Symbols::CRLF;
response += " <Response>" + responseData + " </Response>";
response += Symbols::CRLF;
// Add remainder of request message
start = pb.position();
pb.skipToEnd();
response += pb.data(start);
}
else
{
// No Request in message - just send bare response
response = "<Response>" + responseData + "</Response>";
}
mTxBuffer += response;
if(isFinal)
{
mRequests.erase(it);
}
return true;
}
return false;
}
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

View File

@@ -0,0 +1,84 @@
#if !defined(XmlRpcConnection_hxx)
#define XmlRpcConnection_hxx
#include <map>
#include <rutil/Data.hxx>
#include <rutil/Socket.hxx>
#include <rutil/TransportType.hxx>
#include <resip/stack/Tuple.hxx>
#include "XmlRpcServerBase.hxx"
namespace clicktocall
{
class XmlRpcConnection
{
friend class XmlRpcServerBase;
public:
XmlRpcConnection(XmlRpcServerBase& server, resip::Socket sock);
virtual ~XmlRpcConnection();
unsigned int getConnectionId() const { return mConnectionId; }
void buildFdSet(resip::FdSet& fdset);
bool process(resip::FdSet& fdset);
virtual bool sendResponse(unsigned int requestId, const resip::Data& responseData, bool isFinal);
private:
bool processSomeReads();
bool processSomeWrites();
bool tryParse(); // returns true if we processed something and there is more data in the buffer
XmlRpcServerBase& mXmlRcpServer;
const unsigned int mConnectionId;
static unsigned int NextConnectionId;
unsigned int mNextRequestId;
typedef std::map<unsigned int, resip::Data> RequestMap;
RequestMap mRequests;
resip::Socket mSock;
resip::Data mRxBuffer;
resip::Data mTxBuffer;
};
}
#endif
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

View File

@@ -0,0 +1,202 @@
#include "rutil/ResipAssert.h"
#include <sstream>
#include <resip/stack/Symbols.hxx>
#include <resip/stack/Tuple.hxx>
#include <rutil/Data.hxx>
#include <rutil/DnsUtil.hxx>
#include <rutil/Logger.hxx>
#include <rutil/ParseBuffer.hxx>
#include <rutil/Socket.hxx>
#include <rutil/TransportType.hxx>
#include "AppSubsystem.hxx"
#include "XmlRpcServerBase.hxx"
#include "XmlRpcConnection.hxx"
#include "XmlRpcServer.hxx"
#include "Server.hxx"
using namespace clicktocall;
using namespace resip;
using namespace std;
#define RESIPROCATE_SUBSYSTEM AppSubsystem::CLICKTOCALL
XmlRpcServer::XmlRpcServer(Server& server,
int port,
IpVersion version ) :
XmlRpcServerBase(port, version),
mServer(server)
{
}
void
XmlRpcServer::sendResponse(unsigned int connectionId,
unsigned int requestId,
const Data& responseData,
unsigned int resultCode,
const Data& resultText,
const Data& leg)
{
std::stringstream ss;
ss << Symbols::CRLF << responseData << " <Result Code=\"" << resultCode << "\"";
if(!leg.empty())
{
ss << " Leg=\"" << leg << "\"";
}
ss << ">" << resultText << "</Result>" << Symbols::CRLF;
bool isFinal = resultCode >= 300 || (leg=="Destination" && resultCode >= 200);
XmlRpcServerBase::sendResponse(connectionId, requestId, ss.str().c_str(), isFinal);
}
void
XmlRpcServer::handleRequest(unsigned int connectionId, unsigned int requestId, const resip::Data& request)
{
InfoLog (<< "XmlRpcServer::handleRequest: connectionId=" << connectionId << ", requestId=" << requestId << ", request=" << request);
try
{
ParseBuffer pb(request);
XMLCursor xml(pb);
if(isEqualNoCase(xml.getTag(), "ClickToCall"))
{
handleClickToCallRequest(connectionId, requestId, xml);
}
else
{
InfoLog(<< "XmlRpcServer::handleRequest: Received XML message with unknown method: " << xml.getTag());
sendResponse(connectionId, requestId, Data::Empty, 400, "Unknown method");
}
}
catch(resip::BaseException& e)
{
InfoLog(<< "XmlRpcServer::handleRequest: ParseException: " << e);
sendResponse(connectionId, requestId, Data::Empty, 400, "Parse error");
}
}
void
XmlRpcServer::handleClickToCallRequest(unsigned int connectionId, unsigned int requestId, XMLCursor& xml)
{
Data initiator;
Data destination;
bool anchor = false;
if(xml.firstChild())
{
if(isEqualNoCase(xml.getTag(), "Request"))
{
if(xml.firstChild())
{
do
{
if(isEqualNoCase(xml.getTag(), "Initiator"))
{
if(xml.firstChild())
{
initiator = xml.getValue();
xml.parent();
}
}
else if(isEqualNoCase(xml.getTag(), "Destination"))
{
if(xml.firstChild())
{
destination = xml.getValue();
xml.parent();
}
}
else if(isEqualNoCase(xml.getTag(), "AnchorCall"))
{
if(xml.firstChild())
{
if(isEqualNoCase(xml.getValue(), "true"))
{
anchor = true;
}
xml.parent();
}
}
} while(xml.nextSibling());
xml.parent();
}
}
xml.parent();
}
if(!initiator.empty() && !destination.empty())
{
Data initiatorTranslation;
Data destinationTranslation;
if(mServer.translateAddress(initiator, initiatorTranslation, true /* fail if no rule */) &&
mServer.translateAddress(destination, destinationTranslation, true /* fail if no rule */))
{
try
{
Uri initiatorUri(initiatorTranslation);
Uri destinationUri(destinationTranslation);
XmlRpcInfo info(connectionId, requestId, this);
mServer.clickToCall(initiatorUri, destinationUri, anchor, &info);
std::stringstream ss;
ss << " <TranslatedInitiator>" << initiatorUri << "</TranslatedInitiator>" << Symbols::CRLF;
ss << " <TranslatedDestination>" << destinationUri << "</TranslatedDestination>" << Symbols::CRLF;
sendResponse(connectionId, requestId, ss.str().c_str(), 100, "In progress");
}
catch(resip::BaseException& e)
{
std::stringstream ss;
ss << "Invalid URI format in initiator " << initiatorTranslation << "(" << initiator << ") or destination " << destinationTranslation << "(" << destination << "): " << e;
sendResponse(connectionId, requestId, Data::Empty, 400, ss.str().c_str());
}
}
else
{
std::stringstream ss;
ss << "No translation rule for either initiator " << initiator << " or destination " << destination;
sendResponse(connectionId, requestId, Data::Empty, 400, ss.str().c_str());
}
}
else
{
sendResponse(connectionId, requestId, Data::Empty, 400, "Missing initiator and/or destination tags");
}
}
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

View File

@@ -0,0 +1,96 @@
#if !defined(XmlRpcServer_hxx)
#define XmlRpcServer_hxx
#include <rutil/Data.hxx>
#include <rutil/TransportType.hxx>
#include <resip/stack/Tuple.hxx>
#include <rutil/XMLCursor.hxx>
#include "XmlRpcServerBase.hxx"
namespace resip
{
class DataStream;
}
namespace clicktocall
{
class Server;
class XmlRpcServer;
class XmlRpcInfo
{
public:
XmlRpcInfo(unsigned int connectionId, unsigned int requestId, XmlRpcServer* xmlRpcServer) :
mConnectionId(connectionId), mRequestId(requestId), mXmlRpcServer(xmlRpcServer) {}
XmlRpcInfo() : mConnectionId(0), mRequestId(0), mXmlRpcServer(0) {}
unsigned int mConnectionId;
unsigned int mRequestId;
XmlRpcServer* mXmlRpcServer;
};
class XmlRpcServer: public XmlRpcServerBase
{
public:
XmlRpcServer(Server& server,
int port,
resip::IpVersion version);
// thread safe
virtual void sendResponse(unsigned int connectionId,
unsigned int requestId,
const resip::Data& responseData,
unsigned int resultCode,
const resip::Data& resultText,
const resip::Data& leg = resip::Data::Empty);
protected:
virtual void handleRequest(unsigned int connectionId,
unsigned int requestId,
const resip::Data& request);
private:
void handleClickToCallRequest(unsigned int connectionId, unsigned int requestId, resip::XMLCursor& xml);
Server& mServer;
};
}
#endif
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

View File

@@ -0,0 +1,395 @@
#include "rutil/ResipAssert.h"
#include <rutil/Data.hxx>
#include <rutil/Socket.hxx>
#include <resip/stack/Symbols.hxx>
#include <rutil/TransportType.hxx>
#include <rutil/Logger.hxx>
#include <resip/stack/Tuple.hxx>
#include <rutil/DnsUtil.hxx>
#include <rutil/ParseBuffer.hxx>
#include <resip/stack/Transport.hxx>
#include "AppSubsystem.hxx"
#include "XmlRpcServerBase.hxx"
#include "XmlRpcConnection.hxx"
#include <rutil/WinLeakCheck.hxx>
using namespace clicktocall;
using namespace resip;
using namespace std;
#define RESIPROCATE_SUBSYSTEM AppSubsystem::CLICKTOCALL
XmlRpcServerBase::XmlRpcServerBase(int port, IpVersion ipVer) :
mTuple(Data::Empty,port,ipVer,TCP,Data::Empty),
mSane(true)
{
#ifdef USE_IPV6
mFd = ::socket(ipVer == V4 ? PF_INET : PF_INET6, SOCK_STREAM, 0);
#else
mFd = ::socket(PF_INET, SOCK_STREAM, 0);
#endif
if (mFd == INVALID_SOCKET)
{
int e = getErrno();
logSocketError(e);
ErrLog(<< "XmlRpcServerBase::XmlRpcServerBase: Failed to create socket: " << strerror(e));
mSane = false;
return;
}
DebugLog (<< "XmlRpcServerBase::XmlRpcServerBase: Creating fd=" << (int)mFd
<< (ipVer == V4 ? " V4/" : " V6/") );
int on = 1;
#if !defined(WIN32)
if (::setsockopt(mFd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)))
#else
if (::setsockopt(mFd, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)))
#endif
{
int e = getErrno();
logSocketError(e);
ErrLog(<< "XmlRpcServerBase::XmlRpcServerBase: Couldn't set sockoptions SO_REUSEPORT | SO_REUSEADDR: " << strerror(e));
mSane = false;
return;
}
DebugLog(<< "XmlRpcServerBase::XmlRpcServerBase: Binding to " << Tuple::inet_ntop(mTuple));
if (::bind( mFd, &mTuple.getMutableSockaddr(), mTuple.length()) == SOCKET_ERROR)
{
int e = getErrno();
logSocketError(e);
if (e == EADDRINUSE)
{
ErrLog(<< "XmlRpcServerBase::XmlRpcServerBase: " << mTuple << " already in use ");
}
else
{
ErrLog(<< "XmlRpcServerBase::XmlRpcServerBase: Could not bind to " << mTuple);
}
mSane = false;
return;
}
bool ok = makeSocketNonBlocking(mFd);
if (!ok)
{
int e = getErrno();
logSocketError(e);
ErrLog(<< "XmlRpcServerBase::XmlRpcServerBase: Could not make HTTP socket non-blocking " << port);
mSane = false;
return;
}
// do the listen, seting the maximum queue size for compeletly established
// sockets -- on linux, tcp_max_syn_backlog should be used for the incomplete
// queue size(see man listen)
int e = listen(mFd,5);
if (e != 0)
{
int e = getErrno();
InfoLog(<< "XmlRpcServerBase::XmlRpcServerBase: Failed listen " << strerror(e));
mSane = false;
return;
}
}
XmlRpcServerBase::~XmlRpcServerBase()
{
#if defined(WIN32)
closesocket(mFd);
#else
close(mFd);
#endif
mFd = 0;
ConnectionMap::iterator it = mConnections.begin();
for(; it != mConnections.end(); it++)
{
delete it->second;
}
}
void
XmlRpcServerBase::buildFdSet(FdSet& fdset)
{
mSelectInterruptor.buildFdSet(fdset);
fdset.setRead(mFd); // listen socket for server
ConnectionMap::iterator it = mConnections.begin();
for(; it != mConnections.end(); it++)
{
it->second->buildFdSet(fdset);
}
}
void
XmlRpcServerBase::process(FdSet& fdset)
{
// Process Response fifo first
while (mResponseFifo.messageAvailable())
{
ResponseInfo* responseInfo = mResponseFifo.getNext();
ConnectionMap::iterator it = mConnections.find(responseInfo->getConnectionId());
if(it != mConnections.end())
{
it->second->sendResponse(responseInfo->getRequestId(), responseInfo->getResponseData(), responseInfo->getIsFinal());
delete responseInfo;
}
}
mSelectInterruptor.process(fdset);
if (fdset.readyToRead(mFd))
{
Tuple tuple(mTuple);
struct sockaddr& peer = tuple.getMutableSockaddr();
socklen_t peerLen = tuple.length();
Socket sock = accept( mFd, &peer, &peerLen);
if (sock == SOCKET_ERROR)
{
int e = getErrno();
switch (e)
{
case EWOULDBLOCK:
return;
default:
logSocketError(e);
ErrLog(<< "XmlRpcServerBase::process: Some error reading from socket: " << e);
}
return;
}
makeSocketNonBlocking(sock);
if(mConnections.size() == MaxConnections)
{
closeOldestConnection();
}
XmlRpcConnection* connection = new XmlRpcConnection(*this,sock);
mConnections[connection->getConnectionId()] = connection;
DebugLog (<< "XmlRpcServerBase::process: Received TCP connection as connection=" << connection->getConnectionId() << " fd=" << (int)sock);
}
// Call process on each connection
ConnectionMap::iterator it = mConnections.begin();
for(; it != mConnections.end(); )
{
bool ok = it->second->process(fdset);
if (!ok)
{
delete it->second;
mConnections.erase(it++);
}
else
{
it++;
}
}
}
void
XmlRpcServerBase::sendResponse(unsigned int connectionId,
unsigned int requestId,
const Data& responseData,
bool isFinal)
{
mResponseFifo.add(new ResponseInfo(connectionId, requestId, responseData, isFinal));
mSelectInterruptor.interrupt();
}
bool
XmlRpcServerBase::isSane()
{
return mSane;
}
void
XmlRpcServerBase::closeOldestConnection()
{
if(mConnections.empty()) return;
// Oldest Connection is the one with the lowest Id
ConnectionMap::iterator lowestConnectionIdIt = mConnections.end();
ConnectionMap::iterator it = mConnections.begin();
for(; it != mConnections.end(); it++)
{
if(it->second->getConnectionId() < lowestConnectionIdIt->second->getConnectionId())
{
lowestConnectionIdIt = it;
}
}
delete lowestConnectionIdIt->second;
mConnections.erase(lowestConnectionIdIt);
}
void
XmlRpcServerBase::logSocketError(int e)
{
switch (e)
{
case EAGAIN:
InfoLog (<< "No data ready to read" << strerror(e));
break;
case EINTR:
InfoLog (<< "The call was interrupted by a signal before any data was read : " << strerror(e));
break;
case EIO:
InfoLog (<< "I/O error : " << strerror(e));
break;
case EBADF:
InfoLog (<< "fd is not a valid file descriptor or is not open for reading : " << strerror(e));
break;
case EINVAL:
InfoLog (<< "fd is attached to an object which is unsuitable for reading : " << strerror(e));
break;
case EFAULT:
InfoLog (<< "buf is outside your accessible address space : " << strerror(e));
break;
#if defined(WIN32)
case WSAENETDOWN:
InfoLog (<<" The network subsystem has failed. ");
break;
case WSAEFAULT:
InfoLog (<<" The buf or from parameters are not part of the user address space, "
"or the fromlen parameter is too small to accommodate the peer address. ");
break;
case WSAEINTR:
InfoLog (<<" The (blocking) call was canceled through WSACancelBlockingCall. ");
break;
case WSAEINPROGRESS:
InfoLog (<<" A blocking Windows Sockets 1.1 call is in progress, or the "
"service provider is still processing a callback function. ");
break;
case WSAEINVAL:
InfoLog (<<" The socket has not been bound with bind, or an unknown flag was specified, "
"or MSG_OOB was specified for a socket with SO_OOBINLINE enabled, "
"or (for byte stream-style sockets only) len was zero or negative. ");
break;
case WSAEISCONN :
InfoLog (<<"The socket is connected. This function is not permitted with a connected socket, "
"whether the socket is connection-oriented or connectionless. ");
break;
case WSAENETRESET:
InfoLog (<<" The connection has been broken due to the keep-alive activity "
"detecting a failure while the operation was in progress. ");
break;
case WSAENOTSOCK :
InfoLog (<<"The descriptor is not a socket. ");
break;
case WSAEOPNOTSUPP:
InfoLog (<<" MSG_OOB was specified, but the socket is not stream-style such as type "
"SOCK_STREAM, OOB data is not supported in the communication domain associated with this socket, "
"or the socket is unidirectional and supports only send operations. ");
break;
case WSAESHUTDOWN:
InfoLog (<<"The socket has been shut down; it is not possible to recvfrom on a socket after "
"shutdown has been invoked with how set to SD_RECEIVE or SD_BOTH. ");
break;
case WSAEMSGSIZE:
InfoLog (<<" The message was too large to fit into the specified buffer and was truncated. ");
break;
case WSAETIMEDOUT:
InfoLog (<<" The connection has been dropped, because of a network failure or because the "
"system on the other end went down without notice. ");
break;
case WSAECONNRESET :
InfoLog (<<"Connection reset ");
break;
case WSAEWOULDBLOCK:
DebugLog (<<"Would Block ");
break;
case WSAEHOSTUNREACH:
InfoLog (<<"A socket operation was attempted to an unreachable host ");
break;
case WSANOTINITIALISED:
InfoLog (<<"Either the application has not called WSAStartup or WSAStartup failed. "
"The application may be accessing a socket that the current active task does not own (that is, trying to share a socket between tasks),"
"or WSACleanup has been called too many times. ");
break;
case WSAEACCES:
InfoLog (<<"An attempt was made to access a socket in a way forbidden by its access permissions ");
break;
case WSAENOBUFS:
InfoLog (<<"An operation on a socket could not be performed because the system lacked sufficient "
"buffer space or because a queue was full");
break;
case WSAENOTCONN:
InfoLog (<<"A request to send or receive data was disallowed because the socket is not connected "
"and (when sending on a datagram socket using sendto) no address was supplied");
break;
case WSAECONNABORTED:
InfoLog (<<"An established connection was aborted by the software in your host computer, possibly "
"due to a data transmission time-out or protocol error");
break;
case WSAEADDRNOTAVAIL:
InfoLog (<<"The requested address is not valid in its context. This normally results from an attempt to "
"bind to an address that is not valid for the local computer");
break;
case WSAEAFNOSUPPORT:
InfoLog (<<"An address incompatible with the requested protocol was used");
break;
case WSAEDESTADDRREQ:
InfoLog (<<"A required address was omitted from an operation on a socket");
break;
case WSAENETUNREACH:
InfoLog (<<"A socket operation was attempted to an unreachable network");
break;
#endif
default:
InfoLog (<< "Some other error (" << e << "): " << strerror(e));
break;
}
}
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

View File

@@ -0,0 +1,119 @@
#if !defined(XmlRpcServerBase_hxx)
#define XmlRpcServerBase_hxx
#include <map>
#include <rutil/Data.hxx>
#include <rutil/Socket.hxx>
#include <rutil/TransportType.hxx>
#include <rutil/Fifo.hxx>
#include <resip/stack/Tuple.hxx>
#include <rutil/SelectInterruptor.hxx>
namespace clicktocall
{
class XmlRpcConnection;
class ResponseInfo
{
public:
ResponseInfo(unsigned int connectionId,
unsigned int requestId,
const resip::Data& responseData,
bool isFinal) :
mConnectionId(connectionId),
mRequestId(requestId),
mResponseData(responseData),
mIsFinal(isFinal) {}
~ResponseInfo() {}
unsigned int getConnectionId() const { return mConnectionId; }
unsigned int getRequestId() const { return mRequestId; }
const resip::Data& getResponseData() const { return mResponseData; }
bool getIsFinal() const { return mIsFinal; }
private:
unsigned int mConnectionId;
unsigned int mRequestId;
resip::Data mResponseData;
bool mIsFinal;
};
class XmlRpcServerBase
{
friend class XmlRpcConnection;
public:
XmlRpcServerBase(int port, resip::IpVersion version);
virtual ~XmlRpcServerBase();
void buildFdSet(resip::FdSet& fdset);
void process(resip::FdSet& fdset);
bool isSane();
static void logSocketError(int e);
// thread safe - uses fifo
void sendResponse(unsigned int connectionId,
unsigned int requestId,
const resip::Data& responseData,
bool isFinal=true);
protected:
virtual void handleRequest(unsigned int connectionId,
unsigned int requestId,
const resip::Data& request) = 0;
private:
static const unsigned int MaxConnections = 60; // Note: use caution if making this any bigger, default fd_set size in windows is 64
resip::Socket mFd;
resip::Tuple mTuple;
bool mSane;
typedef std::map<unsigned int, XmlRpcConnection*> ConnectionMap;
ConnectionMap mConnections;
void closeOldestConnection();
resip::Fifo<ResponseInfo> mResponseFifo;
resip::SelectInterruptor mSelectInterruptor;
};
}
#endif
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

View File

@@ -0,0 +1,84 @@
#include <rutil/Socket.hxx>
#include <rutil/Logger.hxx>
#include "AppSubsystem.hxx"
#include "XmlRpcServer.hxx"
#include "XmlRpcServerThread.hxx"
#define RESIPROCATE_SUBSYSTEM AppSubsystem::CLICKTOCALL
using namespace clicktocall;
using namespace resip;
using namespace std;
XmlRpcServerThread::XmlRpcServerThread(const std::list<XmlRpcServer*>& xmlRpcServerList)
: mXmlRpcServerList(xmlRpcServerList)
{
}
void
XmlRpcServerThread::thread()
{
while (!isShutdown())
{
try
{
FdSet fdset;
std::list<XmlRpcServer*>::iterator it = mXmlRpcServerList.begin();
for(;it!=mXmlRpcServerList.end();it++)
{
(*it)->buildFdSet(fdset);
}
fdset.selectMilliSeconds( 10*1000 );
it = mXmlRpcServerList.begin();
for(;it!=mXmlRpcServerList.end();it++)
{
(*it)->process(fdset);
}
}
catch (...)
{
ErrLog (<< "XmlRpcServerThread::thread: Unhandled exception: " );
}
}
}
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

View File

@@ -0,0 +1,62 @@
#if !defined(XmlRpcServerThread_hxx)
#define XmlRpcServerThread_hxx
#include <list>
#include <rutil/ThreadIf.hxx>
#include <rutil/Socket.hxx>
namespace clicktocall
{
class XmlRpcServer;
class XmlRpcServerThread : public resip::ThreadIf
{
public:
XmlRpcServerThread(const std::list<XmlRpcServer*>& xmlRpcServerList);
protected:
private:
virtual void thread();
std::list<XmlRpcServer*> mXmlRpcServerList;
};
}
#endif
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

View File

@@ -0,0 +1,81 @@
########################################################
# click to call server configuration file
########################################################
########################################################
# SIP settings
########################################################
# Local IP Address to bind SIP transports to. If left blank
# ichat-gw will bind to all adapters.
#IPAddress = 192.168.1.106
#IPAddress = 2001:5c0:1000:a::6d
IPAddress =
# Comma separated list of DNS servers, overrides default OS detected list (leave blank for default)
DNSServers =
# Used in From header of SIP calls, when calling initiator. Value must be a valid formatted SIP Uri
ClickToCallIdentity = sip:click2call@blitzzgod.com
# Local port to listen on for SIP messages over UDP or TCP
UDPTCPPort = 5072
# Local port to listen on for SIP messages over TLS
TLSPort = 5073
# TLS domain name for this server (note: domain cert for this domain must be present)
TLSDomainName =
# Enable/Disable TCP/UDP CRLFCRLF keepalive packets for SIP endpoints
# 1|true|on|enable to enable, 0|false|off|disable to disable
KeepAlives = enable
# URI of a proxy server to use a SIP outbound proxy. This setting should not be required if
# proper DNS based SIP routing is operational.
OutboundProxy =
########################################################
# General settings
########################################################
# Logging level: NONE|CRIT|ERR|WARNING|INFO|DEBUG|STACK
LogLevel = INFO
# Log Filename
LogFilename = clicktocall.log
# Log file Max Lines
LogFileMaxLines = 50000
# Port to listen for XML RPC requests on. Set to 0 to disable.
# Note: clicktocall will listen on this port for all interfaces, for both IPv4
# and IPv6 (if available).
XmlRpcPort = 5094
# Port to listen on for HTTP messaging (ie. Click-to-call). Set to 0 to disable.
# Note: clicktocall will listen on this port for all interfaces, for both IPv4
# and IPv6 (if available).
HttpPort = 5090
# Enable/Disable HTTP Digest authentication: 1|true|on to enable
# 1|true|on|enable to enable, 0|false|off|disable to disable
HttpAuth = enable
# Password required if HttpAuth is enabled: Note: auth user is always "admin"
HttpAuthPwd = admin
########################################################
# Address Translation Rules (must be listed in pairs)
########################################################
# Rule for mapping any non-sip address to appropriate SIP URI
TranslationPattern=^(.*)$
TranslationOutput=sip:$1@blitzzgod.com

View File

@@ -0,0 +1,116 @@
#include <signal.h>
#include "AppSubsystem.hxx"
#include "Server.hxx"
#include <rutil/Log.hxx>
#include <rutil/Logger.hxx>
#include <rutil/Time.hxx>
#include <rutil/DnsUtil.hxx>
#include <rutil/BaseException.hxx>
#include <resip/stack/NameAddr.hxx>
#include <rutil/WinLeakCheck.hxx>
using namespace clicktocall;
using namespace resip;
using namespace std;
#define RESIPROCATE_SUBSYSTEM AppSubsystem::CLICKTOCALL
static bool finished = false;
static void
signalHandler(int signo)
{
std::cerr << "Shutting down..." << endl;
finished = true;
}
int
main (int argc, char** argv)
{
#ifndef _WIN32
if ( signal( SIGPIPE, SIG_IGN) == SIG_ERR)
{
cerr << "Couldn't install signal handler for SIGPIPE" << endl;
exit(-1);
}
#else
#if defined(_DEBUG) && defined(LEAK_CHECK)
resip::FindMemoryLeaks fml;
#endif
#endif
if ( signal( SIGINT, signalHandler ) == SIG_ERR )
{
cerr << "Couldn't install signal handler for SIGINT" << endl;
exit( -1 );
}
if ( signal( SIGTERM, signalHandler ) == SIG_ERR )
{
cerr << "Couldn't install signal handler for SIGTERM" << endl;
exit( -1 );
}
initNetwork();
//////////////////////////////////////////////////////////////////////////////
// Create Server
//////////////////////////////////////////////////////////////////////////////
{
Server server(argc, argv);
//////////////////////////////////////////////////////////////////////////////
// Startup and run...
//////////////////////////////////////////////////////////////////////////////
server.startup();
while(true)
{
server.process(50);
if(finished) break;
}
server.shutdown();
}
InfoLog(<< "ClickToCall server is shutdown.");
sleepSeconds(2);
}
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

View File

@@ -0,0 +1,67 @@
Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "clicktocall", "clicktocall_9_0.vcproj", "{8BA87397-9B42-4820-BA53-62FF35C22CAE}"
ProjectSection(ProjectDependencies) = postProject
{2A8BE839-6466-4001-B224-8F1C3168D04A} = {2A8BE839-6466-4001-B224-8F1C3168D04A}
{12720B4D-F4FC-4502-8FA9-589BF5166216} = {12720B4D-F4FC-4502-8FA9-589BF5166216}
{38594885-CF9C-4C5F-B3F0-E4969D7E3F58} = {38594885-CF9C-4C5F-B3F0-E4969D7E3F58}
{96CD935E-1951-43B8-AF75-F1C06B3778C1} = {96CD935E-1951-43B8-AF75-F1C06B3778C1}
{3D0E5CEB-93DC-4FDB-918B-D08FA369E106} = {3D0E5CEB-93DC-4FDB-918B-D08FA369E106}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rutil", "..\..\rutil\rutil_9_0.vcproj", "{3D0E5CEB-93DC-4FDB-918B-D08FA369E106}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "resiprocate", "..\..\resip\stack\resiprocate_9_0.vcproj", "{2A8BE839-6466-4001-B224-8F1C3168D04A}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dum", "..\..\resip\dum\dum_9_0.vcproj", "{12720B4D-F4FC-4502-8FA9-589BF5166216}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ares", "..\..\rutil\dns\ares\ares_9_0.vcproj", "{96CD935E-1951-43B8-AF75-F1C06B3778C1}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pcre", "..\..\contrib\pcre\pcre_9_0.vcproj", "{38594885-CF9C-4C5F-B3F0-E4969D7E3F58}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "clicktocallxml", "test\clicktocallxml_9_0.vcproj", "{9F820A51-A2FF-4EB6-ACB7-F0402E8D5CEC}"
ProjectSection(ProjectDependencies) = postProject
{2A8BE839-6466-4001-B224-8F1C3168D04A} = {2A8BE839-6466-4001-B224-8F1C3168D04A}
{8BA87397-9B42-4820-BA53-62FF35C22CAE} = {8BA87397-9B42-4820-BA53-62FF35C22CAE}
{96CD935E-1951-43B8-AF75-F1C06B3778C1} = {96CD935E-1951-43B8-AF75-F1C06B3778C1}
{3D0E5CEB-93DC-4FDB-918B-D08FA369E106} = {3D0E5CEB-93DC-4FDB-918B-D08FA369E106}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{8BA87397-9B42-4820-BA53-62FF35C22CAE}.Debug|Win32.ActiveCfg = Debug|Win32
{8BA87397-9B42-4820-BA53-62FF35C22CAE}.Debug|Win32.Build.0 = Debug|Win32
{8BA87397-9B42-4820-BA53-62FF35C22CAE}.Release|Win32.ActiveCfg = Release|Win32
{3D0E5CEB-93DC-4FDB-918B-D08FA369E106}.Debug|Win32.ActiveCfg = SSL-Debug|Win32
{3D0E5CEB-93DC-4FDB-918B-D08FA369E106}.Debug|Win32.Build.0 = SSL-Debug|Win32
{3D0E5CEB-93DC-4FDB-918B-D08FA369E106}.Release|Win32.ActiveCfg = SSL-Release|Win32
{3D0E5CEB-93DC-4FDB-918B-D08FA369E106}.Release|Win32.Build.0 = SSL-Release|Win32
{2A8BE839-6466-4001-B224-8F1C3168D04A}.Debug|Win32.ActiveCfg = SSL-Debug|Win32
{2A8BE839-6466-4001-B224-8F1C3168D04A}.Debug|Win32.Build.0 = SSL-Debug|Win32
{2A8BE839-6466-4001-B224-8F1C3168D04A}.Release|Win32.ActiveCfg = SSL-Release|Win32
{2A8BE839-6466-4001-B224-8F1C3168D04A}.Release|Win32.Build.0 = SSL-Release|Win32
{12720B4D-F4FC-4502-8FA9-589BF5166216}.Debug|Win32.ActiveCfg = SSL-Debug|Win32
{12720B4D-F4FC-4502-8FA9-589BF5166216}.Debug|Win32.Build.0 = SSL-Debug|Win32
{12720B4D-F4FC-4502-8FA9-589BF5166216}.Release|Win32.ActiveCfg = SSL-Release|Win32
{12720B4D-F4FC-4502-8FA9-589BF5166216}.Release|Win32.Build.0 = SSL-Release|Win32
{96CD935E-1951-43B8-AF75-F1C06B3778C1}.Debug|Win32.ActiveCfg = Debug|Win32
{96CD935E-1951-43B8-AF75-F1C06B3778C1}.Debug|Win32.Build.0 = Debug|Win32
{96CD935E-1951-43B8-AF75-F1C06B3778C1}.Release|Win32.ActiveCfg = Release|Win32
{96CD935E-1951-43B8-AF75-F1C06B3778C1}.Release|Win32.Build.0 = Release|Win32
{38594885-CF9C-4C5F-B3F0-E4969D7E3F58}.Debug|Win32.ActiveCfg = Debug|Win32
{38594885-CF9C-4C5F-B3F0-E4969D7E3F58}.Debug|Win32.Build.0 = Debug|Win32
{38594885-CF9C-4C5F-B3F0-E4969D7E3F58}.Release|Win32.ActiveCfg = Release|Win32
{38594885-CF9C-4C5F-B3F0-E4969D7E3F58}.Release|Win32.Build.0 = Release|Win32
{9F820A51-A2FF-4EB6-ACB7-F0402E8D5CEC}.Debug|Win32.ActiveCfg = Debug|Win32
{9F820A51-A2FF-4EB6-ACB7-F0402E8D5CEC}.Debug|Win32.Build.0 = Debug|Win32
{9F820A51-A2FF-4EB6-ACB7-F0402E8D5CEC}.Release|Win32.ActiveCfg = Release|Win32
{9F820A51-A2FF-4EB6-ACB7-F0402E8D5CEC}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,312 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
Name="clicktocall"
ProjectGUID="{8BA87397-9B42-4820-BA53-62FF35C22CAE}"
RootNamespace="clicktocall"
Keyword="Win32Proj"
TargetFrameworkVersion="131072"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="&quot;$(ProjectDir)../../&quot;;&quot;$(ProjectDir)../../contrib/openssl/include&quot;;&quot;$(ProjectDir)../../contrib/openssl/inc32&quot;;&quot;$(ProjectDir)../../contrib/pcre&quot;"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;USE_SSL;USE_IPV6;LEAK_CHECK"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="Ws2_32.lib winmm.lib Dnsapi.lib Iphlpapi.lib crypt32.lib &quot;$(ProjectDir)..\..\contrib\openssl\lib\vc\static\libeay32MDd.lib&quot; &quot;$(ProjectDir)..\..\contrib\openssl\lib\vc\static\ssleay32MDd.lib&quot;"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
RandomizedBaseAddress="1"
DataExecutionPrevention="0"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="&quot;$(ProjectDir)../../&quot;;&quot;$(ProjectDir)../../contrib/openssl/include&quot;;&quot;$(ProjectDir)../../contrib/openssl/inc32&quot;;&quot;$(ProjectDir)../../contrib/pcre&quot;"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;USE_SSL;USE_IPV6"
RuntimeLibrary="2"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="false"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="Ws2_32.lib winmm.lib Dnsapi.lib Iphlpapi.lib crypt32.lib &quot;$(ProjectDir)..\..\contrib\openssl\lib\vc\static\libeay32MD.lib&quot; &quot;$(ProjectDir)..\..\contrib\openssl\lib\vc\static\ssleay32MD.lib&quot;"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
RandomizedBaseAddress="1"
DataExecutionPrevention="0"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\AddressTranslator.cxx"
>
</File>
<File
RelativePath=".\AppSubsystem.cxx"
>
</File>
<File
RelativePath=".\B2BSession.cxx"
>
</File>
<File
RelativePath=".\clicktocall.cxx"
>
</File>
<File
RelativePath=".\ConfigParser.cxx"
>
</File>
<File
RelativePath=".\HttpBase.cxx"
>
</File>
<File
RelativePath=".\HttpConnection.cxx"
>
</File>
<File
RelativePath=".\Server.cxx"
>
</File>
<File
RelativePath=".\WebAdmin.cxx"
>
</File>
<File
RelativePath=".\WebAdminThread.cxx"
>
</File>
<File
RelativePath=".\XmlRpcConnection.cxx"
>
</File>
<File
RelativePath=".\XmlRpcServer.cxx"
>
</File>
<File
RelativePath=".\XmlRpcServerBase.cxx"
>
</File>
<File
RelativePath=".\XmlRpcServerThread.cxx"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath=".\AddressTranslator.hxx"
>
</File>
<File
RelativePath=".\AppSubsystem.hxx"
>
</File>
<File
RelativePath=".\B2BSession.hxx"
>
</File>
<File
RelativePath=".\ClickToCallCmds.hxx"
>
</File>
<File
RelativePath=".\ConfigParser.hxx"
>
</File>
<File
RelativePath=".\HttpBase.hxx"
>
</File>
<File
RelativePath=".\HttpConnection.hxx"
>
</File>
<File
RelativePath=".\Server.hxx"
>
</File>
<File
RelativePath=".\Version.hxx"
>
</File>
<File
RelativePath=".\WebAdmin.hxx"
>
</File>
<File
RelativePath=".\WebAdminThread.hxx"
>
</File>
<File
RelativePath=".\XmlRpcConnection.hxx"
>
</File>
<File
RelativePath=".\XmlRpcServer.hxx"
>
</File>
<File
RelativePath=".\XmlRpcServerBase.hxx"
>
</File>
<File
RelativePath=".\XmlRpcServerThread.hxx"
>
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@@ -0,0 +1,6 @@
/Makefile.in
/Makefile
/.deps
/.libs

View File

@@ -0,0 +1,6 @@
add_executable(clicktocallxml
clicktocallxml.cxx
)
target_link_libraries(clicktocallxml PUBLIC rutil)

View File

@@ -0,0 +1,190 @@
#include <rutil/Log.hxx>
#include <rutil/Logger.hxx>
#include <rutil/DnsUtil.hxx>
#include <rutil/BaseException.hxx>
#include <rutil/XMLCursor.hxx>
#include <rutil/WinLeakCheck.hxx>
using namespace resip;
using namespace std;
#define RESIPROCATE_SUBSYSTEM Subsystem::TEST
void sleepSeconds(unsigned int seconds)
{
#ifdef WIN32
Sleep(seconds*1000);
#else
sleep(seconds);
#endif
}
int
main (int argc, char** argv)
{
#ifdef WIN32
initNetwork();
#endif
int sd, rc;
struct sockaddr_in localAddr, servAddr;
struct hostent *h;
if(argc != 6)
{
ErrLog(<< "usage: " << argv[0] <<" <server> <port> <initiator> <destination> <anchor 0|1>");
exit(1);
}
h = gethostbyname(argv[1]);
if(h==0)
{
ErrLog(<< "unknown host " << argv[1]);
exit(1);
}
servAddr.sin_family = h->h_addrtype;
memcpy((char *) &servAddr.sin_addr.s_addr, h->h_addr_list[0], h->h_length);
servAddr.sin_port = htons(atoi(argv[2]));
// Create TCP Socket
sd = socket(AF_INET, SOCK_STREAM, 0);
if(sd < 0)
{
ErrLog(<< "cannot open socket");
exit(1);
}
// bind to any local interface/port
localAddr.sin_family = AF_INET;
localAddr.sin_addr.s_addr = htonl(INADDR_ANY);
localAddr.sin_port = 0;
rc = bind(sd, (struct sockaddr *) &localAddr, sizeof(localAddr));
if(rc < 0)
{
ErrLog(<<"error binding locally");
exit(1);
}
// Connect to server
rc = connect(sd, (struct sockaddr *) &servAddr, sizeof(servAddr));
if(rc < 0)
{
ErrLog(<< "error connecting");
exit(1);
}
Data request(
"<ClickToCall>\r\n"
" <Request>\r\n"
" <Initiator>" + Data(argv[3]) + "</Initiator>\r\n"
" <Destination>" + Data(argv[4]) + "</Destination>\r\n"
" <AnchorCall>" + Data(argv[5][0] == '0' ? "false" : "true") + "</AnchorCall>\r\n"
" </Request>\r\n"
"</ClickToCall>\r\n");
rc = send(sd, request.c_str(), request.size(), 0);
if(rc < 0)
{
ErrLog(<< "error sending");
close(sd);
exit(1);
}
char readBuffer[8000];
while(rc > 0)
{
rc = recv(sd, (char*)&readBuffer, sizeof(readBuffer), 0);
if(rc < 0)
{
ErrLog(<< "error receiving");
close(sd);
exit(1);
}
if(rc > 0)
{
Data response(Data::Borrow, (const char*)&readBuffer, rc);
InfoLog(<< "Received response: \r\n" << response.c_str());
ParseBuffer pb(response);
XMLCursor xml(pb);
if(xml.firstChild())
{
if(xml.nextSibling())
{
if(xml.firstChild())
{
do
{
if(xml.getTag() == "Result")
{
XMLCursor::AttributeMap attribs = xml.getAttributes();
XMLCursor::AttributeMap::iterator it = attribs.find("Code");
if(it != attribs.end())
{
unsigned long statusCode = it->second.convertUnsignedLong();
if(statusCode >= 200 && statusCode < 300)
{
it = attribs.find("Leg");
if(it != attribs.end())
{
if(it->second == "Destination")
{
// Successfully connected to destination - break out
rc = 0;
}
}
}
else if(statusCode >=300)
{
// Failed - break out
rc = 0;
}
}
break;
}
} while(xml.nextSibling());
}
}
}
}
}
//sleepSeconds(5);
InfoLog(<< "xmlrpcclient done.");
}
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

View File

@@ -0,0 +1,201 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
Name="clicktocallxml"
ProjectGUID="{9F820A51-A2FF-4EB6-ACB7-F0402E8D5CEC}"
RootNamespace="clicktocallxml"
Keyword="Win32Proj"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="&quot;$(ProjectDir)../../../&quot;"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="Ws2_32.lib winmm.lib Dnsapi.lib Iphlpapi.lib crypt32.lib &quot;$(ProjectDir)..\..\..\contrib\openssl\lib\vc\static\libeay32MDd.lib&quot; &quot;$(ProjectDir)..\..\..\contrib\openssl\lib\vc\static\ssleay32MDd.lib&quot;"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
EnableIntrinsicFunctions="true"
AdditionalIncludeDirectories="&quot;$(ProjectDir)../../../&quot;"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="Ws2_32.lib winmm.lib Dnsapi.lib Iphlpapi.lib crypt32.lib &quot;$(ProjectDir)..\..\..\contrib\openssl\lib\vc\static\libeay32MD.lib&quot; &quot;$(ProjectDir)..\..\..\contrib\openssl\lib\vc\static\ssleay32MD.lib&quot;"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\clicktocallxml.cxx"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
<File
RelativePath=".\ReadMe.txt"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@@ -0,0 +1,12 @@
*.swp
*.o
*.lo
*.la
/Makefile
/Makefile.in
/.deps
/.libs
/echoTest

View File

@@ -0,0 +1,38 @@
#include "AppSubsystem.hxx"
AppSubsystem AppSubsystem::ECHOTEST("ECHOTEST");
/* ====================================================================
*
* Copyright 2021 Daniel Pocock http://danielpocock.com All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. Neither the name of the author(s) nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*
*/

View File

@@ -0,0 +1,60 @@
#if !defined(AppSubsystem_hxx)
#define AppSubsystem_hxx
#include <iostream>
#include <rutil/Subsystem.hxx>
/**
This class is used in the logging subsystem to identify
logging messages generated from echoTest
*/
class AppSubsystem : public resip::Subsystem
{
public:
// Add new systems below
static AppSubsystem ECHOTEST;
private:
explicit AppSubsystem(const char* rhs) : resip::Subsystem(rhs) {};
explicit AppSubsystem(const resip::Data& rhs);
AppSubsystem& operator=(const resip::Data& rhs);
};
#endif
/* ====================================================================
*
* Copyright 2021 Daniel Pocock http://danielpocock.com All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. Neither the name of the author(s) nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*
*/

View File

@@ -0,0 +1,17 @@
set(INCLUDES
AppSubsystem.hxx
EchoTestConfig.hxx
)
add_executable(echoTest
echoTest.cxx
AppSubsystem.cxx
EchoTestConfig.cxx
${INCLUDES}
)
target_include_directories(echoTest PRIVATE ${GSTREAMERMM_1_0_INCLUDE_DIRS})
target_link_libraries(echoTest dum gstreamerutils)
install(TARGETS echoTest DESTINATION ${CMAKE_INSTALL_BINDIR})

View File

@@ -0,0 +1,66 @@
#include <fstream>
#include <iostream>
#include "EchoTestConfig.hxx"
#include "AppSubsystem.hxx"
#define RESIPROCATE_SUBSYSTEM AppSubsystem::ECHOTEST
using namespace std;
using namespace resip;
using namespace echotest;
EchoTestConfig::EchoTestConfig()
{
}
EchoTestConfig::~EchoTestConfig()
{
}
void
EchoTestConfig::printHelpText(int argc, char **argv)
{
cout << "Command line format is:" << endl;
cout << " " << removePath(argv[0]) << " [<ConfigFilename>] [--<ConfigValueName>=<ConfigValue>] [--<ConfigValueName>=<ConfigValue>] ..." << endl;
cout << "Sample Command lines:" << endl;
cout << " " << removePath(argv[0]) << " echoTest.config --IPAddress=192.168.1.100 --SIPUri=sip:1000@myproxy.com --Password=123" << endl;
}
/* ====================================================================
*
* Copyright 2021, Daniel Pocock https://danielpocock.com
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. Neither the name of the author(s) nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* ====================================================================
*
*
*/

View File

@@ -0,0 +1,66 @@
#if !defined(ECHOTESTCONFIG_HXX)
#define ECHOTESTCONFIG_HXX
#include <sys/ioctl.h>
#include <stdio.h>
#include <map>
#include <rutil/ConfigParse.hxx>
#include <rutil/Data.hxx>
#include <rutil/Log.hxx>
#include <rutil/BaseException.hxx>
#include <resip/stack/SipConfigParse.hxx>
namespace echotest {
class EchoTestConfig : public resip::SipConfigParse
{
public:
EchoTestConfig();
virtual ~EchoTestConfig();
void printHelpText(int argc, char **argv);
using resip::ConfigParse::getConfigValue;
};
} // namespace
#endif
/* ====================================================================
*
* Copyright 2021, Daniel Pocock https://danielpocock.com
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. Neither the name of the author(s) nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* ====================================================================
*
*
*/

View File

@@ -0,0 +1,57 @@
# Introduction
Voice and video echo test
Demonstrates how to use GStreamer C++ bindings (GStreamerMM project)
with reSIProcate.
Currently supports regular RTP devices by using the GStreamer rtpbin element.
https://gstreamer.freedesktop.org/documentation/rtpmanager/rtpbin.html
Could be easily adapted for WebRTC using the GStreamer webrtcbin element.
https://gstreamer.freedesktop.org/documentation/webrtc/index.html
http://blog.nirbheek.in/2018/02/gstreamer-webrtc.html
See the configuration file for individual options. In particular, you
can select one of these pipelines either through the configuration
file or by using the name of the pipeline as the SIP user address,
for example, dialing sip:h264v@192.168.1.10 will select h264v
h264avx - use libav decode and x264 encode
h264v - use VAAPI decode/encode
h264o - use openh264 decode and openh264 encode
h264m - use libav decode and openh264 encode
vp8 - use the vp8decode and vp8encode
# Help and feedback
https://list.resiprocate.org/mailman/listinfo/resiprocate-users
mailto:resiprocate-users@resiprocate.org
# Dependencies
GStreamer and plugins
https://gstreamer.freedesktop.org/
License: LGPL
Note: GPL and/or patent restrictions apply to some optional plugins
Debian/Ubuntu packages: https://packages.qa.debian.org/gstreamer1.0
Fedora/RHEL packages: https://src.fedoraproject.org/rpms/gstreamer1
GStreamerMM (C++ bindings)
https://wiki.gnome.org/Projects/gstreamermm
License: LGPL 2.1
Debian/Ubuntu packages: https://packages.qa.debian.org/gstreamermm-1.0
Fedora/RHEL packages: https://src.fedoraproject.org/rpms/gstreamermm
# Optional dependencies
gst-kurento-plugins (for the vp8parse element)
https://github.com/KurentoLegacy/gst-kurento-plugins
License: LGPL 2.1
OpenH264
http://www.openh264.org/
Note: it is necessary to rebuild gst-plugins-bad after install OpenH264

View File

@@ -0,0 +1,89 @@
########################################################
# echoTest configuration file
########################################################
########################################################
# Logging settings
########################################################
# Logging Type: syslog|cerr|cout|file
LoggingType = file
# For syslog, also specify the facility, default is LOG_DAEMON
SyslogFacility = LOG_DAEMON
# Logging level: NONE|CRIT|ERR|WARNING|INFO|DEBUG|STACK
LogLevel = STACK
# Log Filename
# The following templates can be used in the filename:
# {timestamp} - the number of seconds since the UNIX epoch
# {pid} - the PID of the process
LogFilename = echoTest.log
# Log message structure: Unstructured or JSON_CEE
#LogMessageStructure = Unstructured
LogMessageStructure = JSON_CEE
# Log file Max Bytes. This setting is only applicable when LoggingType is set to file.
LogFileMaxBytes = 0
# Log file Max Lines
LogFileMaxLines = 0
# Instance name to be shown in logs, very useful when multiple instances
# logging to syslog concurrently
# If unspecified, no instance name is logged
#LoggingInstanceName = echoTest-dev
# Specify the HOMER SIP capture server hostname
# If CaptureHost is commented/not defined, there is no default value and
# echoTest doesn't attempt to send any HEP packets.
#CaptureHost = localhost
# Specify the HOMER SIP capture server UDP port
# If not defined, the default value, 9060, is used
#CapturePort = 9060
# Specify the HOMER Capture Agent ID
# The default value is 2002
CaptureAgentID = 2002
########################################################
# Transport settings
########################################################
# Local IP Address to bind SIP transports to.
# In general the IP address to bind to is queried from the host OS.This switch allows specification
# of the IP address for OS's that cannot be queried, or for machines that have mulitple NICs.
IPAddress = 127.0.0.1
# Local port number to use for SIP messaging over TCP - 0 to disable
TCPPort = 12010
# Local port number to use for SIP messaging over UDP - 0 to disable
UDPPort = 12010
# Default decoder / encoder pipeline to select if not specified in
# the URI of an incoming call.
DefaultPipelineId = h264avx
# Local port number to start allocating from for RTP media
MediaPortStart = 8002
# URI of a proxy server to use a SIP outbound proxy.
# By default echoTest does not use an outbound proxy. Use this switch to route all
# outbound, out-of-dialog requests through a fixed proxy despite the destination URI.
OutboundProxyUri =
# Whether to register with a SIP proxy
Register = false
# This option is used to specify the SIP URI for this instance of echoTest. echoTest uses
# this setting (-ip is not specified) in order to find the regisration server. If
# nothing is specified, then the default of sip:UAS@<ipaddress> will be used.
#SIPUri =
# SIP password of this SIP user
# Use this switch in cases where the proxy digest challenges sip messaging.
Password =

View File

@@ -0,0 +1,920 @@
#include <map>
#include <memory>
#include <regex>
#include <sstream>
#include <thread>
#include <time.h>
#include <utility>
#include "resip/stack/SdpContents.hxx"
#include "resip/stack/PlainContents.hxx"
#include "resip/stack/SipMessage.hxx"
#include "resip/stack/ShutdownMessage.hxx"
#include "resip/stack/SipStack.hxx"
#include "resip/stack/HEPSipMessageLoggingHandler.hxx"
#include "resip/dum/ClientAuthManager.hxx"
#include "resip/dum/ClientInviteSession.hxx"
#include "resip/dum/ClientRegistration.hxx"
#include "resip/dum/DialogUsageManager.hxx"
#include "resip/dum/DumShutdownHandler.hxx"
#include "resip/dum/InviteSessionHandler.hxx"
#include "resip/dum/MasterProfile.hxx"
#include "resip/dum/RegistrationHandler.hxx"
#include "resip/dum/ServerInviteSession.hxx"
#include "resip/dum/ServerOutOfDialogReq.hxx"
#include "resip/dum/OutOfDialogHandler.hxx"
#include "resip/dum/AppDialog.hxx"
#include "resip/dum/AppDialogSet.hxx"
#include "resip/dum/AppDialogSetFactory.hxx"
#include "rutil/Log.hxx"
#include "rutil/Logger.hxx"
#include "rutil/Random.hxx"
#include "rutil/WinLeakCheck.hxx"
#include "media/gstreamer/GStreamerUtils.hxx"
#include "media/gstreamer/GstRtpManager.hxx"
#include "media/gstreamer/GstRtpSession.hxx"
#include "rutil/ServerProcess.hxx"
#include "rutil/hep/HepAgent.hxx"
#include <gstreamermm.h>
#include <glibmm/main.h>
#include "EchoTestConfig.hxx"
#define RESIPROCATE_SUBSYSTEM Subsystem::TEST
using namespace echotest;
//using namespace resipgst;
using namespace Gst;
using namespace Glib;
using namespace resip;
using namespace std;
Data myIP;
class GstThread
{
public:
GstThread()
{
main_loop = Glib::MainLoop::create();
mThread = make_shared<thread>([this](){
InfoLog(<<"GstThread starting");
main_loop->run();
});
}
virtual ~GstThread()
{
InfoLog(<<"GstThread stopping");
if(main_loop)
{
main_loop->quit();
}
InfoLog(<<"GstThread destroyed");
}
private:
Glib::RefPtr<Glib::MainLoop> main_loop;
shared_ptr<thread> mThread;
};
/////////////////////////////////////////////////////////////////////////////////
//
// Classes that provide the mapping between Application Data and DUM
// dialogs/dialogsets
//
// The DUM layer creates an AppDialog/AppDialogSet object for inbound/outbound
// SIP Request that results in Dialog creation.
//
/////////////////////////////////////////////////////////////////////////////////
class TestAppDialog : public AppDialog
{
public:
TestAppDialog(HandleManager& ham, Data &SampleAppData, shared_ptr<resipgst::GstRtpManager> rTPManager)
: AppDialog(ham),
mSampleAppData(SampleAppData),
mRtpSession(make_shared<resipgst::GstRtpSession>(*rTPManager, false)) // FIXME isWebRTC
{
InfoLog(<< mSampleAppData << ": TestAppDialog: created.");
}
virtual ~TestAppDialog()
{
InfoLog(<< mSampleAppData << ": TestAppDialog: destroyed.");
}
bool
isWebRTCSession()
{
return false;
}
void
onMediaSourceAdded(const RefPtr<Pad>& pad)
{
Glib::ustring padName = pad->get_name();
DebugLog(<<"onMediaSourceAdded: on-pad-added, padName: " << padName << " stream ID: " << pad->get_stream_id().raw());
if(pad->get_direction() == PAD_SRC)
{
RefPtr<Caps> caps = pad->get_current_caps();
MediaTypeName mediaTypeName = deduceKeyForPadName(padName);
int streamId = getStreamIdFromPadName(padName);
if(streamId < 0)
{
ErrLog(<<"unable to find encoder for " << padName);
}
else
{
auto sink = mRtpSession->getOutgoingPads()[streamId];
if(!sink)
{
ErrLog(<<"no encoder configured for stream " << streamId);
return;
}
bool loopback = !isWebRTCSession();
if(sink->is_linked())
{
StackLog(<<"unlinking existing src");
RefPtr<Pad> src = sink->get_peer();
if(src->unlink(sink))
{
loopback = true;
// FIXME - destroy the unlinked test source
}
else
{
ErrLog(<<"failed to unlink existing src");
resip_assert(0);
}
}
if(loopback)
{
StackLog(<<"attempting loopback configuration");
RefPtr<Element> proxy;
if(mediaTypeName == "video")
{
proxy = Gst::VideoConvert::create();
}
else if(mediaTypeName == "audio")
{
proxy = Gst::AudioConvert::create();
}
else
{
CritLog(<<"unexpected streamKey: " << mediaTypeName);
resip_assert(0);
}
mPipeline->add(proxy);
// convert->link(enc);
proxy->get_static_pad("src")->link(sink);
pad->link(proxy->get_static_pad("sink"));
proxy->sync_state_with_parent();
mMediaBin->sync_state_with_parent();
DebugLog(<<"completed connection from incoming to outgoing stream");
}
else
{
// FIXME - disconnect the test sources and do the loopback
ErrLog(<<"not doing loopback for WebRTC");
}
}
}
else
{
StackLog(<<"not a source pad: " << padName);
}
}
void prepareStream(unsigned int streamId, bool loopbackMode)
{
resipgst::GstRtpSession::CapsVector capsV = mRtpSession->getOutgoingCaps();
RefPtr<Caps> caps;
if(capsV.size() > streamId && capsV[streamId])
{
caps = capsV[streamId];
}
if(!caps)
{
ErrLog(<<"caps not specified");
return;
}
RefPtr<Pad> mediaSink = mRtpSession->getOutgoingPads()[streamId];
MediaTypeName mediaTypeName = getMediaTypeName(caps);
resip_assert(mediaTypeName.size());
if(loopbackMode)
{
// FIXME - move this logic to GstRtpSession
//sendCapsEvent(bin, caps);
}
else
{
RefPtr<Element> testSrc = buildTestSource(mediaTypeName);
resip_assert(testSrc);
mPipeline->add(testSrc);
testSrc->get_static_pad("src")->link(mediaSink);
}
}
Data mSampleAppData;
shared_ptr<resipgst::GstRtpSession> mRtpSession;
Glib::RefPtr<Gst::Pipeline> mPipeline;
Glib::RefPtr<Gst::Element> mMediaBin;
Glib::RefPtr<Gst::Element> mRtpTransportElement;
};
class TestAppDialogSet : public AppDialogSet
{
public:
TestAppDialogSet(DialogUsageManager& dum, Data SampleAppData, shared_ptr<resipgst::GstRtpManager> rTPManager) : AppDialogSet(dum), mSampleAppData(SampleAppData), mRtpManager(rTPManager)
{
InfoLog(<< mSampleAppData << ": TestAppDialogSet: created.");
}
virtual ~TestAppDialogSet()
{
InfoLog(<< mSampleAppData << ": TestAppDialogSet: destroyed.");
}
virtual AppDialog* createAppDialog(const SipMessage& msg)
{
return new TestAppDialog(mDum, mSampleAppData, mRtpManager);
}
virtual std::shared_ptr<UserProfile> selectUASUserProfile(const SipMessage& msg)
{
InfoLog(<< mSampleAppData << ": TestAppDialogSet: UAS UserProfile requested for msg: " << msg.brief());
return mDum.getMasterUserProfile();
}
Data mSampleAppData;
shared_ptr<resipgst::GstRtpManager> mRtpManager;
};
class TestAppDialogSetFactory : public AppDialogSetFactory
{
public:
TestAppDialogSetFactory(shared_ptr<resipgst::GstRtpManager> rTPManager) : mRtpManager(rTPManager) {}
virtual AppDialogSet* createAppDialogSet(DialogUsageManager& dum, const SipMessage& msg)
{ return new TestAppDialogSet(dum, Data("UAS") + Data("(") + getMethodName(msg.header(h_RequestLine).getMethod()) + Data(")"), mRtpManager); }
// For a UAS the testAppDialogSet will be created by DUM using this function. If you want to set
// Application Data, then one approach is to wait for onNewSession(ServerInviteSessionHandle ...)
// to be called, then use the ServerInviteSessionHandle to get at the AppDialogSet or AppDialog,
// then cast to your derived class and set the desired application data.
private:
shared_ptr<resipgst::GstRtpManager> mRtpManager;
};
// Generic InviteSessionHandler
class TestInviteSessionHandler : public InviteSessionHandler, public ClientRegistrationHandler, public OutOfDialogHandler
{
public:
Data name;
bool registered;
ClientRegistrationHandle registerHandle;
TestInviteSessionHandler(const Data& n) : name(n), registered(false)
{
}
virtual ~TestInviteSessionHandler()
{
}
virtual void onSuccess(ClientRegistrationHandle h, const SipMessage& response)
{
registerHandle = h;
resip_assert(registerHandle.isValid());
InfoLog(<< name << ": ClientRegistration-onSuccess - " << response.brief());
registered = true;
}
virtual void onFailure(ClientRegistrationHandle, const SipMessage& msg)
{
InfoLog(<< name << ": ClientRegistration-onFailure - " << msg.brief());
throw; // Ungracefully end
}
virtual void onRemoved(ClientRegistrationHandle, const SipMessage& response)
{
InfoLog(<< name << ": ClientRegistration-onRemoved");
}
virtual int onRequestRetry(ClientRegistrationHandle, int retrySeconds, const SipMessage& response)
{
InfoLog(<< name << ": ClientRegistration-onRequestRetry (" << retrySeconds << ") - " << response.brief());
return -1;
}
virtual void onNewSession(ClientInviteSessionHandle, InviteSession::OfferAnswerType oat, const SipMessage& msg)
{
InfoLog(<< name << ": ClientInviteSession-onNewSession - " << msg.brief());
}
virtual void onNewSession(ServerInviteSessionHandle, InviteSession::OfferAnswerType oat, const SipMessage& msg)
{
InfoLog(<< name << ": ServerInviteSession-onNewSession - " << msg.brief());
}
virtual void onFailure(ClientInviteSessionHandle, const SipMessage& msg)
{
InfoLog(<< name << ": ClientInviteSession-onFailure - " << msg.brief());
}
virtual void onProvisional(ClientInviteSessionHandle, const SipMessage& msg)
{
InfoLog(<< name << ": ClientInviteSession-onProvisional - " << msg.brief());
}
virtual void onConnected(ClientInviteSessionHandle, const SipMessage& msg)
{
InfoLog(<< name << ": ClientInviteSession-onConnected - " << msg.brief());
}
virtual void onStaleCallTimeout(ClientInviteSessionHandle handle)
{
InfoLog(<< name << ": ClientInviteSession-onStaleCallTimeout");
}
virtual void onConnected(InviteSessionHandle, const SipMessage& msg)
{
InfoLog(<< name << ": InviteSession-onConnected - " << msg.brief());
}
virtual void onRedirected(ClientInviteSessionHandle, const SipMessage& msg)
{
InfoLog(<< name << ": ClientInviteSession-onRedirected - " << msg.brief());
}
virtual void onTerminated(InviteSessionHandle, InviteSessionHandler::TerminatedReason reason, const SipMessage* msg)
{
InfoLog(<< name << ": InviteSession-onTerminated - " << msg->brief());
resip_assert(0); // This is overriden in UAS and UAC specific handlers
}
virtual void onAnswer(InviteSessionHandle, const SipMessage& msg, const SdpContents& sdp)
{
InfoLog(<< name << ": InviteSession-onAnswer(SDP)");
//sdp->encode(cout);
}
virtual void onOffer(InviteSessionHandle is, const SipMessage& msg, const SdpContents& sdp)
{
InfoLog(<< name << ": InviteSession-onOffer(SDP)");
//sdp->encode(cout);
}
virtual void onEarlyMedia(ClientInviteSessionHandle, const SipMessage& msg, const SdpContents& sdp)
{
InfoLog(<< name << ": InviteSession-onEarlyMedia(SDP)");
//sdp->encode(cout);
}
virtual void onOfferRequired(InviteSessionHandle, const SipMessage& msg)
{
InfoLog(<< name << ": InviteSession-onOfferRequired - " << msg.brief());
}
virtual void onOfferRejected(InviteSessionHandle, const SipMessage* msg)
{
InfoLog(<< name << ": InviteSession-onOfferRejected");
}
virtual void onRefer(InviteSessionHandle, ServerSubscriptionHandle, const SipMessage& msg)
{
InfoLog(<< name << ": InviteSession-onRefer - " << msg.brief());
}
virtual void onReferAccepted(InviteSessionHandle, ClientSubscriptionHandle, const SipMessage& msg)
{
InfoLog(<< name << ": InviteSession-onReferAccepted - " << msg.brief());
}
virtual void onReferRejected(InviteSessionHandle, const SipMessage& msg)
{
InfoLog(<< name << ": InviteSession-onReferRejected - " << msg.brief());
}
virtual void onReferNoSub(InviteSessionHandle, const SipMessage& msg)
{
InfoLog(<< name << ": InviteSession-onReferNoSub - " << msg.brief());
}
virtual void onInfo(InviteSessionHandle, const SipMessage& msg)
{
InfoLog(<< name << ": InviteSession-onInfo - " << msg.brief());
}
virtual void onInfoSuccess(InviteSessionHandle, const SipMessage& msg)
{
InfoLog(<< name << ": InviteSession-onInfoSuccess - " << msg.brief());
}
virtual void onInfoFailure(InviteSessionHandle, const SipMessage& msg)
{
InfoLog(<< name << ": InviteSession-onInfoFailure - " << msg.brief());
}
virtual void onMessage(InviteSessionHandle, const SipMessage& msg)
{
InfoLog(<< name << ": InviteSession-onMessage - " << msg.brief());
}
virtual void onMessageSuccess(InviteSessionHandle, const SipMessage& msg)
{
InfoLog(<< name << ": InviteSession-onMessageSuccess - " << msg.brief());
}
virtual void onMessageFailure(InviteSessionHandle, const SipMessage& msg)
{
InfoLog(<< name << ": InviteSession-onMessageFailure - " << msg.brief());
}
virtual void onForkDestroyed(ClientInviteSessionHandle)
{
InfoLog(<< name << ": ClientInviteSession-onForkDestroyed");
}
// Out-of-Dialog Callbacks
virtual void onSuccess(ClientOutOfDialogReqHandle, const SipMessage& successResponse)
{
InfoLog(<< name << ": ClientOutOfDialogReq-onSuccess - " << successResponse.brief());
}
virtual void onFailure(ClientOutOfDialogReqHandle, const SipMessage& errorResponse)
{
InfoLog(<< name << ": ClientOutOfDialogReq-onFailure - " << errorResponse.brief());
}
virtual void onReceivedRequest(ServerOutOfDialogReqHandle ood, const SipMessage& request)
{
InfoLog(<< name << ": ServerOutOfDialogReq-onReceivedRequest - " << request.brief());
// Add SDP to response here if required
InfoLog(<< name << ": Sending 200 response to OPTIONS.");
ood->send(ood->answerOptions());
}
};
class TestUas : public TestInviteSessionHandler
{
public:
bool done;
bool requestedOffer;
typedef std::map<DialogId, shared_ptr<GstThread>> MediaThreads;
MediaThreads mMediaThreads;
std::shared_ptr<HepAgent> mHepAgent;
TestUas(const Data& pipelineId, std::shared_ptr<HepAgent> agent)
: TestInviteSessionHandler("UAS"),
done(false),
requestedOffer(false),
mHepAgent(agent)
{
}
~TestUas()
{
}
using TestInviteSessionHandler::onNewSession;
virtual void
onNewSession(ServerInviteSessionHandle sis, InviteSession::OfferAnswerType oat, const SipMessage& msg)
{
InfoLog(<< name << ": ServerInviteSession-onNewSession - " << msg.brief());
InfoLog(<< name << ": Sending 180 response.");
mSis = sis;
sis->provisional(180);
}
virtual void onTerminated(InviteSessionHandle is, InviteSessionHandler::TerminatedReason reason, const SipMessage* msg)
{
InfoLog(<< name << ": InviteSession-onTerminated - ");
mMediaThreads.erase(is->getDialogId());
done = true;
}
bool
onGstBusMessage(const RefPtr<Gst::Bus>&, const RefPtr<Gst::Message>& message)
{
switch(message->get_message_type())
{
case Gst::MESSAGE_EOS:
ErrLog(<< "End of stream");
//main_loop->quit(); // FIXME - from echoTest
return false;
case Gst::MESSAGE_ERROR:
{
Glib::Error error;
std::string debug_message;
RefPtr<MessageError>::cast_static(message)->parse(error, debug_message);
ErrLog(<< "Error: " << error.what() << std::endl << debug_message);
// main_loop->quit(); // FIXME - from echoTest
return false;
}
case Gst::MESSAGE_STATE_CHANGED:
DebugLog(<< "state changed");
return true;
case Gst::MESSAGE_NEW_CLOCK:
DebugLog(<< "new clock");
return true;
case Gst::MESSAGE_STREAM_STATUS:
DebugLog(<< "stream status");
return true;
default:
ErrLog(<<"unhandled Bus Message: " << message->get_message_type());
return true;
}
return true;
}
virtual void onOffer(InviteSessionHandle is, const SipMessage& msg, const SdpContents& sdp)
{
InfoLog(<< name << ": InviteSession-onOffer(SDP)");
TestAppDialog* d = dynamic_cast<TestAppDialog*>(is->getAppDialog().get());
const Data& callee = msg.header(h_RequestLine).uri().user();
InfoLog(<< name << ": call is for: " << callee);
std::shared_ptr<SdpContents> offer(dynamic_cast<SdpContents*>(sdp.clone()));
shared_ptr<SdpContents> mSdp = d->mRtpSession->buildAnswer(offer);
//sdp->encode(cout);
InfoLog(<< name << ": starting GStreamer media thread");
d->mRtpSession->initHomer(msg.header(h_CallId).value(), mHepAgent);
if(d->mPipeline)
{
DebugLog(<<"mPipeline already exists");
}
else
{
d->mPipeline = Gst::Pipeline::create();
d->mMediaBin = d->mRtpSession->getMediaBin();
resip_assert(d->mMediaBin);
d->mRtpTransportElement = d->mRtpSession->getRtpTransportBin();
resip_assert(d->mRtpTransportElement);
d->mPipeline->add(d->mMediaBin);
d->mRtpSession->initOutgoingBins();
bool isWebRTC = d->isWebRTCSession();
bool loopbackMode = !isWebRTC;
unsigned int streamCount = d->mRtpSession->getOutgoingCaps().size();
if(streamCount == 0)
{
// sending an offer
InfoLog(<<"creating streams for SDP offer");
// FIXME - these are currently hardcoded in GstRtpSession::buildOffer
//mRtpSession->addStream(Gst::Caps::create_from_string(GST_RTP_CAPS_PCMA));
//mRtpSession->addStream(Gst::Caps::create_from_string(GST_RTP_CAPS_H264));
}
else
{
// received an offer
InfoLog(<<"creating streams for SDP answer");
for(unsigned int streamId = 0; streamId < streamCount; streamId++)
{
d->prepareStream(streamId, loopbackMode);
}
}
// FIXME
RefPtr<Bus> bus = d->mPipeline->get_bus();
bus->add_watch(sigc::mem_fun(*this, &TestUas::onGstBusMessage));
DebugLog(<<"mPipeline and mRtpTransportElement created");
DebugLog(<<"going to STATE_READY");
d->mPipeline->set_state(STATE_READY);
d->mMediaBin->signal_pad_added().connect(sigc::mem_fun(*d, &TestAppDialog::onMediaSourceAdded));
DebugLog(<<"going to STATE_PLAYING");
StateChangeReturn ret = d->mPipeline->set_state(STATE_PLAYING);
if (ret == STATE_CHANGE_FAILURE)
{
ErrLog(<<"pipeline fail");
d->mPipeline.reset();
is->reject(606);
return;
}
d->mRtpSession->onPlaying(); // FIXME - use a signal in GstRtpSession
mSdp = make_shared<SdpContents>(*d->mRtpSession->getLocalSdp());
mMediaThreads[is->getDialogId()] = make_shared<GstThread>();
}
InfoLog(<< name << ": Sending 200 response with SDP answer.");
is->provideAnswer(*mSdp);
mSis->accept();
}
virtual void onOfferRequired(InviteSessionHandle is, const SipMessage& msg)
{
InfoLog(<< name << ": InviteSession-onOfferRequired - " << msg.brief());
shared_ptr<SdpContents> mSdp;
if(!mSdp)
{
TestAppDialog* d = dynamic_cast<TestAppDialog*>(is->getAppDialog().get());
mSdp = d->mRtpSession->buildOffer(true, true);
}
is->provideOffer(*mSdp);
}
virtual void onConnected(InviteSessionHandle is, const SipMessage& msg)
{
InfoLog(<< name << ": InviteSession-onConnected - " << msg.brief());
// At this point no NIT should have been sent
resip_assert(!is->getLastSentNITRequest());
}
virtual void onInfoSuccess(InviteSessionHandle is, const SipMessage& msg)
{
InfoLog(<< name << ": InviteSession-onInfoSuccess - " << msg.brief());
}
virtual void onMessage(InviteSessionHandle is, const SipMessage& msg)
{
InfoLog(<< name << ": InviteSession-onMessage - " << msg.brief());
is->acceptNIT();
}
// Normal people wouldn't put this functionality in the handler
// it's a kludge for this test for right now
void hangup()
{
if (mSis.isValid())
{
InfoLog(<< name << ": Sending BYE.");
mSis->end();
done = true;
}
}
private:
ServerInviteSessionHandle mSis;
};
class TestShutdownHandler : public DumShutdownHandler
{
public:
TestShutdownHandler(const Data& n) : name(n), dumShutDown(false) { }
virtual ~TestShutdownHandler(){}
Data name;
bool dumShutDown;
virtual void onDumCanBeDeleted()
{
InfoLog(<< name << ": onDumCanBeDeleted.");
dumShutDown = true;
}
};
class EchoTestServer : public resip::ServerProcess
{
private:
SipStack* stackUas;
DialogUsageManager* dumUas;
std::shared_ptr<resipgst::GstRtpManager> mRtpManager;
public:
EchoTestServer() :
stackUas(nullptr),
dumUas(nullptr)
{
};
~EchoTestServer()
{
delete dumUas;
delete stackUas;
};
int
main (int argc, char** argv)
{
installSignalHandler();
Data defaultConfigFilename("echoTest.config");
EchoTestConfig echoTestConfig;
try
{
echoTestConfig.parseConfig(argc, argv, defaultConfigFilename);
}
catch(std::exception& e)
{
ErrLog(<< "Exception parsing configuration: " << e.what());
return -1;
}
Log::initialize(echoTestConfig, argv[0]);
Data captureHost = echoTestConfig.getConfigData("CaptureHost", "");
int capturePort = echoTestConfig.getConfigInt("CapturePort", 9060);
int captureAgentID = echoTestConfig.getConfigInt("CaptureAgentID", 2002);
// For GStreamer
const char* _argv[] = { argv[0], "--gst-debug", "5", NULL };
int _argc = 3;
char** __argv = (char**)_argv;
// FIXME: are there C++ equivalents of these functions?
gst_debug_remove_log_function (gst_debug_log_default);
gst_debug_add_log_function(gst2resip_log_function, nullptr, nullptr);
Gst::init(_argc, __argv);
#if defined(WIN32) && defined(_DEBUG) && defined(LEAK_CHECK)
FindMemoryLeaks fml;
{
#endif
bool doReg = echoTestConfig.getConfigBool("Register", false);
Data uasPasswd;
int uasUdpPort = echoTestConfig.getConfigInt("UDPPort", 12010);
int uasTcpPort = echoTestConfig.getConfigInt("TCPPort", 12010);
Uri outboundUri = echoTestConfig.getConfigUri("OutboundProxyUri", Uri());
bool useOutbound = (outboundUri != Uri());
myIP = echoTestConfig.getConfigData("IPAddress", "127.0.0.1");
uasPasswd = echoTestConfig.getConfigData("Password", Data::Empty);
//set up UAS
stackUas = new SipStack();
std::shared_ptr<HepAgent> agent;
if(!captureHost.empty())
{
agent = std::make_shared<HepAgent>(captureHost, capturePort, captureAgentID);
stackUas->setTransportSipMessageLoggingHandler(std::make_shared<HEPSipMessageLoggingHandler>(agent));
}
dumUas = new DialogUsageManager(*stackUas);
NameAddr uasAor;
Uri uasContact;
if(uasUdpPort)
{
stackUas->addTransport(UDP, uasUdpPort);
uasContact = Uri("sip:" + myIP + ":" + Data(uasUdpPort));
}
if(uasTcpPort)
{
stackUas->addTransport(TCP, uasTcpPort);
if(uasContact.port() == 0)
{
uasContact = Uri("sip:" + myIP + ":" + Data(uasTcpPort) + ";transport=tcp");
}
}
if(uasContact.port() == 0)
{
uasContact = Uri("sip:" + myIP);
ErrLog(<<"no port for uasContact");
resip_assert(0);
}
uasAor = echoTestConfig.getConfigNameAddr("SIPUri", NameAddr("sip:UAS@" + myIP + ":" + Data(uasContact.port())));
auto uasMasterProfile = std::make_shared<MasterProfile>();
std::unique_ptr<ClientAuthManager> uasAuth(new ClientAuthManager);
dumUas->setMasterProfile(uasMasterProfile);
dumUas->setClientAuthManager(std::move(uasAuth));
uasMasterProfile->setOverrideHostAndPort(uasContact);
if(doReg)
{
dumUas->getMasterProfile()->setDigestCredential(uasAor.uri().host(), uasAor.uri().user(), uasPasswd);
}
if(useOutbound)
{
dumUas->getMasterProfile()->setOutboundProxy(outboundUri);
dumUas->getMasterProfile()->addSupportedOptionTag(Token(Symbols::Outbound));
}
dumUas->getMasterProfile()->setDefaultFrom(uasAor);
dumUas->getMasterProfile()->addSupportedMethod(INFO);
dumUas->getMasterProfile()->addSupportedMethod(MESSAGE);
dumUas->getMasterProfile()->addSupportedMimeType(INFO, PlainContents::getStaticType());
dumUas->getMasterProfile()->addSupportedMimeType(MESSAGE, PlainContents::getStaticType());
dumUas->getMasterProfile()->setDefaultRegistrationTime(70);
Data pipelineId = echoTestConfig.getConfigData("DefaultPipelineId", "h264avx");
int mediaPortStart = echoTestConfig.getConfigInt("MediaPortStart", 8002);
// FIXME - IPv6 needed
mRtpManager = make_shared<resipgst::GstRtpManager>(myIP, mediaPortStart, mediaPortStart + 100);
mRtpManager->setApplicationName("reSIProcate GStreamer Echo Test");
TestUas uas(pipelineId, agent);
dumUas->setClientRegistrationHandler(&uas);
dumUas->setInviteSessionHandler(&uas);
dumUas->addOutOfDialogHandler(OPTIONS, &uas);
std::unique_ptr<AppDialogSetFactory> uas_dsf(new TestAppDialogSetFactory(mRtpManager));
dumUas->setAppDialogSetFactory(std::move(uas_dsf));
if (!doReg)
{
uas.registered = true;
}
TestShutdownHandler uasShutdownHandler("UAS");
mainLoop();
// FIXME: shutdown the DUM and SipStack
#if defined(WIN32) && defined(_DEBUG) && defined(LEAK_CHECK)
} // FindMemoryLeaks fml
#endif
return 0;
}
void
doWait()
{
stackUas->process(50);
}
void
onLoop()
{
while(dumUas->process());
}
void
onReload()
{
}
};
int main(int argc, char** argv)
{
EchoTestServer proc;
return proc.main(argc, argv);
}
/* ====================================================================
* The Vovida Software License, Version 1.0
*
* Copyright (c) 2022, Software Freedom Institute https://softwarefreedom.institute
* Copyright (c) 2021-2022, Daniel Pocock https://danielpocock.com
* Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The names "VOCAL", "Vovida Open Communication Application Library",
* and "Vovida Open Communication Application Library (VOCAL)" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact vocal@vovida.org.
*
* 4. Products derived from this software may not be called "VOCAL", nor
* may "VOCAL" appear in their name, without prior written
* permission of Vovida Networks, Inc.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
* NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
* IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* ====================================================================
*
* This software consists of voluntary contributions made by Vovida
* Networks, Inc. and many individuals on behalf of Vovida Networks,
* Inc. For more snformation on Vovida Networks, Inc., please see
* <http://www.vovida.org/>.
*
*/

View File

@@ -0,0 +1,9 @@
/Makefile.in
/Makefile
/.deps
/.libs
/.dirstamp
/ichat-gw

View File

@@ -0,0 +1,214 @@
#include "rutil/Logger.hxx"
#include "rutil/ParseBuffer.hxx"
#include "AppSubsystem.hxx"
#include "AddressTranslator.hxx"
#include "rutil/WinLeakCheck.hxx"
#define RESIPROCATE_SUBSYSTEM AppSubsystem::GATEWAY
using namespace gateway;
using namespace resip;
using namespace std;
namespace gateway
{
AddressTranslator::AddressTranslator()
{
}
AddressTranslator::~AddressTranslator()
{
// Destroy all of the filters
for(FilterOpList::iterator it = mFilterOperators.begin(); it != mFilterOperators.end(); it++)
{
if ( it->preq )
{
delete it->preq;
it->preq = 0;
}
}
mFilterOperators.clear();
}
void
AddressTranslator::addTranslation(const resip::Data& matchingPattern,
const resip::Data& rewriteExpression)
{
InfoLog( << "Add translation " << matchingPattern << " -> " << rewriteExpression);
FilterOp filter;
filter.mMatchingPattern = matchingPattern;
filter.mRewriteExpression = rewriteExpression;
if( !filter.mMatchingPattern.empty() )
{
// Note: this code originally used the PCRE (Perl Compatible) regular expression library. The ECMAScript standard is a subset
// of the Perl regular expression syntax. Posix regular expression syntax is quite a bit different (ie: std::regex_contacts::basic or
// std::regex_contacts::extended). To be as backwards compatible with existing regular expressions as possible, we want to
// use the EMCAScript syntax.
const std::regex_constants::syntax_option_type flags = std::regex_constants::ECMAScript;
if( filter.mRewriteExpression.find("$") == Data::npos )
{
flags |= std::regex_constants::nosubs;
}
try
{
filter.preq = new std::regex(filter.mMatchingPattern.c_str(), flags);
}
catch (std::regex_error& ex)
{
delete filter.preq;
ErrLog( << "Translation has invalid match expression: "
<< filter.mMatchingPattern );
filter.preq = 0;
}
}
mFilterOperators.push_back( filter );
}
void
AddressTranslator::removeTranslation(const resip::Data& matchingPattern )
{
FilterOpList::iterator it = mFilterOperators.begin();
while ( it != mFilterOperators.end() )
{
if ( it->mMatchingPattern == matchingPattern )
{
FilterOpList::iterator i = it;
it++;
if ( i->preq )
{
delete i->preq;
i->preq = 0;
}
mFilterOperators.erase(i);
}
else
{
it++;
}
}
}
bool
AddressTranslator::translate(const resip::Data& address, resip::Data& translation, bool failIfNoRule)
{
bool rc=false;
DebugLog( << "Translating "<< address);
for (FilterOpList::iterator it = mFilterOperators.begin();
it != mFilterOperators.end(); it++)
{
Data rewrite = it->mRewriteExpression;
Data& match = it->mMatchingPattern;
if ( it->preq )
{
std::cmatch matches;
// Note: Using regex_search instead of regex_match, so that we don't need to fully match
// the string, this is backwards compatible with the previous regexec PCRE implementation
if(!std::regex_search(address.c_str(), matches, *it->preq))
{
// did not match
DebugLog( << " Skipped translation "<< address << " did not match " << match );
continue;
}
DebugLog( << " Matched translation "<< address << " matched " << match );
translation = rewrite;
rc=true;
if ( rewrite.find("$") != Data::npos )
{
for ( int i=1; i<matches.size(); i++)
{
Data subExp(matches[i]);
DebugLog( << " subExpression[" <<i <<"]="<< subExp );
Data result;
{
DataStream s(result);
ParseBuffer pb(translation);
while (true)
{
const char* a = pb.position();
pb.skipToChars( Data("$") + char('0'+i) );
if ( pb.eof() )
{
s << pb.data(a);
break;
}
else
{
s << pb.data(a);
pb.skipN(2);
s << subExp;
}
}
s.flush();
}
translation = result;
}
}
else
{
translation = rewrite;
rc = true;
}
break;
}
}
// If we didn't find a translation and we are not suppossed to fail, then just return address
if(!rc && !failIfNoRule)
{
rc = true;
translation = address;
}
InfoLog( << "Translated "<< address << " to " << translation);
return rc;
}
}
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

View File

@@ -0,0 +1,74 @@
#if !defined(AddressTranslator_hxx)
#define AddressTranslator_hxx
#include <list>
#include <regex>
namespace gateway
{
class AddressTranslator
{
public:
AddressTranslator();
~AddressTranslator();
void addTranslation(const resip::Data& matchingPattern,
const resip::Data& rewriteExpression);
void removeTranslation(const resip::Data& matchingPattern);
bool translate(const resip::Data& address, resip::Data& translation, bool failIfNoRule=false);
private:
class FilterOp
{
public:
resip::Data mMatchingPattern;
resip::Data mRewriteExpression;
std::regex *preq;
};
typedef std::list<FilterOp> FilterOpList;
FilterOpList mFilterOperators;
};
}
#endif
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

View File

@@ -0,0 +1,38 @@
#include "AppSubsystem.hxx"
AppSubsystem AppSubsystem::GATEWAY("GATEWAY");
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

View File

@@ -0,0 +1,61 @@
#if !defined(AppSubsystem_hxx)
#define AppSubsystem_hxx
#include <iostream>
#include <rutil/Subsystem.hxx>
/**
This class is used in the logging subsystem to identify
logging messages generated from the iChat Gateway.
Author: Scott Godin (sgodin AT SipSpectrum DOT com)
*/
class AppSubsystem : public resip::Subsystem
{
public:
// Add new systems below
static AppSubsystem GATEWAY;
private:
explicit AppSubsystem(const char* rhs) : resip::Subsystem(rhs) {};
explicit AppSubsystem(const resip::Data& rhs);
AppSubsystem& operator=(const resip::Data& rhs);
};
#endif
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,176 @@
#if !defined(B2BSession_hxx)
#define B2BSession_hxx
#include <rutil/Log.hxx>
#include <resip/dum/DialogUsageManager.hxx>
#include <resip/dum/InviteSessionHandler.hxx>
#include <resip/dum/DialogSetHandler.hxx>
#include <resip/dum/AppDialogSet.hxx>
#include <memory>
namespace gateway
{
class Server;
class IChatIPPortData;
typedef unsigned int B2BSessionHandle;
class B2BSession : public resip::AppDialogSet
{
public:
B2BSession(Server& server, bool hasDialogSet=true);
virtual ~B2BSession();
virtual void end();
void setPeer(B2BSession* peer);
B2BSession* getPeer();
void stealPeer(B2BSession* victimSession);
B2BSessionHandle getB2BSessionHandle() const { return mHandle; }
void initiateIChatCallRequest(const std::string& to, const std::string& from);
bool createNewPeer(const resip::Uri& destinationUri, const resip::NameAddr& from, const resip::SdpContents *sdp);
void startIChatCall(const resip::Uri& destinationUri, const resip::NameAddr& from, const resip::SdpContents *sdp);
void startSIPCall(const resip::Uri& destinationUri, const resip::NameAddr& from, const resip::SdpContents *sdp);
bool checkIChatCallMatch(const resip::SipMessage& msg);
// iChat call notifications from Jabber Component
void notifyIChatCallCancelled();
void notifyIChatCallProceeding(const std::string& to);
void notifyIChatCallFailed(unsigned int statusCode);
void continueIChatCall(const std::string& remoteIPPortListBlob);
void timeoutIChatCall();
// IPC messages for Jabber Component
void initiateIChatCall();
void cancelIChatCall();
void proceedingIChatCall();
void acceptIChatCall();
void rejectIChatCall();
protected:
friend class Server;
virtual std::shared_ptr<resip::UserProfile> selectUASUserProfile(const resip::SipMessage& msg);
// Invite Session Handler /////////////////////////////////////////////////////
virtual void onNewSession(resip::ClientInviteSessionHandle h, resip::InviteSession::OfferAnswerType oat, const resip::SipMessage& msg);
virtual void onNewSession(resip::ServerInviteSessionHandle h, resip::InviteSession::OfferAnswerType oat, const resip::SipMessage& msg);
virtual void onFailure(resip::ClientInviteSessionHandle h, const resip::SipMessage& msg);
virtual void onEarlyMedia(resip::ClientInviteSessionHandle, const resip::SipMessage&, const resip::SdpContents&);
virtual void onProvisional(resip::ClientInviteSessionHandle, const resip::SipMessage& msg);
virtual void onConnected(resip::ClientInviteSessionHandle h, const resip::SipMessage& msg);
virtual void onConnected(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual void onStaleCallTimeout(resip::ClientInviteSessionHandle);
virtual void onTerminated(resip::InviteSessionHandle h, resip::InviteSessionHandler::TerminatedReason reason, const resip::SipMessage* msg);
virtual void onRedirected(resip::ClientInviteSessionHandle, const resip::SipMessage& msg);
virtual void onAnswer(resip::InviteSessionHandle, const resip::SipMessage& msg, const resip::SdpContents&);
virtual void onOffer(resip::InviteSessionHandle handle, const resip::SipMessage& msg, const resip::SdpContents& offer);
virtual void onOfferRequired(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual void onOfferRejected(resip::InviteSessionHandle, const resip::SipMessage* msg);
virtual void onOfferRequestRejected(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual void onRemoteSdpChanged(resip::InviteSessionHandle, const resip::SipMessage& msg, const resip::SdpContents& sdp);
virtual void onInfo(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual void onInfoSuccess(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual void onInfoFailure(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual void onRefer(resip::InviteSessionHandle, resip::ServerSubscriptionHandle, const resip::SipMessage& msg);
virtual void onReferAccepted(resip::InviteSessionHandle, resip::ClientSubscriptionHandle, const resip::SipMessage& msg);
virtual void onReferRejected(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual bool doReferNoSub(const resip::SipMessage& msg);
virtual void onReferNoSub(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual void onMessage(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual void onMessageSuccess(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual void onMessageFailure(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual void onForkDestroyed(resip::ClientInviteSessionHandle);
// DialogSetHandler //////////////////////////////////////////////
virtual void onTrying(resip::AppDialogSetHandle, const resip::SipMessage& msg);
virtual void onNonDialogCreatingProvisional(resip::AppDialogSetHandle, const resip::SipMessage& msg);
// ClientSubscriptionHandler ///////////////////////////////////////////////////
virtual void onUpdatePending(resip::ClientSubscriptionHandle h, const resip::SipMessage& notify, bool outOfOrder);
virtual void onUpdateActive(resip::ClientSubscriptionHandle h, const resip::SipMessage& notify, bool outOfOrder);
virtual void onUpdateExtension(resip::ClientSubscriptionHandle, const resip::SipMessage& notify, bool outOfOrder);
virtual void onTerminated(resip::ClientSubscriptionHandle h, const resip::SipMessage* notify);
virtual void onNewSubscription(resip::ClientSubscriptionHandle h, const resip::SipMessage& notify);
virtual int onRequestRetry(resip::ClientSubscriptionHandle h, int retryMinimum, const resip::SipMessage& notify);
private:
bool buildLocalOffer(resip::SdpContents& sdp);
bool buildLocalAnswer(resip::SdpContents& sdp);
bool provideLocalAnswer(void);
void endPeer();
bool isUACConnected();
bool isStaleFork(const resip::DialogId& dialogId);
void fixupSdp(const resip::SdpContents& origSdp, resip::SdpContents& fixedSdp);
unsigned int mapRejectionCodeForIChat(unsigned int statusCode);
Server& mServer;
bool mHasDialogSet;
resip::DialogUsageManager& mDum;
B2BSession* mPeer;
resip::InviteSessionHandle mInviteSessionHandle;
B2BSessionHandle mHandle;
resip::AppDialogSetHandle mReferringAppDialogSet;
// State information
resip::DialogId mUACConnectedDialogId;
bool mWaitingOfferFromPeer;
bool mWaitingAnswerFromPeer;
bool mWaitingNitAnswerFromPeer;
bool mAnchorMedia;
unsigned short mMediaRelayPort;
// IChat specific endpoint info
bool mIChatEndpoint;
bool mIChatWaitingToAccept;
bool mIChatWaitingToProceed;
bool mIChatWaitingToContinue;
resip::Uri mIChatDestination;
resip::NameAddr mIChatFrom;
resip::SdpContents* mIChatSdp;
std::string mIChatCallToJID;
std::string mIChatCallFromJID;
};
}
#endif
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

View File

@@ -0,0 +1,40 @@
set(INCLUDES
AddressTranslator.hxx
AppSubsystem.hxx
B2BSession.hxx
ConfigParser.hxx
IChatGatewayCmds.hxx
IChatIPPortData.hxx
IPCThread.hxx
MediaRelay.hxx
MediaRelayPort.hxx
Server.hxx
SipRegistration.hxx
Thread.hxx
Version.hxx
)
add_executable(ichat-gw
AddressTranslator.cxx
AppSubsystem.cxx
B2BSession.cxx
ConfigParser.cxx
ichat-gw.cxx
IChatIPPortData.cxx
IPCThread.cxx
MediaRelay.cxx
MediaRelayPort.cxx
Server.cxx
SipRegistration.cxx
Thread.cxx
${INCLUDES}
)
target_include_directories(ichat-gw PRIVATE ${PCRE_INCLUDE_DIRS})
target_link_libraries(ichat-gw PUBLIC dum ${PCRE_LIBRARIES})
install(TARGETS ichat-gw DESTINATION ${CMAKE_INSTALL_SBINDIR})
install_and_preserve_hierarchy(${CMAKE_INSTALL_INCLUDEDIR}/ichat-gw ${INCLUDES})
add_subdirectory(jabberconnector)

View File

@@ -0,0 +1,443 @@
#include "ConfigParser.hxx"
#include "Server.hxx"
#include "AppSubsystem.hxx"
#include <iostream>
#include <fstream>
#include <iterator>
#include <rutil/DnsUtil.hxx>
#include <rutil/Log.hxx>
#include <rutil/Logger.hxx>
#include <rutil/WinLeakCheck.hxx>
using namespace gateway;
using namespace resip;
using namespace std;
#define RESIPROCATE_SUBSYSTEM AppSubsystem::GATEWAY
namespace gateway
{
ConfigParser::ConfigParser(int argc, char** argv) :
// Defaults
mSipPort(5070),
mTlsPort(5071),
mTlsDomain(DnsUtil::getLocalHostName()),
mRegistrationTime(3600),
mRegistrationRetryTime(120),
mKeepAlives(true),
mLogLevel("INFO"),
mLogFilename("ichat-gw.log"),
mLogFileMaxLines(50000), // 50000 is about 5M size
mGatewayIPCPort(2078),
mJabberConnectorIPCPort(2079),
mHttpPort(5090),
mHttpAuth(false),
mHttpAuthPwd("admin"),
mIChatProceedingTimeout(5000),
mAlwaysRelayIChatMedia(true),
mPreferIPv6(false),
mSkipFirstIChatAddress(false),
mMediaRelayPortRangeMin(8000),
mMediaRelayPortRangeMax(9999),
mJabberComponentPort(5275),
mJabberServerPingDuration(60) // 1 min
{
// Parse config file first
parseConfigFile("ichat-gw.config");
// Parse command line options
// Note: command line overrides config file setting
parseCommandLine(argc, argv);
}
ConfigParser::~ConfigParser()
{
}
void
ConfigParser::parseCommandLine(int argc, char** argv)
{
// Loop through command line arguments and process them
for(int i = 1; i < argc; i++)
{
Data commandName(argv[i]);
// Process all commandNames that don't take values
if(isEqualNoCase(commandName, "-?") ||
isEqualNoCase(commandName, "--?") ||
isEqualNoCase(commandName, "--help") ||
isEqualNoCase(commandName, "/?"))
{
cout << "Command line options are:" << endl;
cout << " -a <IP Address> - bind SIP transports to this IP address" << endl;
cout << " -d <DNS servers> - comma seperated list of DNS servers, overrides OS detected list" << endl;
cout << " -gi <Gateway identity> - used in From header of click-to-call requests to initiator" << endl;
cout << " -sp <port num> - local port number to use for SIP messaging (UDP/TCP)" << endl;
cout << " -tp <port num> - local port number to use for TLS SIP messaging" << endl;
cout << " -td <domain name> - domain name to use for TLS server connections" << endl;
cout << " -nk - no keepalives, set this to disable sending of keepalives" << endl;
cout << " -op <SIP URI> - URI of a proxy server to use a SIP outbound proxy" << endl;
cout << " -l <NONE|CRIT|ERR|WARNING|INFO|DEBUG|STACK> - logging level" << endl;
cout << endl;
cout << "Sample Command line:" << endl;
cout << "ichat-gw -a 192.168.1.100 -l DEBUG" << endl;
exit(0);
}
else if(isEqualNoCase(commandName, "-nk"))
{
mKeepAlives = false;
}
else if(commandName.at(0) == '-')
{
commandName = commandName.substr(1); // Remove -
// Process commands that have values
Data commandValue(i+1 < argc ? argv[i+1] : Data::Empty);
if(commandValue.empty() || commandValue.at(0) == '-')
{
cerr << "Invalid command line parameters!" << endl;
exit(-1);
}
i++; // increment argument
//cout << "Command Line Name='" << commandName << "' value='" << commandValue << "'" << endl;
if(!processOption(commandName.lowercase(), commandValue))
{
cerr << "Invalid command line parameters!" << endl;
exit(-1);
}
}
else
{
cerr << "Invalid command line parameters!" << endl;
exit(-1);
}
}
}
void
ConfigParser::parseConfigFile(const Data& filename)
{
ifstream configFile(filename.c_str());
string sline;
while(getline(configFile, sline))
{
Data line(sline);
Data name;
Data value;
ParseBuffer pb(line);
pb.skipWhitespace();
const char * anchor = pb.position();
if(pb.eof() || *anchor == '#') continue; // if line is a comment or blank then skip it
// Look for =
pb.skipToOneOf("= \t");
if(!pb.eof())
{
pb.data(name,anchor);
if(*pb.position()!='=')
{
pb.skipToChar('=');
}
pb.skipChar('=');
pb.skipWhitespace();
anchor = pb.position();
if(!pb.eof())
{
pb.skipToEnd();
pb.data(value, anchor);
}
//cout << "Config file Name='" << name << "' value='" << value << "'" << endl;
processOption(name.lowercase(), value);
}
}
}
bool
ConfigParser::assignOnOffSetting(const Data& value, bool& setting)
{
if(value == "1" || value == "true" || value == "on" || value == "enable")
{
setting = true;
return true;
}
else if(value == "0" || value == "false" || value == "off" || value == "disable")
{
setting = false;
return true;
}
return false;
}
bool
ConfigParser::processOption(const Data& name, const Data& value)
{
bool result = true;
if(name == "a" || name == "ipaddress")
{
mAddress = value;
}
else if(name == "d" || name == "dnsservers")
{
if(!value.empty()) mDnsServers.clear(); // allow command line to override config file, since list is added to
// DNS Servers
ParseBuffer pb(value);
Data dnsServer;
while(!value.empty() && !pb.eof())
{
pb.skipWhitespace();
const char *start = pb.position();
pb.skipToOneOf(ParseBuffer::Whitespace, ";,"); // allow white space
pb.data(dnsServer, start);
if(DnsUtil::isIpV4Address(dnsServer))
{
mDnsServers.push_back(Tuple(dnsServer, 0, UNKNOWN_TRANSPORT).toGenericIPAddress());
}
else
{
cerr << "Tried to add dns server, but invalid format: " << value << endl;
result = false;
}
if(!pb.eof())
{
pb.skipChar();
}
}
}
else if(name == "gi" || name == "sipgatewayidentity")
{
result = assignNameAddr("sip gateway identity", value, mGatewayIdentity);
}
else if(name == "sp" || name == "udptcpport")
{
mSipPort = (unsigned short)value.convertUnsignedLong();
}
else if(name == "tp" || name == "tlsport")
{
mTlsPort = (unsigned short)value.convertUnsignedLong();
}
else if(name == "td" || name == "tlsdomain")
{
mTlsDomain = value;
}
else if(name == "keepalives")
{
assignOnOffSetting(value, mKeepAlives);
}
else if(name == "op" || name == "outboundproxy")
{
result = assignNameAddr("outbound proxy", value, mOutboundProxy);
}
else if(name == "registrationtime")
{
mRegistrationTime = value.convertUnsignedLong();
}
else if(name == "registrationretrytime")
{
mRegistrationRetryTime = value.convertUnsignedLong();
}
else if(name == "l" || name == "loglevel")
{
mLogLevel = value;
}
else if(name == "logfilename")
{
mLogFilename = value;
}
else if(name == "logfilemaxlines")
{
mLogFileMaxLines = value.convertUnsignedLong();
}
else if(name == "gatewayipcport")
{
mGatewayIPCPort = (unsigned short)value.convertUnsignedLong();
}
else if(name == "jabberconnectoripcport")
{
mJabberConnectorIPCPort = (unsigned short)value.convertUnsignedLong();
}
else if(name == "httpport")
{
mHttpPort = (unsigned short)value.convertUnsignedLong();
}
else if(name == "httpauth")
{
assignOnOffSetting(value, mHttpAuth);
}
else if(name == "httpauthpwd")
{
mHttpAuthPwd = value;
}
else if(name == "ichatproceedingtimeout")
{
mIChatProceedingTimeout = value.convertUnsignedLong();
}
else if(name == "alwaysrelayichatmedia")
{
assignOnOffSetting(value, mAlwaysRelayIChatMedia);
}
else if(name == "preferipv6")
{
assignOnOffSetting(value, mPreferIPv6);
}
else if(name == "skipfirstichataddress")
{
assignOnOffSetting(value, mSkipFirstIChatAddress);
}
else if(name == "codecidfilterlist")
{
ParseBuffer pb(value);
Data codecId;
while(!value.empty() && !pb.eof())
{
pb.skipWhitespace();
const char *start = pb.position();
pb.skipToOneOf(ParseBuffer::Whitespace, ";,"); // allow white space
pb.data(codecId, start);
mCodecIdFilterList.insert((unsigned short)codecId.convertUnsignedLong());
if(!pb.eof())
{
pb.skipChar();
}
}
}
else if(name == "mediarelayportrangemin")
{
mMediaRelayPortRangeMin = (unsigned short)value.convertUnsignedLong();
}
else if(name == "mediarelayportrangemax")
{
mMediaRelayPortRangeMax = (unsigned short)value.convertUnsignedLong();
}
else if(name == "translationpattern")
{
mAddressTranslations.push_back(std::make_pair(value, Data::Empty));
}
else if(name == "translationoutput")
{
if(!mAddressTranslations.empty())
{
mAddressTranslations.back().second = value;
}
}
else if(name == "jabberserver")
{
mJabberServer = value;
}
else if(name == "jabbercomponentname")
{
mJabberComponentName = value;
}
else if(name == "jabbercomponentpassword")
{
mJabberComponentPassword = value;
}
else if(name == "jabbercomponentport")
{
mJabberComponentPort = (unsigned short)value.convertUnsignedLong();
}
else if(name == "jabberserverpingduration")
{
mJabberServerPingDuration = value.convertUnsignedLong();
}
else if(name == "jabbercontrolusername")
{
mJabberControlUsername = value;
}
else if(name == "tlsdhparamsfilename")
{
mTLSDHParamsFilename = value;
}
else if(name == "tlscertificate")
{
mTLSCertificate = value;
}
else if(name == "tlsprivateKey")
{
mTLSPrivateKey = value;
}
else if(name == "tlsprivatekeypassphrase")
{
mTLSPrivateKeyPassPhrase = value;
}
else if(name == "ichatjabberconnectorpath")
{
mIchatJabberConnectorPath = value;
}
else
{
result = false;
}
return result;
}
bool
ConfigParser::assignNameAddr(const Data& settingName, const Data& settingValue, NameAddr& nameAddr)
{
try
{
if(!settingValue.empty())
{
NameAddr tempNameAddr(settingValue);
nameAddr = tempNameAddr;
}
}
catch(resip::BaseException& e)
{
// Try adding sip: to address to see if it will be valid
try
{
NameAddr tempNameAddr(Data("sip:" + settingValue));
nameAddr = tempNameAddr;
}
catch(resip::BaseException&)
{
cerr << "Invalid " << settingName << " NameAddr format=" << settingValue << ": " << e << endl;
return false;
}
}
return true;
}
}
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

View File

@@ -0,0 +1,110 @@
#if !defined(ConfigParser_hxx)
#define ConfigParser_hxx
#include <list>
#include <resip/dum/MasterProfile.hxx>
#include <rutil/dns/DnsStub.hxx>
#include <rutil/Log.hxx>
namespace gateway
{
class ConfigParser
{
public:
ConfigParser(int argc, char** argv);
virtual ~ConfigParser();
resip::Data mAddress;
resip::DnsStub::NameserverList mDnsServers;
resip::NameAddr mGatewayIdentity;
unsigned short mSipPort;
unsigned short mTlsPort;
resip::Data mTlsDomain;
resip::NameAddr mOutboundProxy;
unsigned int mRegistrationTime;
unsigned int mRegistrationRetryTime;
bool mKeepAlives;
resip::Data mLogLevel;
resip::Data mLogFilename;
unsigned int mLogFileMaxLines;
unsigned short mGatewayIPCPort;
unsigned short mJabberConnectorIPCPort;
unsigned short mHttpPort;
bool mHttpAuth;
resip::Data mHttpAuthPwd;
unsigned int mIChatProceedingTimeout;
bool mAlwaysRelayIChatMedia;
bool mPreferIPv6;
bool mSkipFirstIChatAddress; // (for testing): skipping the first IPV4 NAT mapped address (on systems with one interface) causes the local address to be used
typedef std::set<unsigned short> CodecIdList;
CodecIdList mCodecIdFilterList;
unsigned short mMediaRelayPortRangeMin;
unsigned short mMediaRelayPortRangeMax;
typedef std::list<std::pair<resip::Data,resip::Data> > TranslationList;
TranslationList mAddressTranslations;
// Jabber specific settings
resip::Data mJabberServer;
resip::Data mJabberComponentName;
resip::Data mJabberComponentPassword;
unsigned short mJabberComponentPort;
unsigned int mJabberServerPingDuration;
resip::Data mJabberControlUsername;
// TLS specific settings
resip::Data mTLSDHParamsFilename;
resip::Data mTLSCertificate;
resip::Data mTLSPrivateKey;
resip::Data mTLSPrivateKeyPassPhrase;
// iChat Jabber Connector file path
resip::Data mIchatJabberConnectorPath;
private:
void parseCommandLine(int argc, char** argv);
void parseConfigFile(const resip::Data& filename);
bool processOption(const resip::Data& name, const resip::Data& value);
bool assignNameAddr(const resip::Data& settingName, const resip::Data& settingValue, resip::NameAddr& nameAddr);
bool assignOnOffSetting(const resip::Data& value, bool& setting);
};
}
#endif
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

View File

@@ -0,0 +1,182 @@
#if !defined(IChatGatewayCmds_hxx)
#define IChatGatewayCmds_hxx
#include <resip/dum/DumCommand.hxx>
#include "Server.hxx"
#include "B2BSession.hxx"
#define RESIPROCATE_SUBSYSTEM AppSubsystem::GATEWAY
namespace gateway
{
/**
The classes defined here are used to pass commands from the
application thread to the DUM thread (process loop).
This ensures thread safety of the external Server methods.
Author: Scott Godin (sgodin AT SipSpectrum DOT com)
*/
class NotifyIChatCallRequestCmd : public resip::DumCommand
{
public:
NotifyIChatCallRequestCmd(Server& server, const std::string& to, const std::string& from)
: mServer(server), mTo(to), mFrom(from) {}
virtual void executeCommand()
{
mServer.notifyIChatCallRequestImpl(mTo, mFrom);
}
resip::Message* clone() const { resip_assert(0); return 0; }
EncodeStream& encode(EncodeStream& strm) const { strm << " NotifyIChatCallRequestCmd: "; return strm; }
EncodeStream& encodeBrief(EncodeStream& strm) const { return encode(strm); }
private:
Server& mServer;
std::string mTo;
std::string mFrom;
};
class NotifyIChatCallCancelledCmd : public resip::DumCommand
{
public:
NotifyIChatCallCancelledCmd(Server& server, const B2BSessionHandle& handle)
: mServer(server), mHandle(handle) {}
virtual void executeCommand()
{
mServer.notifyIChatCallCancelledImpl(mHandle);
}
resip::Message* clone() const { resip_assert(0); return 0; }
EncodeStream& encode(EncodeStream& strm) const { strm << " NotifyIChatCallCancelledCmd: "; return strm; }
EncodeStream& encodeBrief(EncodeStream& strm) const { return encode(strm); }
private:
Server& mServer;
B2BSessionHandle mHandle;
};
class NotifyIChatCallProceedingCmd : public resip::DumCommand
{
public:
NotifyIChatCallProceedingCmd(Server& server, const B2BSessionHandle& handle, const std::string& to)
: mServer(server), mHandle(handle), mTo(to) {}
virtual void executeCommand()
{
mServer.notifyIChatCallProceedingImpl(mHandle, mTo);
}
resip::Message* clone() const { resip_assert(0); return 0; }
EncodeStream& encode(EncodeStream& strm) const { strm << " NotifyIChatCallProceedingCmd: "; return strm; }
EncodeStream& encodeBrief(EncodeStream& strm) const { return encode(strm); }
private:
Server& mServer;
B2BSessionHandle mHandle;
std::string mTo;
};
class NotifyIChatCallFailedCmd : public resip::DumCommand
{
public:
NotifyIChatCallFailedCmd(Server& server, const B2BSessionHandle& handle, unsigned int statusCode)
: mServer(server), mHandle(handle), mStatusCode(statusCode) {}
virtual void executeCommand()
{
mServer.notifyIChatCallFailedImpl(mHandle, mStatusCode);
}
resip::Message* clone() const { resip_assert(0); return 0; }
EncodeStream& encode(EncodeStream& strm) const { strm << " NotifyIChatCallFailedCmd: "; return strm; }
EncodeStream& encodeBrief(EncodeStream& strm) const { return encode(strm); }
private:
Server& mServer;
B2BSessionHandle mHandle;
unsigned int mStatusCode;
};
class ContinueIChatCallCmd : public resip::DumCommand
{
public:
ContinueIChatCallCmd(Server& server, const B2BSessionHandle& handle, const std::string& remoteIPPortListBlob)
: mServer(server), mHandle(handle), mRemoteIPPortListBlob(remoteIPPortListBlob) {}
virtual void executeCommand()
{
mServer.continueIChatCallImpl(mHandle, mRemoteIPPortListBlob);
}
resip::Message* clone() const { resip_assert(0); return 0; }
EncodeStream& encode(EncodeStream& strm) const { strm << " ContinueIChatCallCmd: "; return strm; }
EncodeStream& encodeBrief(EncodeStream& strm) const { return encode(strm); }
private:
Server& mServer;
B2BSessionHandle mHandle;
std::string mRemoteIPPortListBlob;
};
class SipRegisterJabberUserCmd : public resip::DumCommand
{
public:
SipRegisterJabberUserCmd(Server& server, const std::string& jidToRegister)
: mServer(server), mJidToRegister(jidToRegister) {}
virtual void executeCommand()
{
mServer.sipRegisterJabberUserImpl(mJidToRegister);
}
resip::Message* clone() const { resip_assert(0); return 0; }
EncodeStream& encode(EncodeStream& strm) const { strm << " SipRegisterJabberUserCmd: "; return strm; }
EncodeStream& encodeBrief(EncodeStream& strm) const { return encode(strm); }
private:
Server& mServer;
std::string mJidToRegister;
};
class SipUnregisterJabberUserCmd : public resip::DumCommand
{
public:
SipUnregisterJabberUserCmd(Server& server, const std::string& jidToUnregister)
: mServer(server), mJidToUnregister(jidToUnregister) {}
virtual void executeCommand()
{
mServer.sipUnregisterJabberUserImpl(mJidToUnregister);
}
resip::Message* clone() const { resip_assert(0); return 0; }
EncodeStream& encode(EncodeStream& strm) const { strm << " SipUnregisterJabberUserCmd: "; return strm; }
EncodeStream& encodeBrief(EncodeStream& strm) const { return encode(strm); }
private:
Server& mServer;
std::string mJidToUnregister;
};
}
#endif
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

View File

@@ -0,0 +1,169 @@
#if defined(HAVE_CONFIG_H)
#include "config.h"
#endif
#include <rutil/Logger.hxx>
#include <resip/stack/Helper.hxx>
#include "AppSubsystem.hxx"
#include "IChatIPPortData.hxx"
#include <rutil/WinLeakCheck.hxx>
#define RESIPROCATE_SUBSYSTEM AppSubsystem::GATEWAY
using namespace gateway;
using namespace resip;
using namespace std;
namespace gateway
{
typedef struct
{
unsigned short initialPad;
unsigned short family;
char interfaceName[16];
char ipAddress[16];
unsigned short port;
unsigned short finalPad;
} IPPortDataBlob;
IChatIPPortData::IChatIPPortData()
{
}
IChatIPPortData::IChatIPPortData(const std::string& hexblob) : mHexBlob(hexblob)
{
unsigned int pad = 0;
// Note: gloox passes us an initial line feed, so be tollerant of this
if(hexblob.at(0) == 0xa)
{
pad = 1;
}
// Convert hexblob to binary blob
if(((hexblob.size()-pad) % 40) != 0)
{
ErrLog(<< "Data size provided for IChatIPPortData is not correct, size=" << hexblob.size());
return;
}
Data blob((unsigned int)hexblob.size()-1 / 2, Data::Preallocate);
for(unsigned int i = pad; i < hexblob.size(); i=i+8)
{
unsigned int block = ntohl(Helper::hex2integer(&hexblob.at(i)));
blob.append((const char*)&block, 4);
}
for(unsigned int j = 0; j < blob.size(); j=j+40)
{
IPPortDataBlob* ipPortDataBlob = (IPPortDataBlob*)(blob.data()+j);
if(ipPortDataBlob->family == V4)
{
in_addr addr;
memcpy(&addr, ipPortDataBlob->ipAddress, 4);
addIPPortData(Data(ipPortDataBlob->interfaceName), Tuple(addr,ntohs(ipPortDataBlob->port),UDP));
}
else
{
#ifdef USE_IPV6
in6_addr addr;
memcpy(&addr, ipPortDataBlob->ipAddress, 16);
addIPPortData(Data(ipPortDataBlob->interfaceName), Tuple(addr,ntohs(ipPortDataBlob->port),UDP));
#else
ErrLog(<< "IPv6 support not enabled at compile time.");
resip_assert(0);
#endif
}
InfoLog(<< "IChatIPPortData: name=" << mIPPortDataList.back().first << " addr=" << mIPPortDataList.back().second);
}
}
void
IChatIPPortData::addIPPortData(const Data& name, const Tuple& ipPortData)
{
mIPPortDataList.push_back(std::make_pair(name, ipPortData));
mHexBlob.clear(); // clear any existing blob string - it will now need to be re-generated if requested
}
std::string&
IChatIPPortData::hexBlob()
{
if(mHexBlob.empty())
{
Data dataBlob((int)mIPPortDataList.size() * sizeof(IPPortDataBlob), Data::Preallocate);
IPPortDataList::const_iterator it;
for(it = mIPPortDataList.begin(); it != mIPPortDataList.end(); it++)
{
IPPortDataBlob ipPortDataBlob;
memset(&ipPortDataBlob, 0, sizeof(ipPortDataBlob));
memcpy(ipPortDataBlob.interfaceName, it->first.data(), it->first.size() < 16 ? it->first.size() : 16);
ipPortDataBlob.port = htons(it->second.getPort());
if(it->second.ipVersion() == V4)
{
ipPortDataBlob.family = V4;
memcpy(ipPortDataBlob.ipAddress, &reinterpret_cast<const sockaddr_in&>(it->second.getSockaddr()).sin_addr, 4);
}
else
{
ipPortDataBlob.family = V6;
memcpy(ipPortDataBlob.ipAddress, &reinterpret_cast<const sockaddr_in6&>(it->second.getSockaddr()).sin6_addr, 16);
}
dataBlob.append((const char*)&ipPortDataBlob, sizeof(ipPortDataBlob));
}
// Hexify
for(unsigned int i = 0; i < dataBlob.size(); i=i+4)
{
unsigned int block;
memcpy(&block, dataBlob.data()+i, 4);
char hexBlock[8];
Helper::integer2hex(hexBlock, htonl(block));
mHexBlob.append(hexBlock, 8);
}
}
return mHexBlob;
}
const IChatIPPortData::IPPortDataList&
IChatIPPortData::getIPPortDataList() const
{
return mIPPortDataList;
}
}
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

View File

@@ -0,0 +1,66 @@
#if !defined(IChatIPPortData_hxx)
#define IChatIPPortData_hxx
#include <list>
#include <string>
#include "rutil/Data.hxx"
#include "resip/stack/Tuple.hxx"
namespace gateway
{
class IChatIPPortData
{
public:
typedef std::list<std::pair<resip::Data,resip::Tuple> > IPPortDataList;
IChatIPPortData();
IChatIPPortData(const std::string& hexblob);
void addIPPortData(const resip::Data& name, const resip::Tuple& ipPortData);
std::string& hexBlob();
const IPPortDataList& getIPPortDataList() const;
private:
IPPortDataList mIPPortDataList;
std::string mHexBlob;
};
}
#endif
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

View File

@@ -0,0 +1,281 @@
#include "rutil/ResipAssert.h"
#include <iostream>
#include <sstream>
#include <string.h>
#ifdef WIN32
#include <WS2tcpip.h>
#else
#include <sys/fcntl.h>
#include <unistd.h>
#endif
#include "IPCThread.hxx"
using namespace gateway;
using namespace std;
#ifdef WIN32
#define EADDRINUSE WSAEADDRINUSE
#define EWOULDBLOCK WSAEWOULDBLOCK
#define sleepMs(t) Sleep(t)
#else
#define sleepMs(t) usleep(t*1000)
#endif
IPCThread::IPCThread(unsigned short localPort, unsigned short remotePort, IPCHandler* handler, IPCMutex* mutex) :
mLocalPort(localPort),
mRemotePort(remotePort),
mHandler(handler),
mMutex(mutex)
{
resip_assert(handler!=0);
mSocket = createIPCSocket("127.0.0.1",mLocalPort);
if(mSocket == INVALID_SOCKET)
{
cerr << "IPCThread::IPCThread - could not create IPC udp socket on port=" << mLocalPort << endl;
}
else
{
// Set RemoteSockaddr to be same as local but with remote port
memcpy(&mRemoteSockaddr, &mLocalSockaddr, sizeof(mRemoteSockaddr));
sockaddr_in* anonv4 = (sockaddr_in*)&mRemoteSockaddr;
anonv4->sin_port = htons(remotePort);
cout << "IPCThread::IPCThread: local port=" << mLocalPort << ", remote port=" << remotePort << endl;
}
}
IPCThread::~IPCThread()
{
#if defined(WIN32)
closesocket(mSocket);
#else
close(mSocket);
#endif
}
void
IPCThread::sendIPCMsg(IPCMsg& msg)
{
std::ostringstream oss;
msg.encode(oss);
mMutex->lock();
mDataToSend.push(oss.str());
mMutex->unlock();
}
Socket
IPCThread::createIPCSocket(const std::string& printableAddr, unsigned int port)
{
Socket fd;
sockaddr_in* anonv4 = (sockaddr_in*)&mLocalSockaddr;
fd = ::socket(PF_INET, SOCK_DGRAM, 0);
if ( fd == INVALID_SOCKET )
{
int e = getErrno();
cerr << "IPCThread::createIPCSocket - Failed to create socket: error=" << e << endl;
return INVALID_SOCKET;
}
memset(anonv4, 0, sizeof(mLocalSockaddr));
anonv4->sin_family = AF_INET;
anonv4->sin_port = htons(port);
if (printableAddr.empty())
{
anonv4->sin_addr.s_addr = htonl(INADDR_ANY);
}
else
{
anonv4->sin_addr.s_addr = inet_addr(printableAddr.c_str());
}
//cout << "IPCThread::createIPCSocket - Creating fd=" << (int)fd
// << ", Binding to " << printableAddr << ":" << port << endl;
if ( ::bind( fd, &mLocalSockaddr, sizeof(mLocalSockaddr)) == SOCKET_ERROR )
{
int e = getErrno();
if ( e == EADDRINUSE )
{
cerr << "IPCThread::createIPCSocket - " << printableAddr << ":" << port << " already in use" << endl;
}
else
{
cerr << "IPCThread::createIPCSocket - Could not bind to " << printableAddr << ":" << port << ", error=" << e << endl;
}
return INVALID_SOCKET;
}
if(port == 0)
{
// If we used port 0, then query what port the OS allocated for us
socklen_t len = sizeof(mLocalSockaddr);
if(::getsockname(fd, &mLocalSockaddr, &len) == SOCKET_ERROR)
{
int e = getErrno();
cerr <<"IPCThread::createIPCSocket - getsockname failed, error=" << e << endl;
return INVALID_SOCKET;
}
}
#if defined(WIN32)
unsigned long noBlock = 1;
int errNoBlock = ioctlsocket( fd, FIONBIO , &noBlock );
if ( errNoBlock != 0 )
{
cerr << "IPCThread::createIPCSocket - Could not make socket non-blocking" << endl;
return INVALID_SOCKET;
}
#else
int flags = fcntl( fd, F_GETFL, 0);
int errNoBlock = fcntl(fd, F_SETFL, flags | O_NONBLOCK );
if ( errNoBlock != 0 )
{
cerr << "IPCThread::createIPCSocket - Could not make socket non-blocking" << endl;
return INVALID_SOCKET;
}
#endif
return fd;
}
void
IPCThread::thread()
{
fd_set read;
fd_set write;
fd_set except;
struct timeval tv;
if(mSocket == INVALID_SOCKET) return;
while (!isShutdown())
{
tv.tv_sec = 1; // Note: calling select on linux based systems can cause the contents of the passed in timeval struct to be modified, so we need to reset the time on each loop iteration
tv.tv_usec = 0;
FD_ZERO(&read);
FD_ZERO(&write);
FD_ZERO(&except);
FD_SET(mSocket, &read);
FD_SET(mSocket, &except);
if(!mDataToSend.empty())
{
FD_SET(mSocket, &write);
}
int ret = ::select(mSocket+1, &read, &write, &except, &tv);
if (ret > 0)
{
process(read, write);
}
}
cout << "IPCThread::thread - IPCThread shutdown." << endl;
}
void
IPCThread::process(fd_set& read_fdset, fd_set& write_fdset)
{
// If data to send and write has signalled
if(!mDataToSend.empty() && (FD_ISSET(mSocket, &write_fdset) != 0))
{
int count;
mMutex->lock();
std::string& dataToSend = mDataToSend.front();
count = sendto(mSocket,
dataToSend.data(),
dataToSend.size(),
0, // flags
&mRemoteSockaddr, sizeof(mRemoteSockaddr));
mDataToSend.pop();
mMutex->unlock();
if ( count == SOCKET_ERROR )
{
int e = getErrno();
cerr << "IPCThread::process - Failed (" << e << ") sending." << endl;
}
}
if((FD_ISSET(mSocket, &read_fdset) != 0))
{
sockaddr readAddr;
bool success = true;
socklen_t slen = sizeof(readAddr);
int len = recvfrom(mSocket,
mReadBuffer,
UDP_IPC_BUFFER_SIZE,
0 /*flags */,
&readAddr,
&slen);
if ( len == SOCKET_ERROR )
{
int err = getErrno();
if ( err != EWOULDBLOCK )
{
cerr << "IPCThread::process - Error calling recvfrom: " << err << endl;
success = false;
}
}
if (len == 0 || len == SOCKET_ERROR)
{
cerr << "IPCThread::process - No data calling recvfrom: len=" << len << endl;
success = false;
}
if (len+1 >= UDP_IPC_BUFFER_SIZE)
{
cerr << "IPCThread::process - Datagram exceeded max length "<<UDP_IPC_BUFFER_SIZE << endl;
success = false;
}
if(success)
{
//cout << "IPCThread::process - Received a datagram of size=" << len << endl;
IPCMsg msg(std::string(mReadBuffer, len));
mHandler->onNewIPCMsg(msg);
}
}
}
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

View File

@@ -0,0 +1,156 @@
#if !defined(IPCThread_hxx)
#define IPCThread_hxx
#include <queue>
#include <vector>
#include <string>
#include <sstream>
#include <errno.h>
#ifndef WIN32
# include <sys/socket.h>
# include <sys/select.h>
# include <netinet/in.h>
# include <arpa/inet.h>
# include <stdlib.h>
#endif
#include "Thread.hxx"
#define UDP_IPC_BUFFER_SIZE 4192
namespace gateway
{
#ifndef WIN32
typedef int Socket;
#define INVALID_SOCKET (-1)
#define SOCKET_ERROR (-1)
inline int getErrno() { return errno; }
#else
typedef SOCKET Socket;
inline int getErrno() { return WSAGetLastError(); }
#endif
class IPCMutex
{
public:
IPCMutex() {}
virtual ~IPCMutex() {}
virtual void lock() = 0;
virtual void unlock() = 0;
};
class IPCMsg
{
public:
IPCMsg() {};
IPCMsg(const std::string& msg)
{
unsigned int start = 0;
for(unsigned int i = 0; i < msg.size(); i++)
{
if(msg.at(i) == '\r')
{
mArgs.push_back(msg.substr(start,i-start));
start = i+1;
}
}
}
void addArg(const std::string& arg) { mArgs.push_back(arg); }
void addArg(unsigned int arg)
{
std::ostringstream oss;
oss << arg;
mArgs.push_back(oss.str());
}
std::ostream& encode(std::ostream& strm) const
{
std::vector<std::string>::const_iterator it = mArgs.begin();
for(;it != mArgs.end();it++)
{
strm << *it << "\r"; // Note: using /r since there is a /n character at the start of the iChat call blob
}
strm.flush();
return strm;
}
const std::vector<std::string>& getArgs() const { return mArgs; }
private:
std::vector<std::string> mArgs;
};
class IPCHandler
{
public:
virtual ~IPCHandler() {}
virtual void onNewIPCMsg(const IPCMsg& msg) = 0;
};
class IPCThread : public Thread
{
public:
IPCThread(unsigned short localPort, unsigned short remotePort, IPCHandler* handler, IPCMutex* mutex);
virtual ~IPCThread();
void sendIPCMsg(IPCMsg& msg);
protected:
private:
virtual void thread();
void process(fd_set& read_fdset, fd_set& write_fdset);
Socket createIPCSocket(const std::string& printableAddr, unsigned int port);
char mReadBuffer[UDP_IPC_BUFFER_SIZE+1];
sockaddr mLocalSockaddr;
sockaddr mRemoteSockaddr;
Socket mSocket;
unsigned short mLocalPort;
unsigned short mRemotePort;
//resip::Mutex mIPCMutex;
std::queue<std::string> mDataToSend;
IPCHandler* mHandler;
IPCMutex* mMutex;
};
}
#endif
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

View File

@@ -0,0 +1,653 @@
#include "rutil/ResipAssert.h"
#include <rutil/Data.hxx>
#include <rutil/Socket.hxx>
#include <rutil/Timer.hxx>
#include <resip/stack/Symbols.hxx>
#include <rutil/TransportType.hxx>
#include <rutil/Logger.hxx>
#include <resip/stack/Tuple.hxx>
#include <rutil/Random.hxx>
#include <rutil/DnsUtil.hxx>
#include <rutil/ParseBuffer.hxx>
#include <resip/stack/Transport.hxx>
#include "AppSubsystem.hxx"
#include "MediaRelay.hxx"
#include <rutil/WinLeakCheck.hxx>
#include <utility>
using namespace gateway;
using namespace resip;
using namespace std;
#define RESIPROCATE_SUBSYSTEM AppSubsystem::GATEWAY
#ifdef WIN32
#define sleepMs(t) Sleep(t)
#else
#define sleepMs(t) usleep(t*1000)
#endif
typedef struct
{
unsigned short versionExtPayloadTypeAndMarker;
unsigned short sequenceNumber;
unsigned int timestamp;
unsigned int ssrc;
} RtpHeader;
MediaRelay::MediaRelay(bool isV6Avail, unsigned short portRangeMin, unsigned short portRangeMax) :
mIsV6Avail(isV6Avail)
{
if(portRangeMax < portRangeMin) portRangeMax = portRangeMin; // saftey check
for(unsigned int i = portRangeMin; i <= portRangeMax; i++)
{
mFreeRelayPortList.push_back(i);
}
}
MediaRelay::~MediaRelay()
{
Lock lock(mRelaysMutex);
RelayPortList::iterator it = mRelays.begin();
for(;it != mRelays.end(); it++)
{
delete it->second;
}
}
#define NUM_CREATE_TRIES 10 // Number of times to try to allocate a port, since port may be in use by another application
bool
MediaRelay::createRelay(unsigned short& port)
{
for(unsigned int i = 0; i < NUM_CREATE_TRIES; i++)
{
if(createRelayImpl(port)) return true;
}
return false;
}
bool
MediaRelay::createRelayImpl(unsigned short& port)
{
Lock lock(mRelaysMutex);
if(mFreeRelayPortList.empty()) return false;
unsigned short trialPort = mFreeRelayPortList.front();
mFreeRelayPortList.pop_front();
Tuple v4tuple(Data::Empty,trialPort,V4,UDP,Data::Empty);
resip::Socket v4fd = createRelaySocket(v4tuple);
if(v4fd == INVALID_SOCKET)
{
mFreeRelayPortList.push_back(trialPort);
return false;
}
if(mIsV6Avail)
{
Tuple v6tuple(Data::Empty,trialPort,V6,UDP,Data::Empty);
resip::Socket v6fd = createRelaySocket(v6tuple);
if(v6fd != INVALID_SOCKET)
{
port = trialPort;
mRelays[port] = new MediaRelayPort(v4fd, v4tuple, v6fd, v6tuple);
InfoLog(<< "MediaRelay::createRelayImpl - Media relay started for port " << port);
return true;
}
#if defined(WIN32)
closesocket(v4fd);
#else
close(v4fd);
#endif
mFreeRelayPortList.push_back(trialPort);
return false;
}
else
{
// Only V4 is available
port = trialPort;
mRelays[port] = new MediaRelayPort(v4fd, v4tuple);
InfoLog(<< "MediaRelay::createRelayImpl - Media relay started for port " << port);
return true;
}
}
void
MediaRelay::destroyRelay(unsigned short port)
{
Lock lock(mRelaysMutex);
RelayPortList::iterator it = mRelays.find(port);
if(it != mRelays.end())
{
InfoLog(<< "MediaRelay::destroyRelay - port=" << port);
delete it->second;
mRelays.erase(it);
mFreeRelayPortList.push_back(port);
}
}
void
MediaRelay::primeNextEndpoint(unsigned short& port, resip::Tuple& destinationIPPort)
{
Lock lock(mRelaysMutex);
RelayPortList::iterator it = mRelays.find(port);
if(it != mRelays.end())
{
if(it->second->mFirstEndpoint.mTuple.getPort() == 0)
{
InfoLog(<< "MediaRelay::primeNextEndpoint - sender=first, port=" << port << ", addr=" << destinationIPPort);
it->second->mFirstEndpoint.mTuple = destinationIPPort;
}
else
{
InfoLog(<< "MediaRelay::primeNextEndpoint - sender=second, port=" << port << ", addr=" << destinationIPPort);
it->second->mSecondEndpoint.mTuple = destinationIPPort;
}
}
}
resip::Socket
MediaRelay::createRelaySocket(resip::Tuple& tuple)
{
resip::Socket fd;
#ifdef USE_IPV6
fd = ::socket(tuple.ipVersion() == V4 ? PF_INET : PF_INET6, SOCK_DGRAM, 0);
#else
fd = ::socket(PF_INET, SOCK_DGRAM, 0);
#endif
if ( fd == INVALID_SOCKET )
{
int e = getErrno();
ErrLog (<< "MediaRelay::createRelaySocket - Failed to create socket: " << strerror(e));
return INVALID_SOCKET;
}
DebugLog (<< "MediaRelay::createRelaySocket - Creating fd=" << (int)fd
<< (tuple.ipVersion() == V4 ? " V4" : " V6")
<< ", Binding to " << Tuple::inet_ntop(tuple));
if ( ::bind( fd, &tuple.getSockaddr(), tuple.length()) == SOCKET_ERROR )
{
int e = getErrno();
if ( e == EADDRINUSE )
{
ErrLog (<< "MediaRelay::createRelaySocket - " << tuple << " already in use ");
}
else
{
ErrLog (<< "MediaRelay::createRelaySocket - Could not bind to " << tuple << ", error=" << e);
}
return INVALID_SOCKET;
}
if(tuple.getPort() == 0)
{
// If we used port 0, then query what port the OS allocated for us
socklen_t len = tuple.length();
if(::getsockname(fd, &tuple.getMutableSockaddr(), &len) == SOCKET_ERROR)
{
int e = getErrno();
ErrLog (<<"MediaRelay::createRelaySocket - getsockname failed, error=" << e);
return INVALID_SOCKET;
}
}
bool ok = makeSocketNonBlocking(fd);
if ( !ok )
{
ErrLog (<< "MediaRelay::createRelaySocket - Could not make socket non-blocking");
return INVALID_SOCKET;
}
return fd;
}
void
MediaRelay::thread()
{
while (!isShutdown())
{
try
{
if(mRelays.size() == 0)
{
// No relays yet - just wait
sleepMs(50);
}
else
{
resip::FdSet fdset;
buildFdSet(fdset);
int ret = fdset.selectMilliSeconds(50);
if (ret > 0)
{
process(fdset);
}
}
}
catch (BaseException& e)
{
ErrLog (<< "MediaRelay::thread - Unhandled exception: " << e);
}
}
WarningLog (<< "MediaRelay::thread - shutdown");
}
void
MediaRelay::buildFdSet(FdSet& fdset)
{
Lock lock(mRelaysMutex);
RelayPortList::iterator it = mRelays.begin();
for(;it != mRelays.end(); it++)
{
// Add read fd's
fdset.setRead(it->second->mV4Fd);
if(mIsV6Avail) fdset.setRead(it->second->mV6Fd);
fdset.setExcept(it->second->mV4Fd);
if(mIsV6Avail) fdset.setExcept(it->second->mV6Fd);
checkKeepalives(it->second);
// Add write fd's if there is data to write
if((it->second->mFirstEndpoint.mRelayDatagram.get() != 0 && it->second->mFirstEndpoint.mTuple.ipVersion() == V4) ||
(it->second->mSecondEndpoint.mRelayDatagram.get() != 0 && it->second->mSecondEndpoint.mTuple.ipVersion() == V4))
{
fdset.setWrite(it->second->mV4Fd);
}
if(mIsV6Avail &&
((it->second->mFirstEndpoint.mRelayDatagram.get() != 0 && it->second->mFirstEndpoint.mTuple.ipVersion() == V6) ||
(it->second->mSecondEndpoint.mRelayDatagram.get() != 0 && it->second->mSecondEndpoint.mTuple.ipVersion() == V6)))
{
fdset.setWrite(it->second->mV6Fd);
}
}
}
#define KEEPALIVETIMEOUTMS 1000
#define KEEPALIVEMS 20
#define STALEENDPOINTTIMEOUTMS 2000
void
MediaRelay::checkKeepalives(MediaRelayPort* relayPort)
{
uint64_t now = Timer::getTimeMs();
// See if First Endpoint is stale (ie. hasn't received data in STALEENDPOINTTIMEOUTMS ms)
if(relayPort->mFirstEndpoint.mTuple.getPort() != 0 &&
(now - relayPort->mFirstEndpoint.mRecvTimeMs) > STALEENDPOINTTIMEOUTMS)
{
relayPort->mFirstEndpoint.reset();
InfoLog(<< "MediaRelay::checkKeepalives: port=" << relayPort->mLocalV4Tuple.getPort() << ", haven't recevied data from first endpoint in " << STALEENDPOINTTIMEOUTMS << "ms - reseting endpoint.");
}
// See if Second Endpoint is stale (ie. hasn't received data in STALEENDPOINTTIMEOUTMS ms)
if(relayPort->mSecondEndpoint.mTuple.getPort() != 0 &&
(now - relayPort->mSecondEndpoint.mRecvTimeMs) > STALEENDPOINTTIMEOUTMS)
{
relayPort->mSecondEndpoint.reset();
InfoLog(<< "MediaRelay::checkKeepalives: port=" << relayPort->mLocalV4Tuple.getPort() << ", haven't recevied data from second endpoint in " << STALEENDPOINTTIMEOUTMS << "ms - reseting endpoint.");
}
//if(relayPort->mFirstEndpoint.mTuple.getPort() != 0)
//{
//InfoLog(<< "MediaRelay::checkKeepalives - port=" << relayPort->mFirstEndpoint.mTuple.getPort() << ", dataToSend=" <<
// (relayPort->mFirstEndpoint.mRelayDatagram.get() == 0 ? "no" : "yes") << ", time since last send=" <<
// (now - relayPort->mFirstEndpoint.mSendTimeMs));
//}
// See if keepalive needs to be sent to First Endpoint
if(relayPort->mFirstEndpoint.mTuple.getPort() != 0 &&
relayPort->mFirstEndpoint.mRelayDatagram.get() == 0 &&
((!relayPort->mFirstEndpoint.mKeepaliveMode && (now - relayPort->mFirstEndpoint.mSendTimeMs) > KEEPALIVETIMEOUTMS) ||
(relayPort->mFirstEndpoint.mKeepaliveMode && (now - relayPort->mFirstEndpoint.mSendTimeMs) > KEEPALIVEMS)))
{
RtpHeader keepalive; // Create an empty G711 packet to keep iChat happy
keepalive.versionExtPayloadTypeAndMarker = htons(0x8000);
keepalive.sequenceNumber = 0;
keepalive.timestamp = 0;
keepalive.ssrc = relayPort->mFirstEndpoint.mSsrc;
if(!relayPort->mFirstEndpoint.mKeepaliveMode)
{
InfoLog(<< "MediaRelay::checkKeepalives: port=" << relayPort->mLocalV4Tuple.getPort() << ", dispatching initial RTP keepalive to first sender!");
relayPort->mFirstEndpoint.mKeepaliveMode = true;
}
//else
//{
// InfoLog(<< "MediaRelay::checkKeepalives: port=" << relayPort->mLocalV4Tuple.getPort() << ", dispatching subsequent RTP keepalive to first sender!");
//}
// Add message to buffer
std::unique_ptr<char[]> buffer(new char[sizeof(RtpHeader)]);
memcpy(buffer.get(), &keepalive, sizeof(RtpHeader));
relayPort->mFirstEndpoint.mRelayDatagram = std::move(buffer);
relayPort->mFirstEndpoint.mRelayDatagramLen = sizeof(RtpHeader);
}
// See if keepalive needs to be sent to Second Endpoint
if(relayPort->mSecondEndpoint.mTuple.getPort() != 0 &&
relayPort->mSecondEndpoint.mRelayDatagram.get() == 0 &&
((!relayPort->mSecondEndpoint.mKeepaliveMode && (now - relayPort->mSecondEndpoint.mSendTimeMs) > KEEPALIVETIMEOUTMS) ||
(relayPort->mSecondEndpoint.mKeepaliveMode && (now - relayPort->mSecondEndpoint.mSendTimeMs) > KEEPALIVEMS)))
{
RtpHeader keepalive; // Create an empty G711 packet to keep iChat happy
keepalive.versionExtPayloadTypeAndMarker = htons(0x8000);
keepalive.sequenceNumber = 0;
keepalive.timestamp = 0;
keepalive.ssrc = relayPort->mSecondEndpoint.mSsrc;
if(!relayPort->mSecondEndpoint.mKeepaliveMode)
{
InfoLog(<< "MediaRelay::checkKeepalives: port=" << relayPort->mLocalV4Tuple.getPort() << ", dispatching initial RTP keepalive to second sender!");
relayPort->mSecondEndpoint.mKeepaliveMode = true;
}
//else
//{
// InfoLog(<< "MediaRelay::checkKeepalives: port=" << relayPort->mLocalV4Tuple.getPort() << ", dispatching subsequent RTP keepalive to second sender!");
//}
// Add message to buffer
std::unique_ptr<char[]> buffer(new char[sizeof(RtpHeader)]);
memcpy(buffer.get(), &keepalive, sizeof(RtpHeader));
relayPort->mSecondEndpoint.mRelayDatagram = std::move(buffer);
relayPort->mSecondEndpoint.mRelayDatagramLen = sizeof(RtpHeader);
}
}
void
MediaRelay::process(FdSet& fdset)
{
Lock lock(mRelaysMutex);
RelayPortList::iterator it = mRelays.begin();
for(;it != mRelays.end(); it++)
{
if(processWrites(fdset, it->second))
{
// If all writes have been processed, process reads
processReads(fdset, it->second);
}
}
}
bool
MediaRelay::processWrites(FdSet& fdset, MediaRelayPort* relayPort)
{
resip::Socket fd = INVALID_SOCKET;
Tuple tuple;
std::unique_ptr<char[]> buffer;
int len;
// If we have data to write to first sender then check if readyToWrite
if(relayPort->mFirstEndpoint.mRelayDatagram.get() != 0)
{
if(relayPort->mFirstEndpoint.mTuple.ipVersion() == V4 &&
fdset.readyToWrite(relayPort->mV4Fd))
{
fd = relayPort->mV4Fd;
tuple = relayPort->mFirstEndpoint.mTuple;
buffer = std::move(relayPort->mFirstEndpoint.mRelayDatagram);
len = relayPort->mFirstEndpoint.mRelayDatagramLen;
}
else if(mIsV6Avail &&
relayPort->mFirstEndpoint.mTuple.ipVersion() == V6 &&
fdset.readyToWrite(relayPort->mV6Fd))
{
fd = relayPort->mV6Fd;
tuple = relayPort->mFirstEndpoint.mTuple;
buffer = std::move(relayPort->mFirstEndpoint.mRelayDatagram);
len = relayPort->mFirstEndpoint.mRelayDatagramLen;
}
}
// If anything to send to first sender then do it
if (fd != INVALID_SOCKET)
{
int count;
count = sendto(fd,
buffer.get(),
len,
0, // flags
&tuple.getMutableSockaddr(), tuple.length());
if ( count == SOCKET_ERROR )
{
int e = getErrno();
InfoLog (<< "MediaRelay::processWrites: port=" << relayPort->mLocalV4Tuple.getPort() << ", Failed (" << e << ") sending to " << tuple);
}
else
{
// InfoLog(<< len << " bytes of data sent to " << tuple);
relayPort->mFirstEndpoint.mSendTimeMs = Timer::getTimeMs();
}
}
// check if we have data to write to second sender then check if readyToWrite
fd = INVALID_SOCKET; // reset
if(relayPort->mSecondEndpoint.mRelayDatagram.get() != 0)
{
if(relayPort->mSecondEndpoint.mTuple.ipVersion() == V4 &&
fdset.readyToWrite(relayPort->mV4Fd))
{
fd = relayPort->mV4Fd;
tuple = relayPort->mSecondEndpoint.mTuple;
buffer = std::move(relayPort->mSecondEndpoint.mRelayDatagram);
len = relayPort->mSecondEndpoint.mRelayDatagramLen;
}
else if(mIsV6Avail &&
relayPort->mSecondEndpoint.mTuple.ipVersion() == V6 &&
fdset.readyToWrite(relayPort->mV6Fd))
{
fd = relayPort->mV6Fd;
tuple = relayPort->mSecondEndpoint.mTuple;
buffer = std::move(relayPort->mSecondEndpoint.mRelayDatagram);
len = relayPort->mSecondEndpoint.mRelayDatagramLen;
}
}
// If anything to send to sender sender then do it
if (fd != INVALID_SOCKET)
{
int count;
count = sendto(fd,
buffer.get(),
len,
0, // flags
&tuple.getMutableSockaddr(), tuple.length());
if ( count == SOCKET_ERROR )
{
int e = getErrno();
InfoLog (<< "MediaRelay::processWrites: port=" << relayPort->mLocalV4Tuple.getPort() << ", Failed (" << e << ") sending to " << tuple);
}
else
{
//InfoLog(<< len << " bytes of data sent to " << tuple);
relayPort->mSecondEndpoint.mSendTimeMs = Timer::getTimeMs();
}
}
return relayPort->mFirstEndpoint.mRelayDatagram.get() == 0 &&
relayPort->mSecondEndpoint.mRelayDatagram.get() == 0;
}
#define UDP_BUFFER_SIZE 1000
void
MediaRelay::processReads(FdSet& fdset, MediaRelayPort* relayPort)
{
resip::Socket fd = INVALID_SOCKET;
Tuple tuple;
if(fdset.readyToRead(relayPort->mV4Fd))
{
//InfoLog(<<"V4 socket is ready to read.");
fd = relayPort->mV4Fd;
tuple = relayPort->mLocalV4Tuple;
}
else if(mIsV6Avail && fdset.readyToRead(relayPort->mV6Fd))
{
//InfoLog(<<"V6 socket is ready to read.");
fd = relayPort->mV6Fd;
tuple = relayPort->mLocalV6Tuple;
}
if (fd != INVALID_SOCKET)
{
std::unique_ptr<char[]> buffer(new char[UDP_BUFFER_SIZE+1]);
socklen_t slen = tuple.length();
int len = recvfrom( fd,
buffer.get(),
UDP_BUFFER_SIZE,
0 /*flags */,
&tuple.getMutableSockaddr(),
&slen);
if ( len == SOCKET_ERROR )
{
int err = getErrno();
if ( err != EWOULDBLOCK )
{
ErrLog (<< "MediaRelay::processReads: port=" << relayPort->mLocalV4Tuple.getPort() << ", Error calling recvfrom: " << err);
}
buffer.reset();
}
if (len == 0)
{
ErrLog (<< "MediaRelay::processReads: port=" << relayPort->mLocalV4Tuple.getPort() << ", No data calling recvfrom: len=" << len);
buffer.reset();
}
if (len+1 >= UDP_BUFFER_SIZE)
{
InfoLog(<<"MediaRelay::processReads: port=" << relayPort->mLocalV4Tuple.getPort() << ", Datagram exceeded max length "<<UDP_BUFFER_SIZE);
buffer.reset();
}
if(buffer.get() != 0)
{
uint64_t now = Timer::getTimeMs();
RtpHeader* rtpHeader = (RtpHeader*)buffer.get();
//InfoLog(<< "Received a datagram of size=" << len << " from=" << tuple);
MediaEndpoint* pReceivingEndpoint = 0;
MediaEndpoint* pSendingEndpoint = 0;
// First check if packet is from first endpoint
if(tuple == relayPort->mFirstEndpoint.mTuple)
{
pReceivingEndpoint = &relayPort->mFirstEndpoint;
pSendingEndpoint = &relayPort->mSecondEndpoint;
}
// Next check if packet is from second endpoint
else if(tuple == relayPort->mSecondEndpoint.mTuple)
{
pReceivingEndpoint = &relayPort->mSecondEndpoint;
pSendingEndpoint = &relayPort->mFirstEndpoint;
}
else
{
// See if we can store this new sender in First Endpoint
if(relayPort->mFirstEndpoint.mTuple.getPort() == 0)
{
InfoLog(<< "MediaRelay::processReads: port=" << relayPort->mLocalV4Tuple.getPort() << ", First packet received from First Endpoint " << tuple);
pReceivingEndpoint = &relayPort->mFirstEndpoint;
pSendingEndpoint = &relayPort->mSecondEndpoint;
}
else if(relayPort->mSecondEndpoint.mTuple.getPort() == 0)
{
InfoLog(<< "MediaRelay::processReads: port=" << relayPort->mLocalV4Tuple.getPort() << ", First packet received from Second Endpoint " << tuple);
pReceivingEndpoint = &relayPort->mSecondEndpoint;
pSendingEndpoint = &relayPort->mFirstEndpoint;
}
else // We already have 2 endpoints - this would be a third
{
// We have a third sender - for now drop, if one of the other senders stops sending data for 2 seconds then we will start picking up this sender
WarningLog(<< "MediaRelay::processReads: port=" << relayPort->mLocalV4Tuple.getPort() << ", MediaRelay on " << relayPort->mLocalV4Tuple.getPort() << " has seen a third sender " << tuple << " - not implemented yet - ignoring packet");
}
if(pReceivingEndpoint)
{
pReceivingEndpoint->mTuple = tuple;
pReceivingEndpoint->mSendTimeMs = now;
pReceivingEndpoint->mRecvTimeMs = now;
}
}
if(pReceivingEndpoint)
{
pReceivingEndpoint->mRecvTimeMs = now;
if(pSendingEndpoint && pSendingEndpoint->mTuple.getPort() != 0)
{
if(ntohs(rtpHeader->versionExtPayloadTypeAndMarker) & 0x8000) // RTP Version 2
{
// Adjust ssrc
rtpHeader->ssrc = pSendingEndpoint->mSsrc;
// relay packet to second sender
resip_assert(pSendingEndpoint->mRelayDatagram.get() == 0);
pSendingEndpoint->mRelayDatagram = std::move(buffer);
pSendingEndpoint->mRelayDatagramLen = len;
if(pSendingEndpoint->mKeepaliveMode)
{
InfoLog(<< "MediaRelay::processReads: port=" << relayPort->mLocalV4Tuple.getPort() << ", received packet to forward, turning off keepalive mode for " << pSendingEndpoint->mTuple);
pSendingEndpoint->mKeepaliveMode = false;
}
//InfoLog(<< "Relaying packet from=" << tuple << " to " << pSendingEndpoint->mTuple);
}
//else
//{
// InfoLog(<< "MediaRelay::processReads: port=" << relayPort->mLocalV4Tuple.getPort() << ", discarding received packet with unknown RTP version from " << tuple);
//}
}
}
}
}
}
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

View File

@@ -0,0 +1,87 @@
#if !defined(MediaRelay_hxx)
#define MediaRelay_hxx
#include <map>
#include <deque>
#include <rutil/Data.hxx>
#include <rutil/Socket.hxx>
#include <rutil/ThreadIf.hxx>
#include <rutil/TransportType.hxx>
#include <resip/stack/Tuple.hxx>
#include "MediaRelayPort.hxx"
namespace gateway
{
class MediaRelay : public resip::ThreadIf
{
public:
MediaRelay(bool isV6Avail, unsigned short portRangeMin, unsigned short portRangeMax);
virtual ~MediaRelay();
bool createRelay(unsigned short& port);
void destroyRelay(unsigned short port);
void primeNextEndpoint(unsigned short& port, resip::Tuple& destinationIPPort);
protected:
private:
virtual void thread();
void buildFdSet(resip::FdSet& fdset);
void checkKeepalives(MediaRelayPort* relayPort);
void process(resip::FdSet& fdset);
bool processWrites(resip::FdSet& fdset, MediaRelayPort* relayPort); // return true if all writes are complete
void processReads(resip::FdSet& fdset, MediaRelayPort* relayPort);
bool createRelayImpl(unsigned short& port);
resip::Socket createRelaySocket(resip::Tuple& tuple);
typedef std::map<unsigned short, MediaRelayPort*> RelayPortList;
RelayPortList mRelays;
resip::Mutex mRelaysMutex;
bool mIsV6Avail;
std::deque<unsigned int> mFreeRelayPortList;
};
}
#endif
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

View File

@@ -0,0 +1,84 @@
#include "rutil/ResipAssert.h"
#include <rutil/Data.hxx>
#include <rutil/Socket.hxx>
#include <resip/stack/Symbols.hxx>
#include <rutil/TransportType.hxx>
#include <rutil/Logger.hxx>
#include <resip/stack/Tuple.hxx>
//#include <rutil/DnsUtil.hxx>
//#include <rutil/ParseBuffer.hxx>
#include <resip/stack/Transport.hxx>
#include "AppSubsystem.hxx"
#include "MediaRelayPort.hxx"
#include <rutil/WinLeakCheck.hxx>
using namespace gateway;
using namespace resip;
using namespace std;
#define RESIPROCATE_SUBSYSTEM AppSubsystem::GATEWAY
MediaRelayPort::MediaRelayPort() : mV4Fd(INVALID_SOCKET), mV6Fd(INVALID_SOCKET)
{
}
MediaRelayPort::MediaRelayPort(resip::Socket& v4fd, resip::Tuple& v4tuple, resip::Socket& v6fd, resip::Tuple& v6tuple) :
mV4Fd(v4fd), mLocalV4Tuple(v4tuple),
mV6Fd(v6fd), mLocalV6Tuple(v6tuple)
{
}
MediaRelayPort::MediaRelayPort(resip::Socket& v4fd, resip::Tuple& v4tuple) :
mV4Fd(v4fd), mLocalV4Tuple(v4tuple),
mV6Fd(INVALID_SOCKET)
{
}
MediaRelayPort::~MediaRelayPort()
{
#if defined(WIN32)
if(mV4Fd != INVALID_SOCKET) closesocket(mV4Fd);
if(mV6Fd != INVALID_SOCKET) closesocket(mV6Fd);
#else
if(mV4Fd != INVALID_SOCKET) close(mV4Fd);
if(mV6Fd != INVALID_SOCKET) close(mV6Fd);
#endif
}
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

View File

@@ -0,0 +1,94 @@
#if !defined(MediaRelayPort_hxx)
#define MediaRelayPort_hxx
#include <map>
#include <memory>
#include <rutil/Data.hxx>
#include <rutil/Random.hxx>
#include <rutil/Socket.hxx>
#include <rutil/TransportType.hxx>
#include <resip/stack/Tuple.hxx>
namespace gateway
{
class MediaEndpoint
{
public:
MediaEndpoint() : mSsrc(resip::Random::getRandom()), mRelayDatagramLen(0), mSendTimeMs(0), mRecvTimeMs(0), mKeepaliveMode(false) {}
resip::Tuple mTuple;
unsigned int mSsrc;
std::unique_ptr<char[]> mRelayDatagram;
int mRelayDatagramLen;
uint64_t mSendTimeMs;
uint64_t mRecvTimeMs;
bool mKeepaliveMode;
void reset()
{
mTuple = resip::Tuple();
mRelayDatagram.release();
mRelayDatagramLen = 0;
mKeepaliveMode = false;
}
};
class MediaRelayPort
{
public:
MediaRelayPort();
MediaRelayPort(resip::Socket& v4fd, resip::Tuple& v4tuple, resip::Socket& v6fd, resip::Tuple& v6tuple);
MediaRelayPort(resip::Socket& v4fd, resip::Tuple& v4tuple);
~MediaRelayPort();
// V4 and V6 fd's and tuples
resip::Socket mV4Fd;
resip::Tuple mLocalV4Tuple;
resip::Socket mV6Fd;
resip::Tuple mLocalV6Tuple;
// Sender data
MediaEndpoint mFirstEndpoint;
MediaEndpoint mSecondEndpoint;
};
}
#endif
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,362 @@
#if !defined(Server_hxx)
#define Server_hxx
#include <map>
#include <resip/stack/TransactionUser.hxx>
#include <resip/stack/EventStackThread.hxx>
#include <rutil/SelectInterruptor.hxx>
#include <resip/stack/UdpTransport.hxx>
#include <resip/dum/MasterProfile.hxx>
#include <resip/dum/DumShutdownHandler.hxx>
#include <resip/dum/DialogUsageManager.hxx>
#include <resip/dum/InviteSessionHandler.hxx>
#include <resip/dum/DialogSetHandler.hxx>
#include <resip/dum/OutOfDialogHandler.hxx>
#include <resip/dum/RedirectHandler.hxx>
#include <resip/dum/SubscriptionHandler.hxx>
#include <resip/dum/RegistrationHandler.hxx>
#include <rutil/Log.hxx>
#include <rutil/Mutex.hxx>
#include "ConfigParser.hxx"
#include "B2BSession.hxx"
#include "SipRegistration.hxx"
#include "AddressTranslator.hxx"
#include "MediaRelay.hxx"
#include "IChatIPPortData.hxx"
#include "IPCThread.hxx"
#include <memory>
#ifdef WIN32
#define sleepMs(t) Sleep(t)
#else
#define sleepMs(t) usleep(t*1000)
#endif
#define SDP_ICHATGW_ORIGIN_USER "iChat-gw"
namespace gateway
{
class ShutdownCmd;
class B2BSession;
class Server : public ConfigParser,
public IPCHandler,
public resip::DumShutdownHandler,
public resip::InviteSessionHandler,
public resip::DialogSetHandler,
public resip::OutOfDialogHandler,
public resip::RedirectHandler,
public resip::ClientSubscriptionHandler,
public resip::ServerSubscriptionHandler,
public resip::ClientRegistrationHandler,
public resip::ExternalUnknownDatagramHandler
{
public:
Server(int argc, char** argv);
virtual ~Server();
/**
Starts the SIP stack thread.
@note This should be called before calling process() in a loop
*/
void startup();
/**
This should be called in a loop to give process cycles to the server.
@param timeoutMs Will return after timeoutMs if nothing to do.
Application can do some work, but should call
process again ASAP.
*/
void process(int timeoutMs); // call this in a loop
/**
Used to initiate a shutdown of the server. This function blocks
until the shutdown is complete.
@note There should not be an active process request when this
is called.
*/
void shutdown();
// Utility Methods ////////////////////////////////////////////////////////////
typedef enum
{
SubsystemAll,
SubsystemContents,
SubsystemDns,
SubsystemDum,
SubsystemSdp,
SubsystemSip,
SubsystemTransaction,
SubsystemTransport,
SubsystemStats,
SubsystemGateway
} LoggingSubsystem;
/**
Static method that sets the logging level for a particular subsystem,
or all subsystems.
@param level Logging level to set
@param subsystem Subsystem to set level on
@note: Use Server::SubsystemAll to set the logging level on all
subsystems
*/
static void setLogLevel(resip::Log::Level level, LoggingSubsystem subsystem=SubsystemAll);
/**
Called by Jabber side of gateway to notify SIP side of iChat call request.
@param to Bare JID of endpoint we are proceeding to ring
@param from Full JID of endpoint requesting the call
*/
void notifyIChatCallRequest(const std::string& to, const std::string& from);
/**
Called by Jabber side of gateway to notify SIP side of cancelled iChat call request.
@param handle Handle of the B2BSession object for the call
*/
void notifyIChatCallCancelled(const B2BSessionHandle& handle);
/**
Called by Jabber side of gateway to notify B2BSession that iChat call is proceeding.
This call will cause a timeout timer to be deactiviated.
@param handle Handle of the B2BSession object for the call
@param to Full JID of endpoint we are proceeding to ring
*/
void notifyIChatCallProceeding(const B2BSessionHandle& handle, const std::string& to);
/**
Called by Jabber side of gateway to notify B2BSession that iChat call has failed.
@param handle Handle of the B2BSession object for the call
@param statusCode Code representing the reason for the failure
*/
void notifyIChatCallFailed(const B2BSessionHandle& handle, unsigned int statusCode);
/**
Called by Jabber side of gateway to notify B2BSession that iChat call setup
has completed on the Jabber side, and that it now needs to continue via SIP.
@param handle Handle of the B2BSession object for the call
@param remoteIPPortListBlob List of transports received from the iChat client via
Jabber messaging - in proprietary iChat blob format
*/
void continueIChatCall(const B2BSessionHandle& handle, const std::string& remoteIPPortListBlob);
/**
Called by Jabber side of gateway to request that a jabber user be registered on the
configured SIP server. Note: The jabber user's JID is first transformed into a
SIP URI using the configured translation rules. Note: calling this multiple times
with the same jidToRegister is safe and will result in a no op.
@param jidToRegister - Jabber user's JID to register on the SIP server.
*/
void sipRegisterJabberUser(const std::string& jidToRegister);
/**
Called by Jabber side of gateway to request that a jabber user be unregistered from the
configured SIP server. Note: The jabber user's JID is first transformed into a
SIP URI using the configured translation rules.
@param jidToUnregister - Jabber user's JID to unregister from the SIP server.
*/
void sipUnregisterJabberUser(const std::string& jidToUnregister);
/**
Called by Jabber side of gateway to check if the JID to be subscribed will pass the
translation rules.
@param to - JID of address being subscribed to
@param from - JID of subscriber
*/
void checkSubscription(const std::string& to, const std::string& from);
B2BSession* findMatchingIChatB2BSession(const resip::SipMessage& msg);
protected:
std::shared_ptr<resip::MasterProfile>& getMasterProfile() noexcept { return mProfile; }
bool translateAddress(const resip::Data& address, resip::Data& translation, bool failIfNoRule=false);
// IPC Handler
virtual void onNewIPCMsg(const IPCMsg& msg);
// External Unknown Packet Handler//////////////////////////////////////////////
virtual void operator()(resip::UdpTransport* transport, const resip::Tuple& source, std::unique_ptr<resip::Data> unknownPacket);
// Shutdown Handler ////////////////////////////////////////////////////////////
void onDumCanBeDeleted();
// Invite Session Handler /////////////////////////////////////////////////////
virtual void onNewSession(resip::ClientInviteSessionHandle h, resip::InviteSession::OfferAnswerType oat, const resip::SipMessage& msg);
virtual void onNewSession(resip::ServerInviteSessionHandle h, resip::InviteSession::OfferAnswerType oat, const resip::SipMessage& msg);
virtual void onFailure(resip::ClientInviteSessionHandle h, const resip::SipMessage& msg);
virtual void onEarlyMedia(resip::ClientInviteSessionHandle, const resip::SipMessage&, const resip::SdpContents&);
virtual void onProvisional(resip::ClientInviteSessionHandle, const resip::SipMessage& msg);
virtual void onConnected(resip::ClientInviteSessionHandle h, const resip::SipMessage& msg);
virtual void onConnected(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual void onStaleCallTimeout(resip::ClientInviteSessionHandle);
virtual void onTerminated(resip::InviteSessionHandle h, resip::InviteSessionHandler::TerminatedReason reason, const resip::SipMessage* msg);
virtual void onRedirected(resip::ClientInviteSessionHandle, const resip::SipMessage& msg);
virtual void onAnswer(resip::InviteSessionHandle, const resip::SipMessage& msg, const resip::SdpContents&);
virtual void onOffer(resip::InviteSessionHandle handle, const resip::SipMessage& msg, const resip::SdpContents& offer);
virtual void onOfferRequired(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual void onOfferRejected(resip::InviteSessionHandle, const resip::SipMessage* msg);
virtual void onOfferRequestRejected(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual void onRemoteSdpChanged(resip::InviteSessionHandle, const resip::SipMessage& msg, const resip::SdpContents& sdp);
virtual void onInfo(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual void onInfoSuccess(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual void onInfoFailure(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual void onRefer(resip::InviteSessionHandle, resip::ServerSubscriptionHandle, const resip::SipMessage& msg);
virtual void onReferAccepted(resip::InviteSessionHandle, resip::ClientSubscriptionHandle, const resip::SipMessage& msg);
virtual void onReferRejected(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual void onReferNoSub(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual void onMessage(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual void onMessageSuccess(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual void onMessageFailure(resip::InviteSessionHandle, const resip::SipMessage& msg);
virtual void onForkDestroyed(resip::ClientInviteSessionHandle);
// DialogSetHandler //////////////////////////////////////////////
virtual void onTrying(resip::AppDialogSetHandle, const resip::SipMessage& msg);
virtual void onNonDialogCreatingProvisional(resip::AppDialogSetHandle, const resip::SipMessage& msg);
// ClientSubscriptionHandler ///////////////////////////////////////////////////
virtual void onUpdatePending(resip::ClientSubscriptionHandle h, const resip::SipMessage& notify, bool outOfOrder);
virtual void onUpdateActive(resip::ClientSubscriptionHandle h, const resip::SipMessage& notify, bool outOfOrder);
virtual void onUpdateExtension(resip::ClientSubscriptionHandle, const resip::SipMessage& notify, bool outOfOrder);
virtual void onTerminated(resip::ClientSubscriptionHandle h, const resip::SipMessage* notify);
virtual void onNewSubscription(resip::ClientSubscriptionHandle h, const resip::SipMessage& notify);
virtual int onRequestRetry(resip::ClientSubscriptionHandle h, int retryMinimum, const resip::SipMessage& notify);
// ServerSubscriptionHandler ///////////////////////////////////////////////////
virtual void onNewSubscription(resip::ServerSubscriptionHandle, const resip::SipMessage& sub);
virtual void onNewSubscriptionFromRefer(resip::ServerSubscriptionHandle, const resip::SipMessage& sub);
virtual void onRefresh(resip::ServerSubscriptionHandle, const resip::SipMessage& sub);
virtual void onTerminated(resip::ServerSubscriptionHandle);
virtual void onReadyToSend(resip::ServerSubscriptionHandle, resip::SipMessage&);
virtual void onNotifyRejected(resip::ServerSubscriptionHandle, const resip::SipMessage& msg);
virtual void onError(resip::ServerSubscriptionHandle, const resip::SipMessage& msg);
virtual void onExpiredByClient(resip::ServerSubscriptionHandle, const resip::SipMessage& sub, resip::SipMessage& notify);
virtual void onExpired(resip::ServerSubscriptionHandle, resip::SipMessage& notify);
virtual bool hasDefaultExpires() const;
virtual uint32_t getDefaultExpires() const;
// OutOfDialogHandler //////////////////////////////////////////////////////////
virtual void onSuccess(resip::ClientOutOfDialogReqHandle, const resip::SipMessage& response);
virtual void onFailure(resip::ClientOutOfDialogReqHandle, const resip::SipMessage& response);
virtual void onReceivedRequest(resip::ServerOutOfDialogReqHandle, const resip::SipMessage& request);
// RedirectHandler /////////////////////////////////////////////////////////////
virtual void onRedirectReceived(resip::AppDialogSetHandle, const resip::SipMessage& response);
virtual bool onTryingNextTarget(resip::AppDialogSetHandle, const resip::SipMessage& request);
// Registration Handler ////////////////////////////////////////////////////////
virtual void onSuccess(resip::ClientRegistrationHandle h, const resip::SipMessage& response);
virtual void onFailure(resip::ClientRegistrationHandle h, const resip::SipMessage& response);
virtual void onRemoved(resip::ClientRegistrationHandle h, const resip::SipMessage& response);
virtual int onRequestRetry(resip::ClientRegistrationHandle h, int retryMinimum, const resip::SipMessage& msg);
private:
friend class ShutdownCmd;
friend class B2BSession;
friend class IChatCallTimeout;
resip::DialogUsageManager& getDialogUsageManager();
void post(resip::ApplicationMessage& message, unsigned int ms=0);
void shutdownImpl();
friend class NotifyIChatCallRequestCmd;
void notifyIChatCallRequestImpl(const std::string& to, const std::string& from);
friend class NotifyIChatCallCancelledCmd;
void notifyIChatCallCancelledImpl(const B2BSessionHandle& handle);
friend class NotifyIChatCallProceedingCmd;
void notifyIChatCallProceedingImpl(const B2BSessionHandle& handle, const std::string& to);
friend class NotifyIChatCallFailedCmd;
void notifyIChatCallFailedImpl(const B2BSessionHandle& handle, unsigned int statusCode);
friend class ContinueIChatCallCmd;
void continueIChatCallImpl(const B2BSessionHandle& handle, const std::string& remoteIPPortListBlob);
friend class SipRegisterJabberUserCmd;
void sipRegisterJabberUserImpl(const std::string& jidToRegister);
friend class SipUnregisterJabberUserCmd;
void sipUnregisterJabberUserImpl(const std::string& jidToUnregister);
std::shared_ptr<resip::MasterProfile> mProfile;
resip::Security* mSecurity;
resip::FdPollGrp *mPollGrp;
resip::EventThreadInterruptor *mEventInterruptor;
resip::SipStack mStack;
resip::DialogUsageManager mDum;
resip::EventStackThread mStackThread;
volatile bool mDumShutdown;
typedef std::map<B2BSessionHandle, B2BSession*> B2BSessionMap;
B2BSessionMap mB2BSessions;
B2BSessionHandle mCurrentB2BSessionHandle;
B2BSession* getB2BSession(const B2BSessionHandle& handle) const;
B2BSessionHandle registerB2BSession(B2BSession *);
void unregisterB2BSession(const B2BSessionHandle& handle);
friend class SipRegistration;
typedef std::map<resip::Uri, SipRegistration*> RegistrationMap;
RegistrationMap mRegistrations;
void registerRegistration(SipRegistration *);
void unregisterRegistration(SipRegistration *);
bool mIsV6Avail;
IChatIPPortData mLocalIPPortData;
MediaRelay* mMediaRelay;
IPCThread* mIPCThread;
AddressTranslator mAddressTranslator;
std::map<resip::DialogSetId,B2BSession*> mActiveSessions;
};
}
#endif
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

View File

@@ -0,0 +1,165 @@
#include "Server.hxx"
#include "AppSubsystem.hxx"
#include "SipRegistration.hxx"
#include <rutil/Log.hxx>
#include <rutil/Logger.hxx>
#include <resip/dum/DialogUsageManager.hxx>
#include <resip/dum/ClientRegistration.hxx>
using namespace gateway;
using namespace resip;
using namespace std;
#define RESIPROCATE_SUBSYSTEM AppSubsystem::GATEWAY
SipRegistration::SipRegistration(Server& server, DialogUsageManager& dum, Uri& aor)
: AppDialogSet(dum),
mServer(server),
mDum(dum),
mAor(aor),
mEnded(false)
{
mServer.registerRegistration(this);
}
SipRegistration::~SipRegistration()
{
mServer.unregisterRegistration(this);
}
const resip::Uri&
SipRegistration::getAor()
{
return mAor;
}
void
SipRegistration::end()
{
if(!mEnded)
{
mEnded = true;
if(mRegistrationHandle.isValid())
{
try
{
// If ended - then just shutdown registration - likely due to shutdown
mRegistrationHandle->end();
}
catch(BaseException&)
{
// If end() call is nested - it will throw - catch here so that processing continues normally
}
}
}
}
const NameAddrs&
SipRegistration::getContactAddresses()
{
static NameAddrs empty;
if(mRegistrationHandle.isValid())
{
return mRegistrationHandle->allContacts(); // .slg. note: myContacts is not sufficient, since they do not contain the stack populated transport address
}
else
{
return empty;
}
}
////////////////////////////////////////////////////////////////////////////////
// Registration Handler ////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void
SipRegistration::onSuccess(ClientRegistrationHandle h, const SipMessage& msg)
{
InfoLog(<< "onSuccess(ClientRegistrationHandle): aor=" << mAor << ", msg=" << msg.brief());
if(!mEnded)
{
mRegistrationHandle = h;
}
else
{
try
{
// If ended - then just shutdown registration - likely due to shutdown
h->end();
}
catch(BaseException&)
{
// If end() call is nested - it will throw - catch here so that processing continues normally
}
}
}
void
SipRegistration::onFailure(ClientRegistrationHandle h, const SipMessage& msg)
{
InfoLog(<< "onFailure(ClientRegistrationHandle): aor=" << mAor << ", msg=" << msg.brief());
if(!mEnded)
{
mRegistrationHandle = h;
}
else
{
try
{
// If we don't have a handle - then just shutdown registration - likely due to shutdown
h->end();
}
catch(BaseException&)
{
// If end() call is nested - it will throw - catch here so that processing continues normally
}
}
}
void
SipRegistration::onRemoved(ClientRegistrationHandle h, const SipMessage&msg)
{
InfoLog(<< "onRemoved(ClientRegistrationHandle): aor=" << mAor << ", msg=" << msg.brief());
}
int
SipRegistration::onRequestRetry(ClientRegistrationHandle h, int retryMinimum, const SipMessage& msg)
{
InfoLog(<< "onRequestRetry(ClientRegistrationHandle): aor=" << mAor << ", msg=" << msg.brief());
return -1; // Let Profile retry setting take effect
}
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

View File

@@ -0,0 +1,89 @@
#if !defined(SipRegistration_hxx)
#define SipRegistration_hxx
#include <resip/dum/AppDialogSet.hxx>
#include <resip/dum/InviteSessionHandler.hxx>
#include <resip/dum/DialogSetHandler.hxx>
#include <resip/dum/SubscriptionHandler.hxx>
#include "Server.hxx"
namespace resip
{
class DialogUsageManager;
class SipMessage;
}
namespace gateway
{
class Server;
/**
This class is used to manage active SIP registrations.
Author: Scott Godin (sgodin AT SipSpectrum DOT com)
*/
class SipRegistration : public resip::AppDialogSet
{
public:
SipRegistration(Server& server, resip::DialogUsageManager& dum, resip::Uri& aor);
virtual ~SipRegistration();
virtual void end();
const resip::Uri& getAor();
const resip::NameAddrs& getContactAddresses();
// Registration Handler ////////////////////////////////////////////////////////
virtual void onSuccess(resip::ClientRegistrationHandle h, const resip::SipMessage& response);
virtual void onFailure(resip::ClientRegistrationHandle h, const resip::SipMessage& response);
virtual void onRemoved(resip::ClientRegistrationHandle h, const resip::SipMessage& response);
virtual int onRequestRetry(resip::ClientRegistrationHandle h, int retryMinimum, const resip::SipMessage& msg);
private:
Server &mServer;
resip::DialogUsageManager &mDum;
resip::Uri mAor;
bool mEnded;
resip::ClientRegistrationHandle mRegistrationHandle;
};
}
#endif
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

View File

@@ -0,0 +1,176 @@
#include "rutil/ResipAssert.h"
#include "Thread.hxx"
using namespace gateway;
using namespace std;
#if defined(WIN32)
#include <stdio.h>
#include <tchar.h>
#include <time.h>
#include <process.h> // for _beginthreadex()
typedef unsigned(__stdcall *THREAD_START_ROUTINE)(void*);
#endif
#include "rutil/ResipAssert.h"
#include <iostream>
extern "C"
{
static void*
#ifdef WIN32
__stdcall
#endif
threadWrapper( void* parm )
{
resip_assert( parm );
Thread* t = static_cast < Thread* > ( parm );
resip_assert( t );
t->thread();
#ifdef WIN32
_endthreadex(0);
#endif
return 0;
}
}
Thread::Thread() :
#ifdef WIN32
mThread(0),
#endif
mId(0), mShutdown(false)
{
}
Thread::~Thread()
{
shutdown();
join();
}
void
Thread::run()
{
resip_assert(mId == 0);
#if defined(WIN32)
mThread =
(HANDLE)_beginthreadex
(
NULL, // LPSECURITY_ATTRIBUTES lpThreadAttributes, // pointer to security attributes
0, // DWORD dwStackSize, // initial thread stack size
THREAD_START_ROUTINE
(threadWrapper), // LPTHREAD_START_ROUTINE lpStartAddress, // pointer to thread function
this, //LPVOID lpParameter, // argument for new thread
0, //DWORD dwCreationFlags, // creation flags
&mId// LPDWORD lpThreadId // pointer to receive thread ID
);
resip_assert( mThread != 0 );
#else
// spawn the thread
if ( int retval = pthread_create( &mId, 0, threadWrapper, this) )
{
std::cerr << "Failed to spawn thread: " << retval << std::endl;
resip_assert(0);
}
#endif
}
void
Thread::join()
{
if (mId == 0)
{
return;
}
#if defined(WIN32)
DWORD exitCode;
while (true)
{
if (GetExitCodeThread(mThread,&exitCode) != 0)
{
if (exitCode != STILL_ACTIVE)
{
break;
}
else
{
WaitForSingleObject(mThread,INFINITE);
}
}
else
{
break;
}
}
CloseHandle(mThread);
mThread=0;
#else
void* stat;
if (mId != pthread_self())
{
int r = pthread_join( mId , &stat );
if ( r != 0 )
{
cerr << "Internal error: pthread_join() returned " << r << endl;
resip_assert(0);
}
}
#endif
mId = 0;
}
void
Thread::shutdown()
{
mShutdown = true;
}
bool
Thread::isShutdown() const
{
return mShutdown;
}
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

View File

@@ -0,0 +1,85 @@
#if !defined(Thread_hxx)
#define Thread_hxx
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
# include <windows.h>
# include <winsock2.h>
#undef WIN32_LEAN_AND_MEAN
#else
# include <pthread.h>
#endif
namespace gateway
{
class Thread
{
public:
Thread();
virtual ~Thread();
virtual void run();
void join();
virtual void shutdown();
bool isShutdown() const;
#ifdef WIN32
typedef unsigned int Id;
#else
typedef pthread_t Id;
#endif
virtual void thread() = 0;
protected:
#ifdef WIN32
HANDLE mThread;
#endif
Id mId;
volatile bool mShutdown;
private:
// Suppress copying
Thread(const Thread &);
const Thread & operator=(const Thread &);
};
}
#endif
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

View File

@@ -0,0 +1,36 @@
#define ICHATGW_VERSION_STRING "0.1"
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

View File

@@ -0,0 +1,154 @@
########################################################
# ichat-gw configuration file
########################################################
########################################################
# SIP settings
########################################################
# Local IP Address to bind SIP transports to. If left blank
# ichat-gw will bind to all adapters.
#IPAddress = 192.168.1.106
#IPAddress = 2001:5c0:1000:a::6d
IPAddress =
# Comma separated list of DNS servers, overrides default OS detected list (leave blank for default)
DNSServers =
# Used in From header of SIP calls, when caller is unknown. Value must be a valid formatted SIP
# NameAddr. Ie. “{displayname}” <{SIP URI}>. Currently this setting is only used when
# calling iChat endpoints and is never displayed to the end user.
SIPGatewayIdentity = "iChat-gw" <sip:ichat-gw@blitzzgod.com>
# Local port to listen on for SIP messages over UDP or TCP
UDPTCPPort = 5070
# Local port to listen on for SIP messages over TLS
TLSPort = 5071
# TLS domain name for this server (note: domain cert for this domain must be present)
TLSDomain =
# Enable/Disable TCP/UDP CRLFCRLF keepalive packets for SIP endpoints
# 1|true|on|enable to enable, 0|false|off|disable to disable
KeepAlives = enable
# URI of a proxy server to use a SIP outbound proxy. This setting should not be required if
# proper DNS based SIP routing is operational.
OutboundProxy =
# SIP Registration Time - the requested amount of seconds between SIP re-registration requests
# Set to 0, to instruct the iChat gateway not to perform any registrations
RegistrationTime = 3600
# SIP Registration Retry Time - the requested amount of seconds between retrying SIP registration
# requests after a registration failure.
RegistrationRetryTime = 120
########################################################
# General settings
########################################################
# Logging level: NONE|CRIT|ERR|WARNING|INFO|DEBUG|STACK
LogLevel = INFO
# Log Filename
LogFilename = ichat-gw.log
# Log file Max Lines
LogFileMaxLines = 50000
# Gateway IPC Port - for IPC UDP socket bound to 127.0.0.1
GatewayIPCPort = 2078
# Jabber Connector IPC Port - for IPC UDP socket bound to 127.0.0.1
JabberConnectorIPCPort = 2079
# Timeout for obtaining iChat Resources when an iChat user is called.
IChatProceedingTimeout = 5000
# If enabled then any time an IChat endpoint is involved then the media relay will be used.
# If disabled then the media relay is only used if iChat is originator of a Click-to-dial call.
# Note: The media relay MUST be used to perform RTP IPV4<->IPV6 translation and to avoid
# media stream timeout during a SIP phone hold.
# 1|true|on|enable to enable, 0|false|off|disable to disable
AlwaysRelayIChatMedia = true
# Prefer IPv6 over IPv4 - this setting controls which IP address we select when presented
# with the list of IP addresses for an iChat endpoint
PreferIPv6 = true
# Comma separated codec ID filter list - specifies non-interopable codecs that should
# be filtered from Sdp Offers.
# Note: Default is 3 (GSM), since it has proven non-interopable between iChat and SNOM phones
CodecIdFilterList = 3
# Media relay port range min/max settings. These settings define the range of ports that will be used
# by the media relay.
MediaRelayPortRangeMin = 8000
MediaRelayPortRangeMax = 9999
########################################################
# Jabber settings
########################################################
# Hostname or IP address of the Jabber server to connect to
JabberServer = jabber.blitzzgod.com
# Identity of this component - note: domain suffix should match Jabber server domain
JabberComponentName = ichat-gw.jabber.blitzzgod.com
# Jabber Component Password required in order to connect to Jabber server as a component
JabberComponentPassword = password
# Jabber Component Port - port on Jabber server that accepts component connections
JabberComponentPort = 5275
# Duration between Jabber ping messages sent to the server, in order to keep the component connection alive
JabberServerPingDuration = 60
# Username for the iChat Gateway control user - Note: iChat users of the Gateway must add this user to their roster
JabberControlUsername = control
########################################################
# Address Translation Rules (must be listed in pairs)
########################################################
# Rule for mapping any sip address to appropriate jabber JID/domain
TranslationPattern=^sip:(.*)@(.*)$
TranslationOutput=xmpp:$1@jabber.blitzzgod.com
#Rule for mapping any xmpp address to appropriate SIP URI/domain
TranslationPattern=^xmpp:(.*)@(.*)$
TranslationOutput=sip:$1@blitzzgod.com
########################################################
# TLS Configurations
########################################################
#Local path to DH Parameters file
TLSDHParamsFilename =
# Local path to TLS Certificate
TLSCertificate =
# Local path to Private key file
TLSPrivateKey =
# Pass phrase of private key file (can be left blank)
TLSPrivateKeyPassPhrase =
########################################################
# iChat Jabber Connector Settings
########################################################
# Path to iChat jabber connector (ichat-gw-jc) executable
IchatJabberConnectorPath = ichat-gw-jc
#For Windows
#IchatJabberConnectorPath = ichat-gw-jc.exe

View File

@@ -0,0 +1,115 @@
#include <signal.h>
#include "AppSubsystem.hxx"
#include "Server.hxx"
#include <rutil/Log.hxx>
#include <rutil/Logger.hxx>
#include <rutil/DnsUtil.hxx>
#include <rutil/BaseException.hxx>
#include <resip/stack/NameAddr.hxx>
#include <rutil/WinLeakCheck.hxx>
using namespace gateway;
using namespace resip;
using namespace std;
#define RESIPROCATE_SUBSYSTEM AppSubsystem::GATEWAY
static bool finished = false;
static void
signalHandler(int signo)
{
//std::cerr << "Shutting down..." << endl;
finished = true;
}
int
main (int argc, char** argv)
{
#ifndef _WIN32
if ( signal( SIGPIPE, SIG_IGN) == SIG_ERR)
{
cerr << "Couldn't install signal handler for SIGPIPE" << endl;
exit(-1);
}
#else
#if defined(_DEBUG) && defined(LEAK_CHECK)
resip::FindMemoryLeaks fml;
#endif
#endif
if ( signal( SIGINT, signalHandler ) == SIG_ERR )
{
cerr << "Couldn't install signal handler for SIGINT" << endl;
exit( -1 );
}
if ( signal( SIGTERM, signalHandler ) == SIG_ERR )
{
cerr << "Couldn't install signal handler for SIGTERM" << endl;
exit( -1 );
}
initNetwork();
//////////////////////////////////////////////////////////////////////////////
// Create Server
//////////////////////////////////////////////////////////////////////////////
{
Server server(argc, argv);
//////////////////////////////////////////////////////////////////////////////
// Startup and run...
//////////////////////////////////////////////////////////////////////////////
server.startup();
while(true)
{
server.process(50);
if(finished) break;
}
server.shutdown();
}
InfoLog(<< "ichat-gw is shutdown.");
sleepSeconds(2);
}
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of SIP Spectrum nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==================================================================== */

View File

@@ -0,0 +1,72 @@
Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ichat-gw", "ichat-gw_9_0.vcproj", "{8BA87397-9B42-4820-BA53-62FF35C22CAD}"
ProjectSection(ProjectDependencies) = postProject
{A77DCD34-20CA-4602-B185-EE3EAD97713D} = {A77DCD34-20CA-4602-B185-EE3EAD97713D}
{2A8BE839-6466-4001-B224-8F1C3168D04A} = {2A8BE839-6466-4001-B224-8F1C3168D04A}
{12720B4D-F4FC-4502-8FA9-589BF5166216} = {12720B4D-F4FC-4502-8FA9-589BF5166216}
{38594885-CF9C-4C5F-B3F0-E4969D7E3F58} = {38594885-CF9C-4C5F-B3F0-E4969D7E3F58}
{96CD935E-1951-43B8-AF75-F1C06B3778C1} = {96CD935E-1951-43B8-AF75-F1C06B3778C1}
{3D0E5CEB-93DC-4FDB-918B-D08FA369E106} = {3D0E5CEB-93DC-4FDB-918B-D08FA369E106}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rutil", "..\..\rutil\rutil_9_0.vcproj", "{3D0E5CEB-93DC-4FDB-918B-D08FA369E106}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "resiprocate", "..\..\resip\stack\resiprocate_9_0.vcproj", "{2A8BE839-6466-4001-B224-8F1C3168D04A}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dum", "..\..\resip\dum\dum_9_0.vcproj", "{12720B4D-F4FC-4502-8FA9-589BF5166216}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ares", "..\..\rutil\dns\ares\ares_9_0.vcproj", "{96CD935E-1951-43B8-AF75-F1C06B3778C1}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pcre", "..\..\contrib\pcre\pcre_9_0.vcproj", "{38594885-CF9C-4C5F-B3F0-E4969D7E3F58}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jabberconnector", "jabberconnector\jabberconnector_9_0.vcproj", "{A77DCD34-20CA-4602-B185-EE3EAD97713D}"
ProjectSection(ProjectDependencies) = postProject
{EEDA9797-BEAA-4377-96FC-C4B41E063290} = {EEDA9797-BEAA-4377-96FC-C4B41E063290}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gloox", "..\..\contrib\gloox\gloox.vcproj", "{EEDA9797-BEAA-4377-96FC-C4B41E063290}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{8BA87397-9B42-4820-BA53-62FF35C22CAD}.Debug|Win32.ActiveCfg = Debug|Win32
{8BA87397-9B42-4820-BA53-62FF35C22CAD}.Debug|Win32.Build.0 = Debug|Win32
{8BA87397-9B42-4820-BA53-62FF35C22CAD}.Release|Win32.ActiveCfg = Release|Win32
{8BA87397-9B42-4820-BA53-62FF35C22CAD}.Release|Win32.Build.0 = Release|Win32
{3D0E5CEB-93DC-4FDB-918B-D08FA369E106}.Debug|Win32.ActiveCfg = SSL-Debug|Win32
{3D0E5CEB-93DC-4FDB-918B-D08FA369E106}.Debug|Win32.Build.0 = SSL-Debug|Win32
{3D0E5CEB-93DC-4FDB-918B-D08FA369E106}.Release|Win32.ActiveCfg = SSL-Release|Win32
{3D0E5CEB-93DC-4FDB-918B-D08FA369E106}.Release|Win32.Build.0 = SSL-Release|Win32
{2A8BE839-6466-4001-B224-8F1C3168D04A}.Debug|Win32.ActiveCfg = SSL-Debug|Win32
{2A8BE839-6466-4001-B224-8F1C3168D04A}.Debug|Win32.Build.0 = SSL-Debug|Win32
{2A8BE839-6466-4001-B224-8F1C3168D04A}.Release|Win32.ActiveCfg = SSL-Release|Win32
{2A8BE839-6466-4001-B224-8F1C3168D04A}.Release|Win32.Build.0 = SSL-Release|Win32
{12720B4D-F4FC-4502-8FA9-589BF5166216}.Debug|Win32.ActiveCfg = SSL-Debug|Win32
{12720B4D-F4FC-4502-8FA9-589BF5166216}.Debug|Win32.Build.0 = SSL-Debug|Win32
{12720B4D-F4FC-4502-8FA9-589BF5166216}.Release|Win32.ActiveCfg = SSL-Release|Win32
{12720B4D-F4FC-4502-8FA9-589BF5166216}.Release|Win32.Build.0 = SSL-Release|Win32
{96CD935E-1951-43B8-AF75-F1C06B3778C1}.Debug|Win32.ActiveCfg = Debug|Win32
{96CD935E-1951-43B8-AF75-F1C06B3778C1}.Debug|Win32.Build.0 = Debug|Win32
{96CD935E-1951-43B8-AF75-F1C06B3778C1}.Release|Win32.ActiveCfg = Release|Win32
{96CD935E-1951-43B8-AF75-F1C06B3778C1}.Release|Win32.Build.0 = Release|Win32
{38594885-CF9C-4C5F-B3F0-E4969D7E3F58}.Debug|Win32.ActiveCfg = Debug|Win32
{38594885-CF9C-4C5F-B3F0-E4969D7E3F58}.Debug|Win32.Build.0 = Debug|Win32
{38594885-CF9C-4C5F-B3F0-E4969D7E3F58}.Release|Win32.ActiveCfg = Release|Win32
{38594885-CF9C-4C5F-B3F0-E4969D7E3F58}.Release|Win32.Build.0 = Release|Win32
{A77DCD34-20CA-4602-B185-EE3EAD97713D}.Debug|Win32.ActiveCfg = Debug|Win32
{A77DCD34-20CA-4602-B185-EE3EAD97713D}.Debug|Win32.Build.0 = Debug|Win32
{A77DCD34-20CA-4602-B185-EE3EAD97713D}.Release|Win32.ActiveCfg = Release|Win32
{A77DCD34-20CA-4602-B185-EE3EAD97713D}.Release|Win32.Build.0 = Release|Win32
{EEDA9797-BEAA-4377-96FC-C4B41E063290}.Debug|Win32.ActiveCfg = Debug|Win32
{EEDA9797-BEAA-4377-96FC-C4B41E063290}.Debug|Win32.Build.0 = Debug|Win32
{EEDA9797-BEAA-4377-96FC-C4B41E063290}.Release|Win32.ActiveCfg = Release|Win32
{EEDA9797-BEAA-4377-96FC-C4B41E063290}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,300 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
Name="ichat-gw"
ProjectGUID="{8BA87397-9B42-4820-BA53-62FF35C22CAD}"
RootNamespace="ichatgw"
Keyword="Win32Proj"
TargetFrameworkVersion="131072"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="&quot;$(ProjectDir)../../&quot;;&quot;$(ProjectDir)../../contrib/openssl/include&quot;;&quot;$(ProjectDir)../../contrib/openssl/inc32&quot;;&quot;$(ProjectDir)../../contrib/pcre&quot;"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;USE_SSL;USE_IPV6"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="Ws2_32.lib winmm.lib Dnsapi.lib Iphlpapi.lib crypt32.lib &quot;$(ProjectDir)..\..\contrib\openssl\lib\vc\static\libeay32MDd.lib&quot; &quot;$(ProjectDir)..\..\contrib\openssl\lib\vc\static\ssleay32MDd.lib&quot;"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
RandomizedBaseAddress="1"
DataExecutionPrevention="0"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="&quot;$(ProjectDir)../../&quot;;&quot;$(ProjectDir)../../contrib/openssl/include&quot;;&quot;$(ProjectDir)../../contrib/openssl/inc32&quot;;&quot;$(ProjectDir)../../contrib/pcre&quot;"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;USE_SSL;USE_IPV6"
RuntimeLibrary="2"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="false"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="Ws2_32.lib winmm.lib Dnsapi.lib Iphlpapi.lib crypt32.lib &quot;$(ProjectDir)..\..\contrib\openssl\lib\vc\static\libeay32MD.lib&quot; &quot;$(ProjectDir)..\..\contrib\openssl\lib\vc\static\ssleay32MD.lib&quot;"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
RandomizedBaseAddress="1"
DataExecutionPrevention="0"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\AddressTranslator.cxx"
>
</File>
<File
RelativePath=".\AppSubsystem.cxx"
>
</File>
<File
RelativePath=".\B2BSession.cxx"
>
</File>
<File
RelativePath=".\ConfigParser.cxx"
>
</File>
<File
RelativePath=".\ichat-gw.cxx"
>
</File>
<File
RelativePath=".\IChatIPPortData.cxx"
>
</File>
<File
RelativePath=".\IPCThread.cxx"
>
</File>
<File
RelativePath=".\MediaRelay.cxx"
>
</File>
<File
RelativePath=".\MediaRelayPort.cxx"
>
</File>
<File
RelativePath=".\Server.cxx"
>
</File>
<File
RelativePath=".\SipRegistration.cxx"
>
</File>
<File
RelativePath=".\Thread.cxx"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath=".\AddressTranslator.hxx"
>
</File>
<File
RelativePath=".\AppSubsystem.hxx"
>
</File>
<File
RelativePath=".\B2BSession.hxx"
>
</File>
<File
RelativePath=".\ConfigParser.hxx"
>
</File>
<File
RelativePath=".\IChatGatewayCmds.hxx"
>
</File>
<File
RelativePath=".\IChatIPPortData.hxx"
>
</File>
<File
RelativePath=".\IPCThread.hxx"
>
</File>
<File
RelativePath=".\MediaRelay.hxx"
>
</File>
<File
RelativePath=".\MediaRelayPort.hxx"
>
</File>
<File
RelativePath=".\Server.hxx"
>
</File>
<File
RelativePath=".\SipRegistration.hxx"
>
</File>
<File
RelativePath=".\Thread.hxx"
>
</File>
<File
RelativePath=".\Version.hxx"
>
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
<File
RelativePath=".\ichat-gw.config"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

Some files were not shown because too many files have changed in this diff Show More