[Pkg-voip-commits] [SCM] reSIProcate branch, master, updated. upstream/1.8.0_pre1-16-gcca9e38
Daniel Pocock
daniel at pocock.com.au
Sun May 20 18:04:20 UTC 2012
The following commit has been merged in the master branch:
commit 5ac1acc9cbfe46cb93127db2c18e3a2bfc3597fd
Author: Daniel Pocock <daniel at pocock.com.au>
Date: Sun May 20 20:03:01 2012 +0200
Imported Upstream version 1.8.0~pre2
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..8652221
--- /dev/null
+++ b/AUTHORS
@@ -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 at 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
+
+
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..d2036c3
--- /dev/null
+++ b/COPYING
@@ -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 at 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.
diff --git a/Makefile.in b/Makefile.in
index 602caae..dc64afa 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -44,9 +44,10 @@ host_triplet = @host@
subdir = .
DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \
$(srcdir)/Makefile.in $(srcdir)/config.h.in \
- $(srcdir)/resip.spec.in $(top_srcdir)/configure INSTALL \
- build-aux/config.guess build-aux/config.sub build-aux/depcomp \
- build-aux/install-sh build-aux/ltmain.sh build-aux/missing
+ $(srcdir)/resip.spec.in $(top_srcdir)/configure AUTHORS \
+ COPYING INSTALL build-aux/config.guess build-aux/config.sub \
+ build-aux/depcomp build-aux/install-sh build-aux/ltmain.sh \
+ build-aux/missing
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_have_epoll.m4 \
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
diff --git a/RELEASE-PROCESS.txt b/RELEASE-PROCESS.txt
index d83591f..508632e 100644
--- a/RELEASE-PROCESS.txt
+++ b/RELEASE-PROCESS.txt
@@ -9,12 +9,13 @@ Deliverables
------------
The only official deliverable is the tarball, for example,
-resiprocate-1.8.0.tar.gz
+
+ resiprocate-1.8.0.tar.gz
As a courtesy to users, a contrib tarball is also produced,
-containing some third party code, some of it patched for
-use with a specific version of reSIProcate:
-resiprocate-contrib-1.8.0.tar.gz
+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.
@@ -35,10 +36,15 @@ git-svn is used because it makes it easier to build a clean tarball
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 'Update to version 1.8.5'
+
+ git add configure.ac
+ git commit -m 'Update to version 1.8.5'
+
git svn dcommit (send changes back to SVN)
svn copy https://svn.resiprocate.org/rep/resiprocate/main/branches/release-1.8 https://svn.resiprocate.org/rep/resiprocate/main/tags/1.8.5
@@ -56,7 +62,18 @@ it should be discussed on the mailing list and noted in this document.
Make a tarball
--------------
- ./configure --with-ssl && make dist
+ build/release-tarball.sh
+
+ * this script will call configure && make dist
+ * any previous configure settings will be overridden, so you
+ may want to preserve a copy of config.status and config.log
+ or just do this operation from a workspace that is independent
+ of your normal development workspace
+
+Make the contrib tarball
+------------------------
+
+ build/contrib-tarball.sh
Sanity check on tarball
-----------------------
diff --git a/apps/Makefile.am b/apps/Makefile.am
index 899edee..060b4ef 100644
--- a/apps/Makefile.am
+++ b/apps/Makefile.am
@@ -1,5 +1,7 @@
SUBDIRS = clicktocall
SUBDIRS += sipdial
+if BUILD_ICHAT_GW
SUBDIRS += ichat-gw
+endif
diff --git a/apps/Makefile.in b/apps/Makefile.in
index bd80edf..5ee80bf 100644
--- a/apps/Makefile.in
+++ b/apps/Makefile.in
@@ -33,6 +33,7 @@ PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
+ at BUILD_ICHAT_GW_TRUE@am__append_1 = ichat-gw
subdir = apps
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
@@ -63,7 +64,7 @@ AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
distdir
ETAGS = etags
CTAGS = ctags
-DIST_SUBDIRS = $(SUBDIRS)
+DIST_SUBDIRS = clicktocall sipdial ichat-gw
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
am__relativize = \
dir0=`pwd`; \
@@ -215,7 +216,7 @@ target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
-SUBDIRS = clicktocall sipdial ichat-gw
+SUBDIRS = clicktocall sipdial $(am__append_1)
all: all-recursive
.SUFFIXES:
diff --git a/apps/ichat-gw/IChatIPPortData.cxx b/apps/ichat-gw/IChatIPPortData.cxx
index 43da35c..b3ddd19 100644
--- a/apps/ichat-gw/IChatIPPortData.cxx
+++ b/apps/ichat-gw/IChatIPPortData.cxx
@@ -1,3 +1,6 @@
+#if defined(HAVE_CONFIG_H)
+#include "config.h"
+#endif
#include <rutil/Logger.hxx>
#include <resip/stack/Helper.hxx>
@@ -63,9 +66,14 @@ IChatIPPortData::IChatIPPortData(const std::string& hexblob) : mHexBlob(hexblob)
}
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.");
+ assert(0);
+#endif
}
InfoLog(<< "IChatIPPortData: name=" << mIPPortDataList.back().first << " addr=" << mIPPortDataList.back().second);
}
diff --git a/apps/ichat-gw/Makefile.am b/apps/ichat-gw/Makefile.am
index f29be2e..db26edc 100644
--- a/apps/ichat-gw/Makefile.am
+++ b/apps/ichat-gw/Makefile.am
@@ -9,7 +9,7 @@ SUBDIRS = .
# this has more external dependencies, it has been adapted
# for autotools and can be enabled manually if the deps
# are available
-#SUBDIRS += jabberconnector
+SUBDIRS += jabberconnector
#AM_CXXFLAGS = -DUSE_ARES
diff --git a/apps/ichat-gw/Makefile.in b/apps/ichat-gw/Makefile.in
index 722cbac..5dfc818 100644
--- a/apps/ichat-gw/Makefile.in
+++ b/apps/ichat-gw/Makefile.in
@@ -269,7 +269,10 @@ top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
EXTRA_DIST = ichat-gw.config doc *.sln *.vcproj
-SUBDIRS = .
+# this has more external dependencies, it has been adapted
+# for autotools and can be enabled manually if the deps
+# are available
+SUBDIRS = . jabberconnector
ichat_gw_LDADD = ../../resip/dum/libdum.la \
../../resip/stack/libresip.la ../../rutil/librutil.la \
@LIBSSL_LIBADD@ -lpcre -lpthread
diff --git a/apps/ichat-gw/jabberconnector/IChatUser.cxx b/apps/ichat-gw/jabberconnector/IChatUser.cxx
new file mode 100644
index 0000000..1fa3ccb
--- /dev/null
+++ b/apps/ichat-gw/jabberconnector/IChatUser.cxx
@@ -0,0 +1,210 @@
+#include "IChatUser.hxx"
+#include "JabberComponent.hxx"
+
+using namespace gateway;
+using namespace std;
+
+namespace gateway
+{
+
+IChatUser::IChatUser(JabberComponent& component, const std::string& jid) :
+ mJID(jid),
+ mComponent(component)
+{
+}
+
+IChatUser::~IChatUser()
+{
+ ResourceMap::iterator it = mResources.begin();
+ for(;it!=mResources.end();it++)
+ {
+ delete it->second;
+ }
+}
+
+void
+IChatUser::updateResourceInfo(const std::string& resourceId, const gloox::Presence& presence, int priority, bool avAvail)
+{
+ bool originalUnavailability = isUnavailable();
+ if(resourceId.empty())
+ {
+ if(presence == gloox::PresenceUnavailable)
+ {
+ // All resources are unanavaiable
+ ResourceMap::iterator it = mResources.begin();
+ for(; it != mResources.end(); it++)
+ {
+ delete it->second;
+ }
+ mResources.clear();
+ }
+ else
+ {
+ // PresenceAvailable with no resource is meaningless
+ }
+ }
+ else
+ {
+ ResourceMap::iterator it = mResources.find(resourceId);
+ if(it != mResources.end())
+ {
+ if(presence == gloox::PresenceUnavailable)
+ {
+ delete it->second;
+ mResources.erase(it);
+ }
+ else
+ {
+ it->second->mPresence = presence;
+ it->second->mPriority = priority;
+ it->second->mAvAvail = avAvail;
+ }
+ }
+ else
+ {
+ if(presence != gloox::PresenceUnavailable)
+ {
+ mResources[resourceId] = new ResourceInfo(presence, priority, avAvail);
+ }
+ }
+ }
+ if(originalUnavailability && !isUnavailable())
+ {
+ // User was originally unavailable and now they are available - register SIP endpoint
+ mComponent.sipRegisterJabberUser(mJID);
+ }
+ else if(!originalUnavailability && isUnavailable())
+ {
+ // User was originally available and now they are unavailable - unregister SIP endpoint
+ mComponent.sipUnregisterJabberUser(mJID);
+ }
+}
+
+bool
+IChatUser::isUnavailable()
+{
+ return mResources.empty();
+}
+
+IChatUser::ResourceMap::iterator
+IChatUser::getMostAvailableResourceItr()
+{
+ ResourceMap::iterator itBestResource = mResources.end();
+ ResourceMap::iterator it = mResources.begin();
+ for(;it!=mResources.end();it++)
+ {
+ if(it->second->mAvAvail)
+ {
+ if(itBestResource == mResources.end())
+ {
+ itBestResource=it;
+ }
+ else
+ {
+ if(it->second->mPresence < itBestResource->second->mPresence)
+ {
+ itBestResource=it;
+ }
+ else if(it->second->mPresence == itBestResource->second->mPresence)
+ {
+ if(it->second->mPriority < itBestResource->second->mPriority)
+ {
+ itBestResource=it;
+ }
+ }
+ }
+ }
+ }
+ return itBestResource;
+}
+
+const std::string&
+IChatUser::getMostAvailableResource()
+{
+ static const std::string empty;
+ ResourceMap::iterator itBestResource = getMostAvailableResourceItr();
+ if(itBestResource != mResources.end())
+ {
+ return itBestResource->first;
+ }
+ return empty;
+}
+
+bool
+IChatUser::getMostAvailableResourceList(std::list<std::string>& resourceList)
+{
+ bool ret = false;
+
+ // Pass one - go through list and see what highest mPresence availability is
+ ResourceMap::iterator itBestResource = getMostAvailableResourceItr();
+
+ // Pass two - return all resources with matching mPresence and mPriority
+ if(itBestResource != mResources.end())
+ {
+ ResourceMap::iterator it = mResources.begin();
+ for(;it!=mResources.end();it++)
+ {
+ if(it->second->mAvAvail &&
+ it->second->mPresence == itBestResource->second->mPresence &&
+ it->second->mPriority == itBestResource->second->mPriority)
+ {
+ resourceList.push_back(it->first);
+ ret = true;
+ }
+ }
+ }
+ return ret;
+}
+
+void
+IChatUser::addSubscribedGatewayUser(const std::string& jid)
+{
+ mSubscribedGatewayUsers.insert(jid);
+}
+
+void
+IChatUser::removeSubscribedGatewayUser(const std::string& jid)
+{
+ SubscribedGatewayUserList::iterator it = mSubscribedGatewayUsers.find(jid);
+ if(it!=mSubscribedGatewayUsers.end())
+ {
+ mSubscribedGatewayUsers.erase(it);
+ }
+}
+
+}
+
+/* ====================================================================
+
+ 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.
+
+ ==================================================================== */
+
diff --git a/apps/ichat-gw/AddressTranslator.hxx b/apps/ichat-gw/jabberconnector/IChatUser.hxx
similarity index 54%
copy from apps/ichat-gw/AddressTranslator.hxx
copy to apps/ichat-gw/jabberconnector/IChatUser.hxx
index 6d6a85d..f792579 100644
--- a/apps/ichat-gw/AddressTranslator.hxx
+++ b/apps/ichat-gw/jabberconnector/IChatUser.hxx
@@ -1,47 +1,72 @@
-#if !defined(AddressTranslator_hxx)
-#define AddressTranslator_hxx
+#if !defined(IChatUser_hxx)
+#define IChatUser_hxx
+#include <map>
+#include <set>
#include <list>
#ifdef WIN32
-#include <pcreposix.h>
+#define RESIP_CONTRIB_GLOOX
+#endif
+
+// Gloox includes
+#ifndef RESIP_CONTRIB_GLOOX
+#include <gloox/component.h>
+#include <gloox/presence.h>
#else
-#include <regex.h>
+#include <src/component.h>
+#include <src/presence.h>
#endif
-#include "rutil/Data.hxx"
namespace gateway
{
-class AddressTranslator
+class JabberComponent;
+
+class ResourceInfo
{
- 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;
- regex_t *preq;
- };
-
- typedef std::list<FilterOp> FilterOpList;
- FilterOpList mFilterOperators;
+public:
+ ResourceInfo(const gloox::Presence& presence, int priority, bool avAvail) :
+ mPresence(presence), mPriority(priority), mAvAvail(avAvail) {}
+ ~ResourceInfo() {}
+
+ gloox::Presence mPresence;
+ int mPriority;
+ bool mAvAvail;
+};
+
+class IChatUser
+{
+public:
+ IChatUser(JabberComponent& component, const std::string& jid);
+ ~IChatUser();
+
+ typedef std::set<std::string> SubscribedGatewayUserList;
+
+ void updateResourceInfo(const std::string& resourceId, const gloox::Presence& presence, int priority, bool avAvail);
+ bool isUnavailable();
+ const std::string& getMostAvailableResource();
+ bool getMostAvailableResourceList(std::list<std::string>& resourceList);
+
+ void addSubscribedGatewayUser(const std::string& jid);
+ void removeSubscribedGatewayUser(const std::string& jid);
+ const SubscribedGatewayUserList& getSubscribedGatewayUserList() { return mSubscribedGatewayUsers; }
+
+private:
+ std::string mJID;
+
+ typedef std::map<std::string, ResourceInfo*> ResourceMap;
+ ResourceMap mResources;
+
+ ResourceMap::iterator getMostAvailableResourceItr();
+
+ SubscribedGatewayUserList mSubscribedGatewayUsers;
+ JabberComponent& mComponent;
};
}
-#endif
+#endif
/* ====================================================================
diff --git a/apps/ichat-gw/jabberconnector/JabberComponent.cxx b/apps/ichat-gw/jabberconnector/JabberComponent.cxx
new file mode 100644
index 0000000..6f477b3
--- /dev/null
+++ b/apps/ichat-gw/jabberconnector/JabberComponent.cxx
@@ -0,0 +1,1181 @@
+
+#if defined( WIN32 )
+#include <time.h>
+#endif
+
+#include <sstream>
+#include <assert.h>
+#include <algorithm>
+#include "../Version.hxx"
+#include "JabberComponent.hxx"
+#include "IChatUser.hxx"
+
+#ifndef RESIP_CONTRIB_GLOOX
+#include <gloox/disco.h>
+#include <gloox/mutex.h>
+#else
+#include <src/disco.h>
+#include <src/mutex.h>
+#endif
+
+using namespace gateway;
+using namespace gloox;
+using namespace std;
+
+extern void sleepSeconds(unsigned int seconds);
+
+void
+IChatCallRequest::sendIChatVCRequest(const std::string& fullTo)
+{
+ // Only allow one VCRequest per resource - this guards against receiving multiple
+ // presence messages from the same resource
+ if(mPendingVCRequestSet.find(fullTo) == mPendingVCRequestSet.end())
+ {
+ mJabberComponent->notifyIChatCallProceeding(mB2BSessionHandle, fullTo);
+
+ assert(mJabberComponent);
+ mJabberComponent->sendPresence(fullTo, mJabberComponent->mControlJID, false /* advertiseIChatSupport */, true /* available */); // Doing this let's us push the control presence as well send calls
+
+ std::string id = mJabberComponent->mComponent->getID();
+
+ Tag *iq = new Tag("iq");
+ iq->addAttribute("type", "set");
+ iq->addAttribute("id", id);
+ iq->addAttribute("to", fullTo.c_str());
+ iq->addAttribute("from", mFrom.c_str());
+ Tag *query = new Tag(iq, "query");
+ query->addAttribute("xmlns", "apple:iq:vc:request");
+ new Tag(query, "VCNewCallerIPPortData", mJabberComponent->mLocalIChatPortListBlob);
+ new Tag(query, "isAudioOnly", "1");
+ new Tag(query, "extSIPPort", "0");
+ new Tag(query, "extIPAddr", "127.0.0.1");
+ new Tag(query, "VCProtocolVersion", "1");
+ mJabberComponent->mComponent->send(iq);
+
+ mPendingVCRequestSet.insert(fullTo);
+ }
+}
+
+void
+IChatCallRequest::receivedIChatVCResponse(const std::string& from)
+{
+ std::set<std::string>::iterator it = mPendingVCRequestSet.find(from);
+ mPendingVCRequestSet.erase(it); // Remove responded JID from list and cancel all others
+ sendIChatVCCancelToAll();
+}
+
+void
+IChatCallRequest::sendIChatVCCancelToAll()
+{
+ std::set<std::string>::iterator it = mPendingVCRequestSet.begin();
+ std::string id = mJabberComponent->mComponent->getID();
+
+ // Send a cancel out for each VCRequest
+ for(;it!=mPendingVCRequestSet.end();it++)
+ {
+ Tag *iq = new Tag("iq");
+ iq->addAttribute("type", "set");
+ iq->addAttribute("id", id);
+ iq->addAttribute("to", it->c_str());
+ iq->addAttribute("from", mFrom.c_str());
+ Tag *query = new Tag(iq, "query");
+ query->addAttribute("xmlns", "apple:iq:vc:cancel");
+ new Tag(query, "VCProtocolVersion", "1");
+ mJabberComponent->mComponent->send(iq);
+ }
+ mPendingVCRequestSet.clear();
+}
+
+void
+IChatCallRequest::sendIChatVCResponse(bool accept)
+{
+ Tag *iq = new Tag( "iq" );
+ iq->addAttribute( "type", "set" );
+ iq->addAttribute( "id", mJabberComponent->mComponent->getID() );
+ iq->addAttribute( "to", mFrom );
+ iq->addAttribute( "from", mTo );
+ Tag *query = new Tag( iq, "query" );
+ query->addAttribute( "xmlns", "apple:iq:vc:response");
+ if(accept)
+ {
+ new Tag( query, "response", "0" );
+ new Tag( query, "connectData", mJabberComponent->mLocalIChatPortListBlob);
+ }
+ else
+ {
+ new Tag( query, "response", "1" );
+ new Tag( query, "connectData", "");
+ }
+ //new Tag( query, "responseData", "1" ); // doesn't appear to be required
+ new Tag( query, "VCProtocolVersion", "1" );
+ mJabberComponent->mComponent->send(iq);
+}
+
+class IPCMutexGloox : public IPCMutex
+{
+public:
+ IPCMutexGloox() {}
+ virtual ~IPCMutexGloox() {}
+ virtual void lock() { mMutex.lock(); }
+ virtual void unlock() { mMutex.unlock(); }
+private:
+ gloox::Mutex mMutex;
+};
+IPCMutexGloox g_IPCGlooxMutex;
+
+JabberComponent::JabberComponent(unsigned short jabberConnectorIPCPort,
+ unsigned short gatewayIPCPort,
+ const std::string& server,
+ const std::string& component,
+ const std::string& password,
+ int port,
+ unsigned int serverPingDuration,
+ const std::string& controlUser,
+ const std::string& localIChatPortListBlob)
+ : mStopping(false),
+ mServerPingDuration(serverPingDuration),
+ mLocalIChatPortListBlob(localIChatPortListBlob),
+ mIPCThread(jabberConnectorIPCPort, gatewayIPCPort, this, &g_IPCGlooxMutex)
+{
+ mIPCThread.run();
+
+ mComponent = new Component("jabber:component:accept", server, component, password, port);
+
+ mComponent->registerMessageHandler(this);
+ mComponent->registerConnectionListener(this);
+ mComponent->registerPresenceHandler(this);
+ mComponent->registerSubscriptionHandler(this);
+ mComponent->registerIqHandler(this, "apple:iq:vc:request");
+ mComponent->registerIqHandler(this, "apple:iq:vc:cancel");
+ mComponent->registerIqHandler(this, "apple:iq:vc:response");
+ mComponent->registerIqHandler(this, "apple:iq:vc:counterProposal");
+ mComponent->logInstance().registerLogHandler(LogLevelDebug, LogAreaAll, this);
+
+ mComponent->disco()->registerNodeHandler(this, "apple:ichat:caps#avavail");
+ mComponent->disco()->registerNodeHandler(this, "apple:ichat:caps#audio");
+ mComponent->disco()->registerNodeHandler(this, "apple:ichat:caps#avcap");
+ mComponent->disco()->registerNodeHandler(this, "apple:ichat:caps#448");
+ mComponent->disco()->setIdentity("server", "ichat-gw");
+ mComponent->disco()->setVersion("ichat-gw", ICHATGW_VERSION_STRING);
+
+ //mComponent->setTls(tlsPolicy); // This setting appears to have no effect on Component connections
+
+ mControlJID = controlUser + "@" + component;
+}
+
+JabberComponent::~JabberComponent()
+{
+ mIPCThread.shutdown();
+ mIPCThread.join();
+}
+
+void
+JabberComponent::thread()
+{
+ handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::thread - starting...");
+ while(!mStopping)
+ {
+ mComponent->connect(false);
+ ConnectionError rc;
+ time_t lastRecvTime=time(0);
+ while((rc=mComponent->recv(mServerPingDuration * 1000000)) == ConnNoError)
+ {
+ time_t now = time(0);
+ if(now-lastRecvTime >= mServerPingDuration)
+ {
+ mComponent->whitespacePing();
+ }
+ lastRecvTime = now;
+ }
+
+ if(!mStopping)
+ {
+ std::ostringstream oss;
+ oss << "JabberComponent::thread - recv error, rc=" << rc;
+ handleLog(gloox::LogLevelError, gloox::LogAreaUser, oss.str());
+ // Wait 10 seconds then try again
+ sleepSeconds(10);
+ if(mComponent->state() != gloox::StateDisconnected)
+ {
+ mComponent->disconnect();
+ }
+ }
+ }
+ handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::thread - shutdown.");
+}
+
+void
+JabberComponent::stop()
+{
+ mStopping = true;
+ disconnect();
+}
+
+void
+JabberComponent::disconnect()
+{
+ if(mComponent->state() == gloox::StateDisconnected) return;
+
+ mIChatUserMutex.lock();
+
+ // Tell users that control user is now offline
+ IChatUserMap::iterator it = mIChatUsers.begin();
+ for(;it!=mIChatUsers.end();it++)
+ {
+ // Notify user that subscribed users are now offline
+ const IChatUser::SubscribedGatewayUserList& subscribedUserList = it->second->getSubscribedGatewayUserList();
+ IChatUser::SubscribedGatewayUserList::const_iterator it2 = subscribedUserList.begin();
+ for(;it2!=subscribedUserList.end();it2++)
+ {
+ sendPresence(it->first, *it2, false, false /* available? */);
+ }
+ delete it->second;
+ }
+ mIChatUsers.clear();
+
+ mIChatUserMutex.unlock();
+
+ mComponent->disconnect();
+}
+
+void
+JabberComponent::initiateIChatCall(const std::string& to, const std::string& from, unsigned int handle, bool alertOneOnly)
+{
+ JID jid(to);
+ mOutstandingClientIChatCallRequestsMutex.lock();
+
+ // Add call request data to map
+ std::string key = makeVCRequestKey(jid.bare(),from);
+ IChatCallRequest* iChatCallRequest = &(mOutstandingClientIChatCallRequests[key] = IChatCallRequest(this, to, from, handle));
+ handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::initiateiChatCall - key=" + key);
+
+ // If there is no resource, then we need to query the bare JID and find iChat resources
+ if(jid.resource().empty())
+ {
+ bool found = false;
+ if(alertOneOnly)
+ {
+ // First check if we have any info cached locally
+ std::string fullJID;
+ if(getMostAvailableIChatUserFullJID(jid, fullJID))
+ {
+ found = true;
+ iChatCallRequest->sendIChatVCRequest(fullJID);
+ }
+ }
+ else
+ {
+ std::list<std::string> fullJIDList;
+ if(getMostAvailableIChatUserFullJIDList(jid, fullJIDList))
+ {
+ found = true;
+ std::list<std::string>::iterator it = fullJIDList.begin();
+ for(;it!=fullJIDList.end();it++)
+ {
+ iChatCallRequest->sendIChatVCRequest(*it);
+ }
+ }
+ }
+
+ if(!found)
+ {
+ // No local info - try to probe
+ Tag *iq = new Tag("presence");
+ iq->addAttribute("type", "probe");
+ iq->addAttribute("to", to.c_str());
+ iq->addAttribute("from", mControlJID);
+ mComponent->send(iq);
+ }
+ }
+ else // We have full JID - send the vc-request directly to the resource
+ {
+ iChatCallRequest->sendIChatVCRequest(to);
+ }
+ mOutstandingClientIChatCallRequestsMutex.unlock();
+}
+
+void
+JabberComponent::cancelIChatCall(const std::string& to, const std::string& from)
+{
+ JID jid(to);
+ mOutstandingClientIChatCallRequestsMutex.lock();
+
+ IChatCallRequestMap::iterator it = findOutstandingClientIChatCallRequest(jid.bare(), from);
+ if(it != mOutstandingClientIChatCallRequests.end())
+ {
+ it->second.sendIChatVCCancelToAll();
+ handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::cancelIChatCall - success");
+ mOutstandingClientIChatCallRequests.erase(it);
+ }
+ else
+ {
+ handleLog(gloox::LogLevelWarning, gloox::LogAreaUser, "JabberComponent::cancelIChatCall - not found");
+ }
+ mOutstandingClientIChatCallRequestsMutex.unlock();
+}
+
+void
+JabberComponent::proceedingIChatCall(const std::string& to, const std::string& from, unsigned int handle)
+{
+ mOutstandingServerIChatCallRequestsMutex.lock();
+ IChatCallRequestMap::iterator it = findOutstandingServerIChatCallRequest(to, from);
+ if(it!=mOutstandingServerIChatCallRequests.end())
+ {
+ // Store session handle for notifications to SIP layer
+ assert(it->second.mB2BSessionHandle == 0);
+ std::ostringstream oss;
+ oss << "JabberComponent::proceedingIChatCall - set handle to " << handle;
+ handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, oss.str());
+ it->second.mB2BSessionHandle = handle;
+
+ // If already cancelled, then notify SIP layer now
+ if(it->second.mCancelled)
+ {
+ notifyIChatCallCancelled(it->second.mB2BSessionHandle);
+ mOutstandingServerIChatCallRequests.erase(it);
+ }
+ }
+ mOutstandingServerIChatCallRequestsMutex.unlock();
+}
+
+void
+JabberComponent::acceptIChatCall(const std::string& to, const std::string& from)
+{
+ mOutstandingServerIChatCallRequestsMutex.lock();
+ IChatCallRequestMap::iterator it = findOutstandingServerIChatCallRequest(to, from);
+ if(it!=mOutstandingServerIChatCallRequests.end())
+ {
+ it->second.sendIChatVCResponse(true);
+ mOutstandingServerIChatCallRequests.erase(it);
+ }
+ mOutstandingServerIChatCallRequestsMutex.unlock();
+}
+
+void
+JabberComponent::rejectIChatCall(const std::string& to, const std::string& from)
+{
+ mOutstandingServerIChatCallRequestsMutex.lock();
+ IChatCallRequestMap::iterator it = findOutstandingServerIChatCallRequest(to, from);
+ if(it!=mOutstandingServerIChatCallRequests.end())
+ {
+ it->second.sendIChatVCResponse(false);
+ mOutstandingServerIChatCallRequests.erase(it);
+ }
+ mOutstandingServerIChatCallRequestsMutex.unlock();
+}
+
+std::string
+JabberComponent::makeVCRequestKey(const std::string& bareTo, const std::string& bareFrom)
+{
+ std::string key = bareTo + "|" + bareFrom;
+#ifdef WIN32
+ std::transform(key.begin(), key.end(), key.begin(), tolower);
+#else
+ std::transform(key.begin(), key.end(), key.begin(), (int(*)(int))std::tolower);
+#endif
+ return key;
+}
+
+JabberComponent::IChatCallRequestMap::iterator
+JabberComponent::findOutstandingClientIChatCallRequest(const std::string& bareTo, const std::string& bareFrom)
+{
+ std::string key = makeVCRequestKey(bareTo, bareFrom);
+ handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::findOutstandingClientIChatCallRequest - key=" + key);
+ return mOutstandingClientIChatCallRequests.find(key);
+}
+
+void
+JabberComponent::failOutstandingClientIChatCallRequest(const std::string& bareTo, const std::string& bareFrom, unsigned int code)
+{
+ mOutstandingClientIChatCallRequestsMutex.lock();
+ IChatCallRequestMap::iterator it = findOutstandingClientIChatCallRequest(bareTo, bareFrom);
+ if(it!=mOutstandingClientIChatCallRequests.end())
+ {
+ notifyIChatCallFailed(it->second.mB2BSessionHandle, code);
+ mOutstandingClientIChatCallRequests.erase(it);
+ }
+ mOutstandingClientIChatCallRequestsMutex.unlock();
+}
+
+void
+JabberComponent::failOutstandingClientIChatCallRequest(const std::string& bareTo, unsigned int code)
+{
+ mOutstandingClientIChatCallRequestsMutex.lock();
+ IChatCallRequestMap::iterator it = mOutstandingClientIChatCallRequests.begin();
+ while(it != mOutstandingClientIChatCallRequests.end())
+ {
+ if(it->second.mTo == bareTo)
+ {
+ notifyIChatCallFailed(it->second.mB2BSessionHandle, code);
+ mOutstandingClientIChatCallRequests.erase(it++);
+ }
+ else
+ {
+ it++;
+ }
+ }
+ mOutstandingClientIChatCallRequestsMutex.unlock();
+}
+
+JabberComponent::IChatCallRequestMap::iterator
+JabberComponent::findOutstandingServerIChatCallRequest(const std::string& bareTo, const std::string& bareFrom)
+{
+ std::string key = makeVCRequestKey(bareTo, bareFrom);
+ handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::findOutstandingServerIChatCallRequest - key=" + key);
+ return mOutstandingServerIChatCallRequests.find(key);
+}
+
+void
+JabberComponent::cancelOutstandingServerIChatCallRequest(const std::string& bareTo, const std::string& bareFrom)
+{
+ mOutstandingServerIChatCallRequestsMutex.lock();
+ IChatCallRequestMap::iterator it = findOutstandingServerIChatCallRequest(bareTo, bareFrom);
+ if(it!=mOutstandingServerIChatCallRequests.end())
+ {
+ if(it->second.mB2BSessionHandle != 0)
+ {
+ handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::cancelOutstandingServerIChatCallRequest - to=" + bareTo + " from=" + bareFrom);
+ notifyIChatCallCancelled(it->second.mB2BSessionHandle);
+ mOutstandingServerIChatCallRequests.erase(it);
+ }
+ else
+ {
+ // We don't have a session handle yet, so flag request as cancelled,
+ // when session handle arrives, call notifyIChatCallCancelled and remove entry
+ it->second.mCancelled = true;
+ handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::cancelOutstandingServerIChatCallRequest - no session handle yet, pending - to=" + bareTo + " from=" + bareFrom);
+ }
+ }
+ mOutstandingServerIChatCallRequestsMutex.unlock();
+}
+
+void
+JabberComponent::probePresence(const std::string& to)
+{
+ Tag *presence = new Tag("presence");
+ presence->addAttribute("type", "probe");
+ presence->addAttribute("to", to);
+ presence->addAttribute("from", mControlJID);
+ mComponent->send(presence);
+}
+
+void
+JabberComponent::sendPresenceForRequest(Stanza* stanza)
+{
+ sendPresence(stanza->from().bare(), stanza->to().full(), stanza->to().bare() != mControlJID, true /* available */);
+}
+
+void
+JabberComponent::sendPresence(const std::string& to, const std::string& from, bool advertiseIChatSupport, bool available)
+{
+ Tag *presence = new Tag("presence");
+ if(!available)
+ {
+ presence->addAttribute("type", "unavailable");
+ }
+ presence->addAttribute("to", to);
+ presence->addAttribute("from", from);
+ new Tag(presence, "priority", "0");
+ if(advertiseIChatSupport)
+ {
+ Tag* c = new Tag(presence, "c");
+ c->addAttribute("xmlns", "http://jabber.org/protocol/caps");
+ c->addAttribute("node", "apple:ichat:caps");
+ c->addAttribute("ver", "448"); // Note: Use version 448 so we don't collide with actual iChat version
+ c->addAttribute("ext", "avavail avcap audio");
+ }
+ mComponent->send(presence);
+}
+
+void
+JabberComponent::sendSubscriptionResponse(const std::string& to, const std::string& from, bool success)
+{
+ if(success)
+ {
+ Tag *p = new Tag( "presence" );
+ p->addAttribute( "type", "subscribed" );
+ p->addAttribute( "to", to );
+ p->addAttribute( "from", from );
+ mComponent->send( p );
+
+ mUserDb.addSubscribedJID(to.c_str(), from.c_str());
+ storeIChatSubscribedUser(to, from);
+ sendPresence(to, from, from != mControlJID, true);
+
+ // Subscribe back to client to ensure we are subscribed to client
+ Tag *iq = new Tag("presence");
+ iq->addAttribute("type", "subscribe");
+ iq->addAttribute("to", to);
+ iq->addAttribute("from", mControlJID);
+ mComponent->send(iq);
+ }
+ else
+ {
+ Tag *p = new Tag( "presence" );
+ p->addAttribute( "type", "unsubscribed" );
+ p->addAttribute( "to", to );
+ p->addAttribute( "from", from );
+ mComponent->send( p );
+ }
+}
+
+void
+JabberComponent::removeIChatSubscribedUser(const std::string& user, const std::string& subscribedJID)
+{
+ mIChatUserMutex.lock();
+
+ IChatUserMap::iterator it = mIChatUsers.find(user);
+ if(it != mIChatUsers.end())
+ {
+ it->second->removeSubscribedGatewayUser(subscribedJID);
+ }
+
+ mIChatUserMutex.unlock();
+}
+
+void
+JabberComponent::storeIChatSubscribedUser(const std::string& user, const std::string& subscribedJID)
+{
+ mIChatUserMutex.lock();
+
+ IChatUserMap::iterator it = mIChatUsers.find(user);
+ if(it == mIChatUsers.end())
+ {
+ // User is not yet present in map
+ IChatUser* iChatUser = new IChatUser(*this, user);
+ iChatUser->addSubscribedGatewayUser(subscribedJID);
+ mIChatUsers[user] = iChatUser;
+ }
+ else
+ {
+ it->second->addSubscribedGatewayUser(subscribedJID);
+ }
+
+ mIChatUserMutex.unlock();
+}
+
+void
+JabberComponent::storeIChatPresence(const gloox::JID& jid, const gloox::Presence& presence, int priority, bool avAvail)
+{
+ mIChatUserMutex.lock();
+
+ IChatUserMap::iterator it = mIChatUsers.find(jid.bare());
+ if(it == mIChatUsers.end())
+ {
+ if(presence != gloox::PresenceUnavailable && !jid.resource().empty())
+ {
+ // User is not yet present in map
+ IChatUser* iChatUser = new IChatUser(*this, jid.bare());
+ iChatUser->updateResourceInfo(jid.resource(), presence, priority, avAvail);
+ mIChatUsers[jid.bare()] = iChatUser;
+ }
+ }
+ else
+ {
+ it->second->updateResourceInfo(jid.resource(), presence, priority, avAvail);
+ }
+
+ mIChatUserMutex.unlock();
+}
+
+bool
+JabberComponent::getMostAvailableIChatUserFullJID(const gloox::JID& jid, std::string& fullJID)
+{
+ bool ret = false;
+ mIChatUserMutex.lock();
+
+ IChatUserMap::iterator it = mIChatUsers.find(jid.bare());
+ if(it != mIChatUsers.end())
+ {
+ std::string resource = it->second->getMostAvailableResource();
+ if(!resource.empty())
+ {
+ JID temp(jid);
+ temp.setResource(resource);
+ fullJID = temp.full();
+ ret = true;
+ }
+ }
+
+ mIChatUserMutex.unlock();
+
+ return ret;
+}
+
+bool
+JabberComponent::getMostAvailableIChatUserFullJIDList(const gloox::JID& jid, std::list<std::string>& fullJIDList)
+{
+ bool ret = false;
+ mIChatUserMutex.lock();
+
+ IChatUserMap::iterator it = mIChatUsers.find(jid.bare());
+ if(it != mIChatUsers.end())
+ {
+ std::list<std::string> resourceList;
+ if(it->second->getMostAvailableResourceList(resourceList))
+ {
+ std::list<std::string>::iterator listIt = resourceList.begin();
+ for(;listIt!=resourceList.end();listIt++)
+ {
+ if(!listIt->empty())
+ {
+ JID temp(jid);
+ temp.setResource(*listIt);
+ fullJIDList.push_back(temp.full());
+ ret = true;
+ }
+ }
+ }
+ }
+
+ mIChatUserMutex.unlock();
+
+ return ret;
+}
+
+void
+JabberComponent::notifyIChatCallRequest(const std::string& to, const std::string& from)
+{
+ IPCMsg msg;
+ msg.addArg("notifyIChatCallRequest");
+ msg.addArg(to.c_str());
+ msg.addArg(from.c_str());
+ mIPCThread.sendIPCMsg(msg);
+}
+
+void
+JabberComponent::notifyIChatCallCancelled(unsigned int handle)
+{
+ IPCMsg msg;
+ msg.addArg("notifyIChatCallCancelled");
+ msg.addArg(handle);
+ mIPCThread.sendIPCMsg(msg);
+}
+
+void
+JabberComponent::notifyIChatCallProceeding(unsigned int handle, const std::string& to)
+{
+ IPCMsg msg;
+ msg.addArg("notifyIChatCallProceeding");
+ msg.addArg(handle);
+ msg.addArg(to.c_str());
+ mIPCThread.sendIPCMsg(msg);
+}
+
+void
+JabberComponent::notifyIChatCallFailed(unsigned int handle, unsigned int statusCode)
+{
+ IPCMsg msg;
+ msg.addArg("notifyIChatCallFailed");
+ msg.addArg(handle);
+ msg.addArg(statusCode);
+ mIPCThread.sendIPCMsg(msg);
+}
+
+void
+JabberComponent::continueIChatCall(unsigned int handle, const std::string& remoteIPPortListBlob)
+{
+ IPCMsg msg;
+ msg.addArg("continueIChatCall");
+ msg.addArg(handle);
+ msg.addArg(remoteIPPortListBlob.c_str());
+ mIPCThread.sendIPCMsg(msg);
+}
+
+void
+JabberComponent::sipRegisterJabberUser(const std::string& jidToRegister)
+{
+ IPCMsg msg;
+ msg.addArg("sipRegisterJabberUser");
+ msg.addArg(jidToRegister.c_str());
+ mIPCThread.sendIPCMsg(msg);
+}
+
+void
+JabberComponent::sipUnregisterJabberUser(const std::string& jidToUnregister)
+{
+ IPCMsg msg;
+ msg.addArg("sipUnregisterJabberUser");
+ msg.addArg(jidToUnregister.c_str());
+ mIPCThread.sendIPCMsg(msg);
+}
+
+void
+JabberComponent::checkSubscription(const std::string& to, const std::string& from)
+{
+ IPCMsg msg;
+ msg.addArg("checkSubscription");
+ msg.addArg(to.c_str());
+ msg.addArg(from.c_str());
+ mIPCThread.sendIPCMsg(msg);
+}
+
+void
+JabberComponent::onNewIPCMsg(const IPCMsg& msg)
+{
+ const std::vector<std::string>& args = msg.getArgs();
+ assert(args.size() >= 1);
+ if(args.at(0) == "initiateIChatCall")
+ {
+ handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::onNewIPCMsg - initiateIChatCall");
+ assert(args.size() == 4);
+ initiateIChatCall(args.at(1).c_str(), args.at(2).c_str(), atoi(args.at(3).c_str()), false /* TODO - make setting? */);
+ }
+ else if(args.at(0) == "cancelIChatCall")
+ {
+ handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::onNewIPCMsg - cancelIChatCall");
+ assert(args.size() == 3);
+ cancelIChatCall(args.at(1).c_str(), args.at(2).c_str());
+ }
+ else if(args.at(0) == "proceedingIChatCall")
+ {
+ handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::onNewIPCMsg - proceedingIChatCall");
+ assert(args.size() == 4);
+ proceedingIChatCall(args.at(1).c_str(), args.at(2).c_str(), atoi(args.at(3).c_str()));
+ }
+ else if(args.at(0) == "acceptIChatCall")
+ {
+ handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::onNewIPCMsg - acceptIChatCall");
+ assert(args.size() == 3);
+ acceptIChatCall(args.at(1).c_str(), args.at(2).c_str());
+ }
+ else if(args.at(0) == "rejectIChatCall")
+ {
+ handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::onNewIPCMsg - rejectIChatCall");
+ assert(args.size() == 3);
+ rejectIChatCall(args.at(1).c_str(), args.at(2).c_str());
+ }
+ else if(args.at(0) == "sendSubscriptionResponse")
+ {
+ handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::onNewIPCMsg - sendSubscriptionResponse");
+ assert(args.size() == 4);
+ sendSubscriptionResponse(args.at(1).c_str(), args.at(2).c_str(), atoi(args.at(3).c_str()) != 0);
+ }
+ else
+ {
+ assert(false);
+ }
+}
+
+void
+JabberComponent::handleLog(LogLevel level, LogArea area, const std::string& message)
+{
+ IPCMsg msg;
+ msg.addArg("log");
+
+ switch(level)
+ {
+ case LogLevelWarning: /**< Non-crititcal warning messages. */
+ msg.addArg("warning");
+ break;
+ case LogLevelError: /**< Critical, unrecoverable errors. */
+ msg.addArg("error");
+ break;
+ case LogLevelDebug: /**< Debug messages. */
+ default:
+ msg.addArg("info");
+ break;
+ }
+ msg.addArg(message.c_str());
+ mIPCThread.sendIPCMsg(msg);
+}
+
+void
+JabberComponent::onConnect()
+{
+ // connection established, auth done (see API docs for exceptions)
+ handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::onConnect");
+
+ // Get persisent User subscriptions - and send on-line message
+ const JabberUserDb::UserMap& users = mUserDb.getUserSubscriptions();
+ JabberUserDb::UserMap::const_iterator it = users.begin();
+ for(;it!=users.end();it++)
+ {
+ probePresence(it->first.c_str()); // Probe for users presence
+ JabberUserDb::SubscribeSet::const_iterator it2 = it->second.begin();
+ for(;it2!=it->second.end();it2++)
+ {
+ sendPresence(it->first.c_str(), it2->c_str(), it2->c_str() != mControlJID /* advertise iChat audio support */, true /* available */);
+ storeIChatSubscribedUser(it->first.c_str(), it2->c_str());
+ }
+ }
+}
+
+
+void
+JabberComponent::onDisconnect(ConnectionError e)
+{
+ // connection established, auth done (see API docs for exceptions)
+ std::ostringstream oss;
+ oss << "JabberComponent::onDisconnect - error=" << e;
+ if(mStopping)
+ {
+ handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, oss.str());
+ }
+ else
+ {
+ handleLog(gloox::LogLevelWarning, gloox::LogAreaUser, oss.str());
+ }
+}
+
+bool
+JabberComponent::onTLSConnect(const CertInfo& info)
+{
+ // Note: currently gloox components to not support TLS connections
+
+ // examine certificate info
+ handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::onTLSConnect");
+ return true;
+}
+
+void
+JabberComponent::handleSubscription( Stanza *stanza )
+{
+ switch( stanza->subtype() )
+ {
+ case StanzaS10nSubscribe:
+ {
+ handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::handleSubscription - StanzaS10nSubscribe");
+ if(stanza->to().full() == mControlJID)
+ {
+ sendSubscriptionResponse(stanza->from().bare(), stanza->to().full(), true);
+ }
+ else
+ {
+ checkSubscription(stanza->to().full(), stanza->from().bare());
+ }
+ break;
+ }
+ case StanzaS10nUnsubscribe:
+ {
+ handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::handleSubscription - StanzaS10nUnsubscribe");
+ Tag *p = new Tag( "presence" );
+ p->addAttribute( "type", "unsubscribed" );
+ p->addAttribute( "to", stanza->from().bare() );
+ p->addAttribute( "from", stanza->to().full() );
+ mComponent->send( p );
+
+ mUserDb.removeSubscribedJID(stanza->from().bare().c_str(), stanza->to().bare().c_str());
+ removeIChatSubscribedUser(stanza->from().bare(), stanza->to().bare());
+
+ break;
+ }
+ default:
+ {
+ handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::handleSubscription - subtype=" + stanza->subtype());
+ break;
+ }
+ }
+}
+
+void
+JabberComponent::handlePresence(Stanza *stanza)
+{
+ bool iChatResource = false;
+ bool avAvail=false;
+
+ // Check if iChat endpoint
+ Tag* c = stanza->findChild("c");
+ if(c)
+ {
+ std::string node = c->findAttribute("node");
+ if(node == "apple:ichat:caps" ||
+ node == "http://www.apple.com/ichat/caps")
+ {
+ iChatResource = true;
+
+ // Check if caps include AV Available capability (note: if iChat is already on a call then it does not have avavail capability - since iChat only allows one call at a time)
+ std::string ext = c->findAttribute("ext");
+ if(ext.find("avavail") != std::string::npos)
+ {
+ avAvail = true;
+ }
+ }
+ }
+
+ // presence info
+ switch(stanza->subtype())
+ {
+ case StanzaPresenceProbe:
+ // A request for an entity's current presence
+ handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::handlePresence - Probe from " + stanza->from().full());
+ sendPresenceForRequest(stanza);
+ break;
+
+ case StanzaPresenceAvailable:
+ // Signals to the server that the sender is online and available for communication.
+
+ if(iChatResource)
+ {
+ handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::handlePresence - PresenceAvailable from " + stanza->from().full());
+ // Ensure we are tracking client
+ storeIChatPresence(stanza->from(), stanza->presence(), stanza->priority(), avAvail);
+
+ // Check if we have an outstanding iChat Call request
+ if(avAvail)
+ {
+ mOutstandingClientIChatCallRequestsMutex.lock();
+ IChatCallRequestMap::iterator it = mOutstandingClientIChatCallRequests.begin();
+ bool callRequestFound = false;
+ while(it != mOutstandingClientIChatCallRequests.end())
+ {
+ if(it->second.mTo == stanza->from().bare())
+ {
+ callRequestFound = true;
+ handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::handlePresence - Available for " + stanza->from().full() + " - outstanding iChat call request - continuing call");
+
+ it->second.sendIChatVCRequest(stanza->from().full());
+ }
+ it++;
+ }
+ mOutstandingClientIChatCallRequestsMutex.unlock();
+ }
+ }
+ break;
+
+ case StanzaPresenceUnavailable:
+ // Signals that the entity is no longer available for communication.
+ handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::handlePresence - Unavailable for " + stanza->from().full());
+
+ // Ensure we are tracking client
+ storeIChatPresence(stanza->from(), stanza->presence(), stanza->priority(), avAvail);
+
+ // Check if we have an outstanding iChat Call request to fail
+ failOutstandingClientIChatCallRequest(stanza->from().bare(), 404);
+ break;
+
+ case StanzaPresenceError:
+ handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::handlePresence - Error for " + stanza->from().full());
+
+ {
+ unsigned int code = 0;
+ Tag *error = stanza->findChild( "error" );
+ if(error)
+ {
+ code = atoi(error->findAttribute("code").c_str());
+ }
+
+ // Check if we have an outstanding iChat Call request to fail
+ failOutstandingClientIChatCallRequest(stanza->from().bare(), code);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void
+JabberComponent::handleMessage(Stanza* stanza, MessageSession* session)
+{
+ std::ostringstream oss;
+ oss << "JabberComponent::handlePresence - " << *stanza;
+ handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, oss.str());
+ Stanza *s = Stanza::createMessageStanza(stanza->from().full(), "You have reached the ichat gateway!" );
+ s->addAttribute("from", stanza->to().full());
+
+ mComponent->send( s );
+}
+
+bool
+JabberComponent::handleIq(Stanza *stanza)
+{
+ if(stanza->subtype() == StanzaIqSet && stanza->xmlns() == "apple:iq:vc:request")
+ {
+ handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "Jabber::handleIq - apple:iq:vc:request from=" + stanza->from().full() + ", to=" + stanza->to().full());
+ Tag::TagList tlist = stanza->children();
+ Tag* query = stanza->findChild("query");
+ Tag* vcNewCallerIPPortDataTag;
+ if(query)
+ {
+ vcNewCallerIPPortDataTag = query->findChild("VCNewCallerIPPortData");
+ if(vcNewCallerIPPortDataTag)
+ {
+ std::ostringstream oss;
+ oss << "Jabber::handleIq: vc:request, VCNewCallerIPPortData=" << vcNewCallerIPPortDataTag->cdata() << " size=" << vcNewCallerIPPortDataTag->cdata().size();
+ handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, oss.str());
+ }
+ Tag* extSIPPort = query->findChild("extSIPPort");
+ if(extSIPPort)
+ {
+ handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "Jabber::handleIq - apple:iq:vc:request extSIPPort=" + extSIPPort->cdata());
+ }
+ Tag* extIPAddr = query->findChild("extIPAddr");
+ if(extIPAddr)
+ {
+ handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "Jabber::handleIq - apple:iq:vc:request extIPAddr=" + extIPAddr->cdata());
+ }
+ Tag* vcProtocolVersion = query->findChild("VCProtocolVersion");
+ if(vcProtocolVersion)
+ {
+ handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "Jabber::handleIq - apple:iq:vc:request VCProtocolVersion=" + vcProtocolVersion->cdata());
+ }
+ }
+
+ // Create entry in outstanding server requests map
+ std::string key = makeVCRequestKey(stanza->to().bare(),stanza->from().bare());
+ mOutstandingServerIChatCallRequestsMutex.lock();
+ IChatCallRequest* iChatCallRequest = &(mOutstandingServerIChatCallRequests[key] = IChatCallRequest(this, stanza->to().bare(), stanza->from().full(), 0));
+ mOutstandingServerIChatCallRequestsMutex.unlock();
+
+ // Pass request to SIP side
+ notifyIChatCallRequest(stanza->to().bare(), stanza->from().bare());
+ }
+ else if(stanza->subtype() == StanzaIqSet && stanza->xmlns() == "apple:iq:vc:counterProposal")
+ {
+ handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "Jabber::handleIq - apple:iq:vc:counterProposal from=" + stanza->from().full() + ", to=" + stanza->to().full());
+
+ // Build response - Do we even need to respond???
+ {
+ Tag *iq = new Tag( "iq" );
+ iq->addAttribute( "type", "set" );
+ iq->addAttribute( "id", mComponent->getID() );
+ iq->addAttribute( "to", stanza->from().full() );
+ iq->addAttribute( "from", stanza->to().full() );
+ Tag *query = new Tag( iq, "query" );
+ query->addAttribute( "xmlns", "apple:iq:vc:counterProposal");
+ new Tag( query, "connectData", mLocalIChatPortListBlob);
+ new Tag( query, "VCProtocolVersion", "1" );
+ mComponent->send(iq);
+ }
+ }
+ else if(stanza->subtype() == StanzaIqSet && stanza->xmlns() == "apple:iq:vc:cancel")
+ {
+ handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "Jabber::handleIq - apple:iq:vc:cancel from=" + stanza->from().full() + ", to=" + stanza->to().full());
+ cancelOutstandingServerIChatCallRequest(stanza->to().bare(), stanza->from().bare());
+ }
+ else if(stanza->subtype() == StanzaIqSet && stanza->xmlns() == "apple:iq:vc:response")
+ {
+ handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "Jabber::handleIq - apple:iq:vc:response from=" + stanza->from().full() + ", to=" + stanza->to().full());
+ Tag::TagList tlist = stanza->children();
+ Tag* query = stanza->findChild("query");
+ Tag* vcNewCallerIPPortDataTag;
+ if(query)
+ {
+ vcNewCallerIPPortDataTag = query->findChild("connectData");
+ if(vcNewCallerIPPortDataTag)
+ {
+ mOutstandingClientIChatCallRequestsMutex.lock();
+
+ std::ostringstream oss;
+ oss << "Jabber::handleIq - connectData=" << vcNewCallerIPPortDataTag->cdata() << " size=" << vcNewCallerIPPortDataTag->cdata().size();
+ handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, oss.str());
+
+ IChatCallRequestMap::iterator it = findOutstandingClientIChatCallRequest(stanza->from().bare(), stanza->to().bare());
+ if(it!=mOutstandingClientIChatCallRequests.end())
+ {
+ handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "Jabber::handleIq - apple:iq:vc:response received - continuing SIP portion of call...");
+ it->second.receivedIChatVCResponse(stanza->from().full());
+ continueIChatCall(it->second.mB2BSessionHandle, vcNewCallerIPPortDataTag->cdata());
+ mOutstandingClientIChatCallRequests.erase(it);
+ }
+ mOutstandingClientIChatCallRequestsMutex.unlock();
+ }
+ }
+ }
+ else if(stanza->subtype() == StanzaIqError && stanza->xmlns() == "apple:iq:vc:request")
+ {
+ unsigned int code = 0;
+ Tag *error = stanza->findChild( "error" );
+ if(error)
+ {
+ code = atoi(error->findAttribute("code").c_str());
+ }
+
+ failOutstandingClientIChatCallRequest(stanza->from().bare(), stanza->to().bare(), code);
+ handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "Jabber::handleIq - apple:iq:vc:request error received - notifying SIP portion of call...");
+ }
+ else
+ {
+ std::ostringstream oss;
+ oss << "Jabber::handleIq - " << *stanza;
+ handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, oss.str());
+ }
+ return true;
+}
+
+bool
+JabberComponent::handleIqID(Stanza *stanza, int context)
+{
+ std::ostringstream oss;
+ oss << "Jabber::handleIqID - context=" << context;
+ handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, oss.str());
+ return false;
+}
+
+StringList
+JabberComponent::handleDiscoNodeFeatures(const std::string& node)
+{
+ handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::handleDiscoNodeFeatures - node=" + node);
+ StringList slist;
+ if(node == "apple:ichat:caps#avavail")
+ {
+ slist.push_back("apple:iq:vc:available");
+ }
+ else if(node == "apple:ichat:caps#audio")
+ {
+ slist.push_back("apple:iq:vc:audio");
+ }
+ else if(node == "apple:ichat:caps#avcap")
+ {
+ slist.push_back("apple:iq:vc:capable");
+ }
+ else if(node == "apple:ichat:caps#448")
+ {
+ slist.push_back("jabber:iq:version");
+ }
+ return slist;
+}
+
+StringMap
+JabberComponent::handleDiscoNodeIdentities(const std::string& node, std::string& name)
+{
+ handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::handleDiscoNodeIdentities - node=" + node + ", name=" + name);
+ StringMap smap;
+ smap["client"] = "pc";
+ return smap;
+}
+
+DiscoNodeItemList
+JabberComponent::handleDiscoNodeItems(const std::string& node)
+{
+ handleLog(gloox::LogLevelDebug, gloox::LogAreaUser, "JabberComponent::handleDiscoNodeItems - node=" + node);
+ DiscoNodeItemList dlist;
+ return dlist;
+}
+
+
+/* ====================================================================
+
+ 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.
+
+ ==================================================================== */
+
diff --git a/apps/ichat-gw/jabberconnector/JabberComponent.hxx b/apps/ichat-gw/jabberconnector/JabberComponent.hxx
new file mode 100644
index 0000000..cfc47e2
--- /dev/null
+++ b/apps/ichat-gw/jabberconnector/JabberComponent.hxx
@@ -0,0 +1,215 @@
+#if !defined(JabberComponent_hxx)
+#define JabberComponent_hxx
+
+#include "JabberUserDb.hxx"
+#include "../IPCThread.hxx"
+
+#include <string>
+#include <map>
+#include <set>
+#include <list>
+
+#ifdef WIN32
+#define RESIP_CONTRIB_GLOOX
+#endif
+
+// Gloox includes
+#ifndef RESIP_CONTRIB_GLOOX
+#include <gloox/component.h>
+#include <gloox/mutex.h>
+#include <gloox/messagehandler.h>
+#include <gloox/presencehandler.h>
+#include <gloox/loghandler.h>
+#include <gloox/rostermanager.h>
+#include <gloox/connectionlistener.h>
+#include <gloox/stanzaextension.h>
+#include <gloox/iqhandler.h>
+#include <gloox/disco.h>
+#include <gloox/disconodehandler.h>
+#include <gloox/subscriptionhandler.h>
+#else
+#include <src/component.h>
+#include <src/mutex.h>
+#include <src/messagehandler.h>
+#include <src/presencehandler.h>
+#include <src/loghandler.h>
+#include <src/rostermanager.h>
+#include <src/connectionlistener.h>
+#include <src/stanzaextension.h>
+#include <src/iqhandler.h>
+#include <src/disco.h>
+#include <src/disconodehandler.h>
+#include <src/subscriptionhandler.h>
+#endif
+
+namespace gateway
+{
+
+class JabberComponent;
+class IChatUser;
+
+class IChatCallRequest
+{
+public:
+ IChatCallRequest() : mJabberComponent(0), mB2BSessionHandle(0), mCancelled(false) {}
+ IChatCallRequest(JabberComponent* jabberComponent, const std::string& to, const std::string& from, unsigned int handle) :
+ mJabberComponent(jabberComponent), mTo(to), mFrom(from), mB2BSessionHandle(handle), mCancelled(false) {}
+
+ // Client Methods
+ void sendIChatVCRequest(const std::string& fullTo);
+ void sendIChatVCCancelToAll();
+ void receivedIChatVCResponse(const std::string& from);
+
+ // Server Methods
+ void sendIChatVCResponse(bool accept);
+
+ JabberComponent* mJabberComponent;
+
+ std::string mTo;
+ std::string mFrom;
+ unsigned int mB2BSessionHandle;
+ bool mCancelled;
+ std::set<std::string> mPendingVCRequestSet;
+};
+
+class JabberComponent : public Thread,
+ IPCHandler,
+ gloox::ConnectionListener,
+ gloox::PresenceHandler,
+ gloox::MessageHandler,
+ gloox::LogHandler,
+ gloox::DiscoNodeHandler,
+ gloox::IqHandler,
+ gloox::SubscriptionHandler
+{
+public:
+ JabberComponent(unsigned short jabberConnectorIPCPort,
+ unsigned short gatewayIPCPort,
+ const std::string& server,
+ const std::string& component,
+ const std::string& password,
+ int port,
+ unsigned int serverPingDuration,
+ const std::string& controlUser,
+ const std::string& localIChatPortListBlob);
+ ~JabberComponent();
+
+ void stop();
+ void disconnect();
+
+ // Client Methods
+ void initiateIChatCall(const std::string& to, const std::string& from, unsigned int handle, bool alertOneOnly=true);
+ void cancelIChatCall(const std::string& to, const std::string& from);
+
+ // Server Methods
+ void proceedingIChatCall(const std::string& to, const std::string& from, unsigned int handle);
+ void acceptIChatCall(const std::string& to, const std::string& from);
+ void rejectIChatCall(const std::string& to, const std::string& from);
+
+private:
+ void probePresence(const std::string& to);
+ void sendPresenceForRequest(gloox::Stanza* stanza);
+ void sendPresence(const std::string& to, const std::string& from, bool advertiseIChatSupport, bool available);
+ void sendSubscriptionResponse(const std::string& to, const std::string& from, bool success);
+
+ // Interfaces to send IPC messages
+ friend class IChatUser;
+ void notifyIChatCallRequest(const std::string& to, const std::string& from);
+ void notifyIChatCallCancelled(unsigned int handle);
+ void notifyIChatCallProceeding(unsigned int handle, const std::string& to);
+ void notifyIChatCallFailed(unsigned int handle, unsigned int statusCode);
+ void continueIChatCall(unsigned int, const std::string& remoteIPPortListBlob);
+ void sipRegisterJabberUser(const std::string& jidToRegister);
+ void sipUnregisterJabberUser(const std::string& jidToUnregister);
+ void checkSubscription(const std::string& to, const std::string& from);
+
+ // Handlers
+ virtual void onNewIPCMsg(const IPCMsg& msg);
+ virtual void handleLog(gloox::LogLevel level, gloox::LogArea area, const std::string& message);
+ virtual void onConnect();
+ virtual void onDisconnect(gloox::ConnectionError e);
+ virtual bool onTLSConnect(const gloox::CertInfo& info);
+ virtual void handleSubscription(gloox::Stanza *stanza);
+ virtual void handlePresence(gloox::Stanza *stanza);
+ virtual void handleMessage(gloox::Stanza* stanza, gloox::MessageSession* session = 0);
+ virtual bool handleIq(gloox::Stanza *stanza);
+ virtual bool handleIqID(gloox::Stanza *stanza, int context);
+ virtual gloox::StringList handleDiscoNodeFeatures(const std::string& node);
+ virtual gloox::StringMap handleDiscoNodeIdentities(const std::string& node, std::string& name);
+ virtual gloox::DiscoNodeItemList handleDiscoNodeItems(const std::string& node);
+
+ virtual void thread();
+
+ gloox::Component* mComponent;
+ bool mStopping;
+ unsigned int mServerPingDuration;
+ std::string mControlJID;
+ std::string mLocalIChatPortListBlob;
+
+ // Outstanding IChat call request maps
+ typedef std::map<std::string, IChatCallRequest> IChatCallRequestMap;
+ friend class IChatCallRequest;
+ std::string makeVCRequestKey(const std::string& bareTo, const std::string& bareFrom);
+
+ IChatCallRequestMap mOutstandingClientIChatCallRequests;
+ gloox::Mutex mOutstandingClientIChatCallRequestsMutex;
+ IChatCallRequestMap::iterator findOutstandingClientIChatCallRequest(const std::string& bareTo, const std::string& bareFrom);
+ void failOutstandingClientIChatCallRequest(const std::string& bareTo, const std::string& bareFrom, unsigned int code);
+ void failOutstandingClientIChatCallRequest(const std::string& bareTo, unsigned int code);
+
+ IChatCallRequestMap mOutstandingServerIChatCallRequests;
+ gloox::Mutex mOutstandingServerIChatCallRequestsMutex;
+ IChatCallRequestMap::iterator findOutstandingServerIChatCallRequest(const std::string& bareTo, const std::string& bareFrom);
+ void cancelOutstandingServerIChatCallRequest(const std::string& bareTo, const std::string& bareFrom);
+
+ gloox::Mutex mIChatUserMutex;
+ typedef std::map<std::string, IChatUser*> IChatUserMap;
+ IChatUserMap mIChatUsers;
+ void storeIChatSubscribedUser(const std::string& user, const std::string& subscribedJID);
+ void removeIChatSubscribedUser(const std::string& user, const std::string& subscribedJID);
+ void storeIChatPresence(const gloox::JID& jid, const gloox::Presence& presence, int priority, bool avAvail);
+ bool getMostAvailableIChatUserFullJID(const gloox::JID& jid, std::string& fullJID);
+ bool getMostAvailableIChatUserFullJIDList(const gloox::JID& jid, std::list<std::string>& fullJIDList);
+
+ JabberUserDb mUserDb;
+ IPCThread mIPCThread;
+};
+
+}
+#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.
+
+ ==================================================================== */
+
diff --git a/apps/ichat-gw/jabberconnector/JabberUserDb.cxx b/apps/ichat-gw/jabberconnector/JabberUserDb.cxx
new file mode 100644
index 0000000..b83fc0c
--- /dev/null
+++ b/apps/ichat-gw/jabberconnector/JabberUserDb.cxx
@@ -0,0 +1,168 @@
+#include "JabberUserDb.hxx"
+
+#include <iostream>
+#include <fstream>
+#include <iterator>
+
+using namespace gateway;
+using namespace std;
+
+namespace gateway
+{
+
+JabberUserDb::JabberUserDb()
+ : mDbFilename("ichat-gw.userdb")
+{
+ parseDbFile(mDbFilename);
+}
+
+JabberUserDb::~JabberUserDb()
+{
+}
+
+void
+JabberUserDb::addSubscribedJID(const std::string& user, const std::string& subscribedJID)
+{
+ mUsers[user].insert(subscribedJID);
+ writeDbFile(mDbFilename);
+}
+
+void
+JabberUserDb::removeSubscribedJID(const std::string& user, const std::string& subscribedJID)
+{
+ bool found = false;
+ UserMap::iterator it = mUsers.find(user);
+ if(it!=mUsers.end())
+ {
+ SubscribeSet::iterator it2 = it->second.find(subscribedJID);
+ if(it2!=it->second.end())
+ {
+ found = true;
+ it->second.erase(it2);
+ }
+ // Remove user entirely if no subscriptions left
+ if(it->second.size() == 0)
+ {
+ mUsers.erase(it);
+ }
+ }
+ if(found)
+ {
+ writeDbFile(mDbFilename);
+ }
+}
+
+void
+JabberUserDb::parseDbFile(const std::string& filename)
+{
+ ifstream dbFile(filename.c_str());
+ string lastUser;
+ string sline;
+
+ // Get first line and ensure version is present
+ if(getline(dbFile, sline))
+ {
+ if(sline != "v1") // For now we just read version 1 format
+ {
+ cerr << "JabberUserDb::parseDbFile: invalid first line in file, expecting version line!" << endl;
+ return;
+ }
+ }
+ else
+ {
+ cerr << "JabberUserDb::parseDbFile: invalid first line in file, expecting version line!" << endl;
+ return;
+ }
+ while(getline(dbFile, sline))
+ {
+ if(sline.size() > 1 &&
+ sline.at(0) == '\t' &&
+ !lastUser.empty())
+ {
+ // This should be a local subscription JID
+ mUsers[lastUser].insert(sline.substr(1));
+ //cout << "'" << lastUser << "': '" << sline.substr(1) << "'" << endl;
+ }
+ else
+ {
+ // This should be a user
+ lastUser = sline;
+ }
+ }
+}
+
+void
+JabberUserDb::writeDbFile(const std::string& filename)
+{
+ std::string tempfilename = filename + ".tmp";
+
+ // safewrite - write to a temp file, delete original, then move temp file
+ ofstream dbFile(tempfilename.c_str(), std::ios_base::out | std::ios_base::trunc);
+ if(dbFile.is_open())
+ {
+ dbFile << "v1\n";
+ UserMap::iterator it = mUsers.begin();
+ for(;it!=mUsers.end();it++)
+ {
+ dbFile << it->first << "\n";
+ SubscribeSet::iterator it2 = it->second.begin();
+ for(;it2!=it->second.end();it2++)
+ {
+ dbFile << "\t" << *it2 << "\n";
+ }
+ }
+ dbFile.close();
+ if(remove(filename.c_str()) != 0)
+ {
+ cerr << "JabberUserDb::writeDbFile - error removing " << filename << " to update with new data." << endl;
+ }
+ else
+ {
+ if(rename(tempfilename.c_str(), filename.c_str()) != 0)
+ {
+ cerr << "JabberUserDb::writeDbFile - error renaming " << tempfilename << " to " << filename << " to update with new data." << endl;
+ }
+ }
+ }
+ else
+ {
+ cerr << "JabberUserDb::writeDbFile - error opening " << tempfilename << " for writing." << endl;
+ }
+}
+
+}
+
+/* ====================================================================
+
+ 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.
+
+ ==================================================================== */
+
diff --git a/apps/ichat-gw/IChatIPPortData.hxx b/apps/ichat-gw/jabberconnector/JabberUserDb.hxx
similarity index 73%
copy from apps/ichat-gw/IChatIPPortData.hxx
copy to apps/ichat-gw/jabberconnector/JabberUserDb.hxx
index e0bf887..d072733 100644
--- a/apps/ichat-gw/IChatIPPortData.hxx
+++ b/apps/ichat-gw/jabberconnector/JabberUserDb.hxx
@@ -1,34 +1,40 @@
-#if !defined(IChatIPPortData_hxx)
-#define IChatIPPortData_hxx
+#if !defined(JabberUserDb_hxx)
+#define JabberUserDb_hxx
#include <list>
+#include <map>
+#include <set>
#include <string>
-#include "rutil/Data.hxx"
-#include "resip/stack/Tuple.hxx"
-
namespace gateway
{
-class IChatIPPortData
+class JabberUserDb
{
public:
- typedef std::list<std::pair<resip::Data,resip::Tuple> > IPPortDataList;
-
- IChatIPPortData();
- IChatIPPortData(const std::string& hexblob);
+ JabberUserDb();
+ virtual ~JabberUserDb();
+
+ typedef std::set<std::string> SubscribeSet;
+ typedef std::map<std::string, SubscribeSet> UserMap;
- void addIPPortData(const resip::Data& name, const resip::Tuple& ipPortData);
- std::string& hexBlob();
- const IPPortDataList& getIPPortDataList() const;
+ const UserMap& getUserSubscriptions() const { return mUsers; }
+
+ void addSubscribedJID(const std::string& user, const std::string& subscribedJID);
+ void removeSubscribedJID(const std::string& user, const std::string& subscribedJID);
private:
- IPPortDataList mIPPortDataList;
- std::string mHexBlob;
-};
+ void parseDbFile(const std::string& filename);
+ void writeDbFile(const std::string& filename);
+ std::string mDbFilename;
+ UserMap mUsers;
+};
+
}
-#endif
+
+#endif
+
/* ====================================================================
diff --git a/reTurn/test/Makefile.am b/apps/ichat-gw/jabberconnector/Makefile.am
similarity index 77%
copy from reTurn/test/Makefile.am
copy to apps/ichat-gw/jabberconnector/Makefile.am
index 33986fa..8efd9b0 100644
--- a/reTurn/test/Makefile.am
+++ b/apps/ichat-gw/jabberconnector/Makefile.am
@@ -1,31 +1,33 @@
# $Id$
-EXTRA_DIST = stunTestVectors_10_0.vcxproj stunTestVectors_10_0.vcxproj.filters
-EXTRA_DIST += *.vcproj
+EXTRA_DIST = *.vcproj
-#AM_CXXFLAGS = -DUSE_ARES
+SUBDIRS = .
-LDADD = ../../rutil/librutil.la
-#LDADD += ../../contrib/ares/libares.a
-LDADD += $(LIBSSL_LIBADD) -lpthread
+#AM_CXXFLAGS = -DUSE_ARES
-#
-# This doesn't work because the Stun classes for reTurn are built
-# into a binary rather than a library.
-#
-# Strategy:
-# - take common classes for reTurn client and server, make a library for
-# out of them
-# - use the library for building the client and server
-# - use the library for building this test case again
-#
-#TESTS = \
-# stunTestVectors
+sbin_PROGRAMS = ichat-gw-jc
+ichat_gw_jc_LDADD = ../../../resip/dum/libdum.la
+ichat_gw_jc_LDADD += ../../../resip/stack/libresip.la
+ichat_gw_jc_LDADD += ../../../rutil/librutil.la
+ichat_gw_jc_LDADD += -lgloox
+ichat_gw_jc_LDADD += -lgnutls
+ichat_gw_jc_LDADD += -lidn
+ichat_gw_jc_LDADD += -lresolv
+ichat_gw_jc_LDADD += -lpthread
-#check_PROGRAMS = \
-# stunTestVectors
+ichat_gw_jc_SOURCES = \
+ ichat-gw-jc.cxx \
+ IChatUser.cxx \
+ ../IPCThread.cxx \
+ JabberComponent.cxx \
+ JabberUserDb.cxx \
+ ../Thread.cxx
-#stunTestVectors_SOURCES = stunTestVectors.cxx
+ichat_gw_jcincludedir = $(includedir)/ichat-gw-jc
+nobase_ichat_gw_jcinclude_HEADERS = IChatUser.hxx \
+ JabberComponent.hxx \
+ JabberUserDb.hxx
##############################################################################
#
diff --git a/apps/clicktocall/Makefile.in b/apps/ichat-gw/jabberconnector/Makefile.in
similarity index 79%
copy from apps/clicktocall/Makefile.in
copy to apps/ichat-gw/jabberconnector/Makefile.in
index 6c988ad..63119c6 100644
--- a/apps/clicktocall/Makefile.in
+++ b/apps/ichat-gw/jabberconnector/Makefile.in
@@ -37,15 +37,14 @@ PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
-sbin_PROGRAMS = clicktocall$(EXEEXT)
-subdir = apps/clicktocall
-DIST_COMMON = $(nobase_clicktocallinclude_HEADERS) \
+sbin_PROGRAMS = ichat-gw-jc$(EXEEXT)
+subdir = apps/ichat-gw/jabberconnector
+DIST_COMMON = $(nobase_ichat_gw_jcinclude_HEADERS) \
$(srcdir)/Makefile.am $(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/m4/ax_have_epoll.m4 \
- $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
- $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
- $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/acinclude.m4 \
+am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
@@ -54,17 +53,13 @@ CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
am__installdirs = "$(DESTDIR)$(sbindir)" \
- "$(DESTDIR)$(clicktocallincludedir)"
+ "$(DESTDIR)$(ichat_gw_jcincludedir)"
PROGRAMS = $(sbin_PROGRAMS)
-am_clicktocall_OBJECTS = AddressTranslator.$(OBJEXT) \
- AppSubsystem.$(OBJEXT) B2BSession.$(OBJEXT) \
- clicktocall.$(OBJEXT) ConfigParser.$(OBJEXT) \
- HttpBase.$(OBJEXT) HttpConnection.$(OBJEXT) Server.$(OBJEXT) \
- WebAdmin.$(OBJEXT) WebAdminThread.$(OBJEXT) \
- XmlRpcConnection.$(OBJEXT) XmlRpcServerBase.$(OBJEXT) \
- XmlRpcServer.$(OBJEXT) XmlRpcServerThread.$(OBJEXT)
-clicktocall_OBJECTS = $(am_clicktocall_OBJECTS)
-clicktocall_DEPENDENCIES = ../../resip/dum/libdum.la \
+am_ichat_gw_jc_OBJECTS = ichat-gw-jc.$(OBJEXT) IChatUser.$(OBJEXT) \
+ IPCThread.$(OBJEXT) JabberComponent.$(OBJEXT) \
+ JabberUserDb.$(OBJEXT) Thread.$(OBJEXT)
+ichat_gw_jc_OBJECTS = $(am_ichat_gw_jc_OBJECTS)
+ichat_gw_jc_DEPENDENCIES = ../../resip/dum/libdum.la \
../../resip/stack/libresip.la ../../rutil/librutil.la
DEFAULT_INCLUDES = -I. at am__isrc@ -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
@@ -79,8 +74,8 @@ CXXLD = $(CXX)
CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
--mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \
$(LDFLAGS) -o $@
-SOURCES = $(clicktocall_SOURCES)
-DIST_SOURCES = $(clicktocall_SOURCES)
+SOURCES = $(ichat_gw_jc_SOURCES)
+DIST_SOURCES = $(ichat_gw_jc_SOURCES)
RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
html-recursive info-recursive install-data-recursive \
install-dvi-recursive install-exec-recursive \
@@ -109,7 +104,7 @@ am__nobase_list = $(am__nobase_strip_setup); \
am__base_list = \
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
-HEADERS = $(nobase_clicktocallinclude_HEADERS)
+HEADERS = $(nobase_ichat_gw_jcinclude_HEADERS)
RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
distclean-recursive maintainer-clean-recursive
AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
@@ -181,11 +176,8 @@ INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LD = @LD@
LDFLAGS = @LDFLAGS@
-LIBARES_LIBADD = @LIBARES_LIBADD@
-LIBGEOIP_LIBADD = @LIBGEOIP_LIBADD@
LIBMYSQL_LIBADD = @LIBMYSQL_LIBADD@
LIBOBJS = @LIBOBJS@
-LIBPOPT_LIBADD = @LIBPOPT_LIBADD@
LIBRADIUS_LIBADD = @LIBRADIUS_LIBADD@
LIBS = @LIBS@
LIBSSL_LIBADD = @LIBSSL_LIBADD@
@@ -269,43 +261,23 @@ target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
-EXTRA_DIST = clicktocall.config doc *.sln *.vcproj
+EXTRA_DIST = *.vcproj
SUBDIRS = .
-clicktocall_LDADD = ../../resip/dum/libdum.la \
- ../../resip/stack/libresip.la ../../rutil/librutil.la \
- @LIBSSL_LIBADD@ -lpcre -lpthread
-clicktocall_SOURCES = \
- 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
-
-clicktocallincludedir = $(includedir)/clicktocall
-nobase_clicktocallinclude_HEADERS = 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
+ichat_gw_jc_LDADD = ../../resip/dum/libdum.la \
+ ../../resip/stack/libresip.la ../../rutil/librutil.la -lgloox \
+ -lgnutls -lidn -lresolv -lpthread
+ichat_gw_jc_SOURCES = \
+ ichat-gw-jc.cxx \
+ IChatUser.cxx \
+ ../IPCThread.cxx \
+ JabberComponent.cxx \
+ JabberUserDb.cxx \
+ ../Thread.cxx
+
+ichat_gw_jcincludedir = $(includedir)/ichat-gw-jc
+nobase_ichat_gw_jcinclude_HEADERS = IChatUser.hxx \
+ JabberComponent.hxx \
+ JabberUserDb.hxx
all: all-recursive
@@ -320,9 +292,9 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi
exit 1;; \
esac; \
done; \
- echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu apps/clicktocall/Makefile'; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu apps/ichat-gw/jabberconnector/Makefile'; \
$(am__cd) $(top_srcdir) && \
- $(AUTOMAKE) --gnu apps/clicktocall/Makefile
+ $(AUTOMAKE) --gnu apps/ichat-gw/jabberconnector/Makefile
.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
@@ -384,9 +356,9 @@ clean-sbinPROGRAMS:
list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
echo " rm -f" $$list; \
rm -f $$list
-clicktocall$(EXEEXT): $(clicktocall_OBJECTS) $(clicktocall_DEPENDENCIES)
- @rm -f clicktocall$(EXEEXT)
- $(CXXLINK) $(clicktocall_OBJECTS) $(clicktocall_LDADD) $(LIBS)
+ichat-gw-jc$(EXEEXT): $(ichat_gw_jc_OBJECTS) $(ichat_gw_jc_DEPENDENCIES)
+ @rm -f ichat-gw-jc$(EXEEXT)
+ $(CXXLINK) $(ichat_gw_jc_OBJECTS) $(ichat_gw_jc_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
@@ -394,20 +366,12 @@ mostlyclean-compile:
distclean-compile:
-rm -f *.tab.c
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/AddressTranslator.Po at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/AppSubsystem.Po at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/B2BSession.Po at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/ConfigParser.Po at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/HttpBase.Po at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/HttpConnection.Po at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/Server.Po at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/WebAdmin.Po at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/WebAdminThread.Po at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/XmlRpcConnection.Po at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/XmlRpcServer.Po at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/XmlRpcServerBase.Po at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/XmlRpcServerThread.Po at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/clicktocall.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/IChatUser.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/IPCThread.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/JabberComponent.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/JabberUserDb.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/Thread.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/ichat-gw-jc.Po at am__quote@
.cxx.o:
@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -430,34 +394,62 @@ distclean-compile:
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $<
+IPCThread.o: ../IPCThread.cxx
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT IPCThread.o -MD -MP -MF $(DEPDIR)/IPCThread.Tpo -c -o IPCThread.o `test -f '../IPCThread.cxx' || echo '$(srcdir)/'`../IPCThread.cxx
+ at am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/IPCThread.Tpo $(DEPDIR)/IPCThread.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../IPCThread.cxx' object='IPCThread.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o IPCThread.o `test -f '../IPCThread.cxx' || echo '$(srcdir)/'`../IPCThread.cxx
+
+IPCThread.obj: ../IPCThread.cxx
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT IPCThread.obj -MD -MP -MF $(DEPDIR)/IPCThread.Tpo -c -o IPCThread.obj `if test -f '../IPCThread.cxx'; then $(CYGPATH_W) '../IPCThread.cxx'; else $(CYGPATH_W) '$(srcdir)/../IPCThread.cxx'; fi`
+ at am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/IPCThread.Tpo $(DEPDIR)/IPCThread.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../IPCThread.cxx' object='IPCThread.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o IPCThread.obj `if test -f '../IPCThread.cxx'; then $(CYGPATH_W) '../IPCThread.cxx'; else $(CYGPATH_W) '$(srcdir)/../IPCThread.cxx'; fi`
+
+Thread.o: ../Thread.cxx
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT Thread.o -MD -MP -MF $(DEPDIR)/Thread.Tpo -c -o Thread.o `test -f '../Thread.cxx' || echo '$(srcdir)/'`../Thread.cxx
+ at am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/Thread.Tpo $(DEPDIR)/Thread.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../Thread.cxx' object='Thread.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o Thread.o `test -f '../Thread.cxx' || echo '$(srcdir)/'`../Thread.cxx
+
+Thread.obj: ../Thread.cxx
+ at am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT Thread.obj -MD -MP -MF $(DEPDIR)/Thread.Tpo -c -o Thread.obj `if test -f '../Thread.cxx'; then $(CYGPATH_W) '../Thread.cxx'; else $(CYGPATH_W) '$(srcdir)/../Thread.cxx'; fi`
+ at am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/Thread.Tpo $(DEPDIR)/Thread.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../Thread.cxx' object='Thread.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o Thread.obj `if test -f '../Thread.cxx'; then $(CYGPATH_W) '../Thread.cxx'; else $(CYGPATH_W) '$(srcdir)/../Thread.cxx'; fi`
+
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
-install-nobase_clicktocallincludeHEADERS: $(nobase_clicktocallinclude_HEADERS)
+install-nobase_ichat_gw_jcincludeHEADERS: $(nobase_ichat_gw_jcinclude_HEADERS)
@$(NORMAL_INSTALL)
- test -z "$(clicktocallincludedir)" || $(MKDIR_P) "$(DESTDIR)$(clicktocallincludedir)"
- @list='$(nobase_clicktocallinclude_HEADERS)'; test -n "$(clicktocallincludedir)" || list=; \
+ test -z "$(ichat_gw_jcincludedir)" || $(MKDIR_P) "$(DESTDIR)$(ichat_gw_jcincludedir)"
+ @list='$(nobase_ichat_gw_jcinclude_HEADERS)'; test -n "$(ichat_gw_jcincludedir)" || list=; \
$(am__nobase_list) | while read dir files; do \
xfiles=; for file in $$files; do \
if test -f "$$file"; then xfiles="$$xfiles $$file"; \
else xfiles="$$xfiles $(srcdir)/$$file"; fi; done; \
test -z "$$xfiles" || { \
test "x$$dir" = x. || { \
- echo "$(MKDIR_P) '$(DESTDIR)$(clicktocallincludedir)/$$dir'"; \
- $(MKDIR_P) "$(DESTDIR)$(clicktocallincludedir)/$$dir"; }; \
- echo " $(INSTALL_HEADER) $$xfiles '$(DESTDIR)$(clicktocallincludedir)/$$dir'"; \
- $(INSTALL_HEADER) $$xfiles "$(DESTDIR)$(clicktocallincludedir)/$$dir" || exit $$?; }; \
+ echo "$(MKDIR_P) '$(DESTDIR)$(ichat_gw_jcincludedir)/$$dir'"; \
+ $(MKDIR_P) "$(DESTDIR)$(ichat_gw_jcincludedir)/$$dir"; }; \
+ echo " $(INSTALL_HEADER) $$xfiles '$(DESTDIR)$(ichat_gw_jcincludedir)/$$dir'"; \
+ $(INSTALL_HEADER) $$xfiles "$(DESTDIR)$(ichat_gw_jcincludedir)/$$dir" || exit $$?; }; \
done
-uninstall-nobase_clicktocallincludeHEADERS:
+uninstall-nobase_ichat_gw_jcincludeHEADERS:
@$(NORMAL_UNINSTALL)
- @list='$(nobase_clicktocallinclude_HEADERS)'; test -n "$(clicktocallincludedir)" || list=; \
+ @list='$(nobase_ichat_gw_jcinclude_HEADERS)'; test -n "$(ichat_gw_jcincludedir)" || list=; \
$(am__nobase_strip_setup); files=`$(am__nobase_strip)`; \
test -n "$$files" || exit 0; \
- echo " ( cd '$(DESTDIR)$(clicktocallincludedir)' && rm -f" $$files ")"; \
- cd "$(DESTDIR)$(clicktocallincludedir)" && rm -f $$files
+ echo " ( cd '$(DESTDIR)$(ichat_gw_jcincludedir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(ichat_gw_jcincludedir)" && rm -f $$files
# This directory's subdirectories are mostly independent; you can cd
# into them and run `make' without going through this Makefile.
@@ -657,7 +649,7 @@ check: check-recursive
all-am: Makefile $(PROGRAMS) $(HEADERS)
installdirs: installdirs-recursive
installdirs-am:
- for dir in "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(clicktocallincludedir)"; do \
+ for dir in "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(ichat_gw_jcincludedir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-recursive
@@ -708,7 +700,7 @@ info: info-recursive
info-am:
-install-data-am: install-nobase_clicktocallincludeHEADERS
+install-data-am: install-nobase_ichat_gw_jcincludeHEADERS
install-dvi: install-dvi-recursive
@@ -754,7 +746,7 @@ ps: ps-recursive
ps-am:
-uninstall-am: uninstall-nobase_clicktocallincludeHEADERS \
+uninstall-am: uninstall-nobase_ichat_gw_jcincludeHEADERS \
uninstall-sbinPROGRAMS
.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \
@@ -768,14 +760,14 @@ uninstall-am: uninstall-nobase_clicktocallincludeHEADERS \
install install-am install-data install-data-am install-dvi \
install-dvi-am install-exec install-exec-am install-html \
install-html-am install-info install-info-am install-man \
- install-nobase_clicktocallincludeHEADERS install-pdf \
+ install-nobase_ichat_gw_jcincludeHEADERS install-pdf \
install-pdf-am install-ps install-ps-am install-sbinPROGRAMS \
install-strip installcheck installcheck-am installdirs \
installdirs-am maintainer-clean maintainer-clean-generic \
mostlyclean mostlyclean-compile mostlyclean-generic \
mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \
uninstall uninstall-am \
- uninstall-nobase_clicktocallincludeHEADERS \
+ uninstall-nobase_ichat_gw_jcincludeHEADERS \
uninstall-sbinPROGRAMS
diff --git a/apps/ichat-gw/ichat-gw.cxx b/apps/ichat-gw/jabberconnector/ichat-gw-jc.cxx
similarity index 60%
copy from apps/ichat-gw/ichat-gw.cxx
copy to apps/ichat-gw/jabberconnector/ichat-gw-jc.cxx
index 9650e35..5aa54b4 100644
--- a/apps/ichat-gw/ichat-gw.cxx
+++ b/apps/ichat-gw/jabberconnector/ichat-gw-jc.cxx
@@ -1,21 +1,12 @@
#include <signal.h>
+#include <iostream>
+#include <assert.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>
+#include "JabberComponent.hxx"
using namespace gateway;
-using namespace resip;
using namespace std;
-#define RESIPROCATE_SUBSYSTEM AppSubsystem::GATEWAY
-
void sleepSeconds(unsigned int seconds)
{
#ifdef WIN32
@@ -25,13 +16,13 @@ void sleepSeconds(unsigned int seconds)
#endif
}
-static bool finished = false;
+JabberComponent* g_component;
static void
signalHandler(int signo)
{
- //std::cerr << "Shutting down..." << endl;
- finished = true;
+ //std::cerr << "Shutting down" << endl;
+ g_component->stop();
}
int
@@ -43,10 +34,6 @@ main (int argc, char** argv)
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 )
@@ -61,33 +48,50 @@ main (int argc, char** argv)
exit( -1 );
}
- initNetwork();
+ if(argc != 11 || std::string(argv[0]) != std::string("ichat-gw"))
+ {
+ cerr << "argc=" << argc << ", argv[0]=" << argv[0] << endl;
+ cerr << "Jabber connector process must not be launched manually, it is launched automatically from the main ichat-gw program." << endl;
+ exit(-1);
+ }
- //////////////////////////////////////////////////////////////////////////////
- // Create Server
- //////////////////////////////////////////////////////////////////////////////
+#if defined(WIN32)
+ WORD wVersionRequested = MAKEWORD( 2, 2 );
+ WSADATA wsaData;
+ int err = WSAStartup( wVersionRequested, &wsaData );
+ if ( err != 0 )
{
- Server server(argc, argv);
+ // could not find a usable WinSock DLL
+ cerr << "Could not load winsock" << endl;
+ assert(0);
+ exit(1);
+ }
+#endif
- //////////////////////////////////////////////////////////////////////////////
- // Startup and run...
- //////////////////////////////////////////////////////////////////////////////
+ unsigned int jabberConnectorIPCPort = atoi(argv[1]);
+ unsigned int gatewayIPCPort = atoi(argv[2]);
- server.startup();
+ g_component = new JabberComponent(jabberConnectorIPCPort,
+ gatewayIPCPort,
+ argv[3], // Jabber server
+ argv[4], // Jabber component name
+ argv[5], // Jabber component password
+ atoi(argv[6]), // Jabber component port
+ atoi(argv[7]), // Jabber server ping duration
+ argv[8], // Jabber control username
+ argv[9]); // IPPort Data blob
- while(true)
- {
- server.process(50);
- if(finished) break;
- }
- server.shutdown();
- }
+ g_component->run();
- InfoLog(<< "ichat-gw is shutdown.");
+ g_component->join();
+ delete g_component;
+
+ cout << "ichat-gw-jc is shutdown." << endl;
sleepSeconds(2);
}
+
/* ====================================================================
Copyright (c) 2009, SIP Spectrum, Inc.
diff --git a/apps/ichat-gw/ichat-gw_8_0.vcproj b/apps/ichat-gw/jabberconnector/jabberconnector_8_0.vcproj
similarity index 62%
copy from apps/ichat-gw/ichat-gw_8_0.vcproj
copy to apps/ichat-gw/jabberconnector/jabberconnector_8_0.vcproj
index 6993933..27e3376 100644
--- a/apps/ichat-gw/ichat-gw_8_0.vcproj
+++ b/apps/ichat-gw/jabberconnector/jabberconnector_8_0.vcproj
@@ -2,9 +2,9 @@
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
- Name="ichat-gw"
- ProjectGUID="{8BA87397-9B42-4820-BA53-62FF35C22CAD}"
- RootNamespace="ichatgw"
+ Name="jabberconnector"
+ ProjectGUID="{A77DCD34-20CA-4602-B185-EE3EAD97713D}"
+ RootNamespace="jabberconnector"
Keyword="Win32Proj"
>
<Platforms>
@@ -40,7 +40,7 @@
<Tool
Name="VCCLCompilerTool"
Optimization="0"
- AdditionalIncludeDirectories=""$(ProjectDir)../";"$(ProjectDir)../contrib/openssl/include";"$(ProjectDir)../contrib/openssl/inc32";"$(ProjectDir)../contrib/pcre""
+ AdditionalIncludeDirectories=""$(ProjectDir)../../";"$(ProjectDir)../../contrib/gloox""
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;USE_SSL;USE_IPV6"
MinimalRebuild="true"
BasicRuntimeChecks="3"
@@ -61,7 +61,8 @@
/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="Ws2_32.lib Dnsapi.lib Iphlpapi.lib crypt32.lib "$(ProjectDir)..\contrib\openssl\lib\vc\static\libeay32MDd.lib" "$(ProjectDir)..\contrib\openssl\lib\vc\static\ssleay32MDd.lib""
+ AdditionalDependencies="Ws2_32.lib Dnsapi.lib Iphlpapi.lib crypt32.lib "$(ProjectDir)..\..\contrib\openssl\lib\vc\static\libeay32MDd.lib" "$(ProjectDir)..\..\contrib\openssl\lib\vc\static\ssleay32MDd.lib""
+ OutputFile="$(OutDir)\ichat-gw-jc.exe"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
@@ -90,6 +91,7 @@
/>
<Tool
Name="VCPostBuildEventTool"
+ CommandLine="copy $(TargetPath) $(ProjectDir)..\"
/>
</Configuration>
<Configuration
@@ -117,7 +119,7 @@
/>
<Tool
Name="VCCLCompilerTool"
- AdditionalIncludeDirectories=""$(ProjectDir)../";"$(ProjectDir)../contrib/openssl/include";"$(ProjectDir)../contrib/openssl/inc32";"$(ProjectDir)../contrib/pcre""
+ AdditionalIncludeDirectories=""$(ProjectDir)../../";"$(ProjectDir)../../contrib/gloox""
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;USE_SSL;USE_IPV6"
RuntimeLibrary="2"
UsePrecompiledHeader="0"
@@ -136,7 +138,8 @@
/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="Ws2_32.lib Dnsapi.lib Iphlpapi.lib crypt32.lib "$(ProjectDir)..\contrib\openssl\lib\vc\static\libeay32MD.lib" "$(ProjectDir)..\contrib\openssl\lib\vc\static\ssleay32MD.lib""
+ AdditionalDependencies="Ws2_32.lib Dnsapi.lib Iphlpapi.lib crypt32.lib "$(ProjectDir)..\..\contrib\openssl\lib\vc\static\libeay32MD.lib" "$(ProjectDir)..\..\contrib\openssl\lib\vc\static\ssleay32MD.lib""
+ OutputFile="$(OutDir)\ichat-gw-jc.exe"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
@@ -167,6 +170,7 @@
/>
<Tool
Name="VCPostBuildEventTool"
+ CommandLine="copy $(TargetPath) $(ProjectDir)..\"
/>
</Configuration>
</Configurations>
@@ -179,51 +183,27 @@
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
- RelativePath=".\AddressTranslator.cxx"
+ RelativePath=".\ichat-gw-jc.cxx"
>
</File>
<File
- RelativePath=".\AppSubsystem.cxx"
+ RelativePath=".\IChatUser.cxx"
>
</File>
<File
- RelativePath=".\B2BSession.cxx"
+ RelativePath="..\IPCThread.cxx"
>
</File>
<File
- RelativePath=".\ConfigParser.cxx"
+ RelativePath=".\JabberComponent.cxx"
>
</File>
<File
- RelativePath=".\ichat-gw.cxx"
+ RelativePath=".\JabberUserDb.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"
+ RelativePath="..\Thread.cxx"
>
</File>
</Filter>
@@ -233,55 +213,23 @@
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"
+ RelativePath=".\IChatUser.hxx"
>
</File>
<File
- RelativePath=".\Server.hxx"
+ RelativePath="..\IPCThread.hxx"
>
</File>
<File
- RelativePath=".\SipRegistration.hxx"
+ RelativePath=".\JabberComponent.hxx"
>
</File>
<File
- RelativePath=".\Thread.hxx"
+ RelativePath=".\JabberUserDb.hxx"
>
</File>
<File
- RelativePath=".\Version.hxx"
+ RelativePath="..\Thread.hxx"
>
</File>
</Filter>
diff --git a/reTurn/test/stunTestVectors_9_0.vcproj b/apps/ichat-gw/jabberconnector/jabberconnector_9_0.vcproj
similarity index 62%
copy from reTurn/test/stunTestVectors_9_0.vcproj
copy to apps/ichat-gw/jabberconnector/jabberconnector_9_0.vcproj
index 683dced..281403b 100644
--- a/reTurn/test/stunTestVectors_9_0.vcproj
+++ b/apps/ichat-gw/jabberconnector/jabberconnector_9_0.vcproj
@@ -2,9 +2,9 @@
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
- Name="stunTestVectors"
- ProjectGUID="{73151749-13F0-4093-97F1-B6952ECECDCF}"
- RootNamespace="stunTestVectors"
+ Name="jabberconnector"
+ ProjectGUID="{A77DCD34-20CA-4602-B185-EE3EAD97713D}"
+ RootNamespace="jabberconnector"
Keyword="Win32Proj"
TargetFrameworkVersion="131072"
>
@@ -18,11 +18,10 @@
<Configurations>
<Configuration
Name="Debug|Win32"
- OutputDirectory="Debug"
- IntermediateDirectory="Debug"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
- CharacterSet="2"
+ CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
@@ -42,8 +41,8 @@
<Tool
Name="VCCLCompilerTool"
Optimization="0"
- AdditionalIncludeDirectories="../../contrib/asio;../../contrib/boost_1_34_1;../../;../../../contrib/OpenSSL/include;../../contrib/OpenSSL/inc32"
- PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;BOOST_ALL_NO_LIB;_WIN32_WINNT=0x0501;USE_SSL;LEAK_CHECK;ASIO_ENABLE_CANCELIO"
+ AdditionalIncludeDirectories=""$(ProjectDir)../../../";"$(ProjectDir)../../../contrib/gloox""
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;USE_SSL;USE_IPV6"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
@@ -63,11 +62,10 @@
/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="winmm.lib "$(ProjectDir)..\..\contrib\openssl\out32.dbg\libeay32.lib" "$(ProjectDir)..\..\contrib\openssl\out32.dbg\ssleay32.lib" iphlpapi.lib"
- OutputFile="$(OutDir)/stunTestVectors.exe"
+ AdditionalDependencies="Ws2_32.lib winmm.lib Dnsapi.lib Iphlpapi.lib crypt32.lib"
+ OutputFile="$(OutDir)\ichat-gw-jc.exe"
LinkIncremental="2"
GenerateDebugInformation="true"
- ProgramDatabaseFile="$(OutDir)/stunTestVectors.pdb"
SubSystem="1"
RandomizedBaseAddress="1"
DataExecutionPrevention="0"
@@ -93,15 +91,16 @@
/>
<Tool
Name="VCPostBuildEventTool"
+ CommandLine="copy $(TargetPath) $(ProjectDir)..\"
/>
</Configuration>
<Configuration
Name="Release|Win32"
- OutputDirectory="Release"
- IntermediateDirectory="Release"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
- CharacterSet="2"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
@@ -120,8 +119,8 @@
/>
<Tool
Name="VCCLCompilerTool"
- AdditionalIncludeDirectories="../../contrib/asio;../../contrib/boost_1_34_1;../../;../../contrib/OpenSSL/include;../../contrib/OpenSSL/inc32"
- PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;BOOST_ALL_NO_LIB;_WIN32_WINNT=0x0501;USE_SSL;ASIO_ENABLE_CANCELIO"
+ AdditionalIncludeDirectories=""$(ProjectDir)../../../";"$(ProjectDir)../../../contrib/gloox""
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;USE_SSL;USE_IPV6"
RuntimeLibrary="2"
UsePrecompiledHeader="0"
WarningLevel="3"
@@ -139,8 +138,8 @@
/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="winmm.lib "$(ProjectDir)..\..\contrib\openssl\out32\libeay32.lib" "$(ProjectDir)..\..\contrib\openssl\out32\ssleay32.lib" iphlpapi.lib"
- OutputFile="$(OutDir)/stunTestVectors.exe"
+ AdditionalDependencies="Ws2_32.lib winmm.lib Dnsapi.lib Iphlpapi.lib crypt32.lib"
+ OutputFile="$(OutDir)\ichat-gw-jc.exe"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
@@ -170,6 +169,7 @@
/>
<Tool
Name="VCPostBuildEventTool"
+ CommandLine="copy $(TargetPath) $(ProjectDir)..\"
/>
</Configuration>
</Configurations>
@@ -178,23 +178,31 @@
<Files>
<Filter
Name="Source Files"
- Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
- RelativePath="..\ReTurnSubsystem.cxx"
+ RelativePath=".\ichat-gw-jc.cxx"
>
</File>
<File
- RelativePath="..\StunMessage.cxx"
+ RelativePath=".\IChatUser.cxx"
>
</File>
<File
- RelativePath=".\stunTestVectors.cxx"
+ RelativePath="..\IPCThread.cxx"
>
</File>
<File
- RelativePath="..\StunTuple.cxx"
+ RelativePath=".\JabberComponent.cxx"
+ >
+ </File>
+ <File
+ RelativePath=".\JabberUserDb.cxx"
+ >
+ </File>
+ <File
+ RelativePath="..\Thread.cxx"
>
</File>
</Filter>
@@ -204,21 +212,29 @@
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
- RelativePath="..\ReTurnSubsystem.hxx"
+ RelativePath=".\IChatUser.hxx"
+ >
+ </File>
+ <File
+ RelativePath="..\IPCThread.hxx"
+ >
+ </File>
+ <File
+ RelativePath=".\JabberComponent.hxx"
>
</File>
<File
- RelativePath="..\StunMessage.hxx"
+ RelativePath=".\JabberUserDb.hxx"
>
</File>
<File
- RelativePath="..\StunTuple.hxx"
+ RelativePath="..\Thread.hxx"
>
</File>
</Filter>
<Filter
Name="Resource Files"
- Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+ 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>
diff --git a/apps/sipdial/Makefile.am b/apps/sipdial/Makefile.am
index 6be9403..6f9066e 100644
--- a/apps/sipdial/Makefile.am
+++ b/apps/sipdial/Makefile.am
@@ -22,6 +22,9 @@ libsipdial_la_LDFLAGS += -export-dynamic
bin_PROGRAMS = sipdialer
sipdialer_LDADD = libsipdial.la
+sipdialer_LDADD += ../../resip/dum/libdum.la
+sipdialer_LDADD += ../../resip/stack/libresip.la
+sipdialer_LDADD += ../../rutil/librutil.la
libsipdial_la_SOURCES = \
DialInstance.cpp \
diff --git a/apps/sipdial/Makefile.in b/apps/sipdial/Makefile.in
index 3f1ac01..95cfe7e 100644
--- a/apps/sipdial/Makefile.in
+++ b/apps/sipdial/Makefile.in
@@ -89,7 +89,8 @@ libsipdial_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
PROGRAMS = $(bin_PROGRAMS)
am_sipdialer_OBJECTS = sipdialer.$(OBJEXT)
sipdialer_OBJECTS = $(am_sipdialer_OBJECTS)
-sipdialer_DEPENDENCIES = libsipdial.la
+sipdialer_DEPENDENCIES = libsipdial.la ../../resip/dum/libdum.la \
+ ../../resip/stack/libresip.la ../../rutil/librutil.la
DEFAULT_INCLUDES = -I. at am__isrc@ -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
am__depfiles_maybe = depfiles
@@ -287,7 +288,8 @@ libsipdial_la_LIBADD = ../../resip/dum/libdum.la \
@LIBSSL_LIBADD@ -lpthread
libsipdial_la_LDFLAGS = -version-info 0:0:0 -release @ABIVERSION@ \
-export-dynamic
-sipdialer_LDADD = libsipdial.la
+sipdialer_LDADD = libsipdial.la ../../resip/dum/libdum.la \
+ ../../resip/stack/libresip.la ../../rutil/librutil.la
libsipdial_la_SOURCES = \
DialInstance.cpp \
MyInviteSessionHandler.cpp \
diff --git a/config.h.in b/config.h.in
index 4142663..73672f9 100644
--- a/config.h.in
+++ b/config.h.in
@@ -3,6 +3,9 @@
/* BUILD_APPS */
#undef BUILD_APPS
+/* BUILD_ICHAT_GW */
+#undef BUILD_ICHAT_GW
+
/* BUILD_P2P */
#undef BUILD_P2P
diff --git a/configure b/configure
index 65dc979..6778b9e 100755
--- a/configure
+++ b/configure
@@ -752,6 +752,8 @@ BUILD_P2P_FALSE
BUILD_P2P_TRUE
BUILD_RECON_FALSE
BUILD_RECON_TRUE
+BUILD_ICHAT_GW_FALSE
+BUILD_ICHAT_GW_TRUE
BUILD_APPS_FALSE
BUILD_APPS_TRUE
BUILD_TFM_FALSE
@@ -910,6 +912,7 @@ with_geoip
with_radius
with_tfm
with_apps
+with_ichat_gw
with_recon
with_p2p
enable_maintainer_mode
@@ -1574,6 +1577,7 @@ Optional Packages:
--with-radius Link against RADIUS client libraries
--with-tfm Build TFM, links against Netxx and cppunit
--with-apps Build apps, links against various things
+ --with-ichat-gw Build iChat gateway, links against gloox
--with-recon Build recon, links against sipX
--with-p2p Build P2P, links against S2C and SSL, unfinished
@@ -5109,13 +5113,13 @@ if test "${lt_cv_nm_interface+set}" = set; then :
else
lt_cv_nm_interface="BSD nm"
echo "int some_variable = 0;" > conftest.$ac_ext
- (eval echo "\"\$as_me:5112: $ac_compile\"" >&5)
+ (eval echo "\"\$as_me:5116: $ac_compile\"" >&5)
(eval "$ac_compile" 2>conftest.err)
cat conftest.err >&5
- (eval echo "\"\$as_me:5115: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
+ (eval echo "\"\$as_me:5119: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
(eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
cat conftest.err >&5
- (eval echo "\"\$as_me:5118: output\"" >&5)
+ (eval echo "\"\$as_me:5122: output\"" >&5)
cat conftest.out >&5
if $GREP 'External.*some_variable' conftest.out > /dev/null; then
lt_cv_nm_interface="MS dumpbin"
@@ -6321,7 +6325,7 @@ ia64-*-hpux*)
;;
*-*-irix6*)
# Find out which ABI we are using.
- echo '#line 6324 "configure"' > conftest.$ac_ext
+ echo '#line 6328 "configure"' > conftest.$ac_ext
if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
(eval $ac_compile) 2>&5
ac_status=$?
@@ -8377,11 +8381,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:8380: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:8384: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:8384: \$? = $ac_status" >&5
+ echo "$as_me:8388: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -8716,11 +8720,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:8719: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:8723: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:8723: \$? = $ac_status" >&5
+ echo "$as_me:8727: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -8821,11 +8825,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:8824: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:8828: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:8828: \$? = $ac_status" >&5
+ echo "$as_me:8832: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -8876,11 +8880,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:8879: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:8883: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:8883: \$? = $ac_status" >&5
+ echo "$as_me:8887: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -11260,7 +11264,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 11263 "configure"
+#line 11267 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -11356,7 +11360,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 11359 "configure"
+#line 11363 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -13312,11 +13316,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:13315: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:13319: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:13319: \$? = $ac_status" >&5
+ echo "$as_me:13323: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -13411,11 +13415,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:13414: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:13418: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:13418: \$? = $ac_status" >&5
+ echo "$as_me:13422: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -13463,11 +13467,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:13466: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:13470: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:13470: \$? = $ac_status" >&5
+ echo "$as_me:13474: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -14986,7 +14990,7 @@ cat >>confdefs.h <<_ACEOF
#define USE_MYSQL /**/
_ACEOF
- LIBMYSQL_LIBADD="-lmysqlclient"
+ LIBMYSQL_LIBADD="-lmysqlclient_r"
if true; then
USE_MYSQL_TRUE=
@@ -15121,6 +15125,33 @@ fi
if false; then
+ BUILD_ICHAT_GW_TRUE=
+ BUILD_ICHAT_GW_FALSE='#'
+else
+ BUILD_ICHAT_GW_TRUE='#'
+ BUILD_ICHAT_GW_FALSE=
+fi
+
+
+# Check whether --with-ichat-gw was given.
+if test "${with_ichat_gw+set}" = set; then :
+ withval=$with_ichat_gw;
+cat >>confdefs.h <<_ACEOF
+#define BUILD_ICHAT_GW /**/
+_ACEOF
+
+ if true; then
+ BUILD_ICHAT_GW_TRUE=
+ BUILD_ICHAT_GW_FALSE='#'
+else
+ BUILD_ICHAT_GW_TRUE='#'
+ BUILD_ICHAT_GW_FALSE=
+fi
+
+fi
+
+
+ if false; then
BUILD_RECON_TRUE=
BUILD_RECON_FALSE='#'
else
@@ -15832,6 +15863,14 @@ if test -z "${BUILD_APPS_TRUE}" && test -z "${BUILD_APPS_FALSE}"; then
as_fn_error $? "conditional \"BUILD_APPS\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
+if test -z "${BUILD_ICHAT_GW_TRUE}" && test -z "${BUILD_ICHAT_GW_FALSE}"; then
+ as_fn_error $? "conditional \"BUILD_ICHAT_GW\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${BUILD_ICHAT_GW_TRUE}" && test -z "${BUILD_ICHAT_GW_FALSE}"; then
+ as_fn_error $? "conditional \"BUILD_ICHAT_GW\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
if test -z "${BUILD_RECON_TRUE}" && test -z "${BUILD_RECON_FALSE}"; then
as_fn_error $? "conditional \"BUILD_RECON\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
diff --git a/configure.ac b/configure.ac
index 4a25f84..93aac92 100644
--- a/configure.ac
+++ b/configure.ac
@@ -172,7 +172,7 @@ AM_CONDITIONAL(USE_MYSQL, false)
AC_ARG_WITH(mysql,
[ --with-mysql Link against MySQL client libraries],
[AC_DEFINE_UNQUOTED(USE_MYSQL, , USE_MYSQL)
- AC_SUBST(LIBMYSQL_LIBADD, "-lmysqlclient")
+ AC_SUBST(LIBMYSQL_LIBADD, "-lmysqlclient_r")
AM_CONDITIONAL(USE_MYSQL, true)],
[ AC_SUBST(LIBMYSQL_LIBADD, "")])
@@ -204,6 +204,12 @@ AC_ARG_WITH(apps,
[AC_DEFINE_UNQUOTED(BUILD_APPS, , BUILD_APPS)
AM_CONDITIONAL(BUILD_APPS, true)], )
+AM_CONDITIONAL(BUILD_ICHAT_GW, false)
+AC_ARG_WITH(ichat-gw,
+[ --with-ichat-gw Build iChat gateway, links against gloox],
+ [AC_DEFINE_UNQUOTED(BUILD_ICHAT_GW, , BUILD_ICHAT_GW)
+ AM_CONDITIONAL(BUILD_ICHAT_GW, true)], )
+
AM_CONDITIONAL(BUILD_RECON, false)
AC_ARG_WITH(recon,
[ --with-recon Build recon, links against sipX],
diff --git a/repro/AsyncProcessor.hxx b/repro/AsyncProcessor.hxx
index 8a283fb..96a089e 100644
--- a/repro/AsyncProcessor.hxx
+++ b/repro/AsyncProcessor.hxx
@@ -46,12 +46,6 @@ class AsyncProcessorMessage;
// {
// }
//
-// MyAsyncProcessorAsyncMessage(const MyAsyncProcessorAsyncMessage& orig):
-// AsyncProcessorMessage(orig)
-// {
-// }
-//
-// virtual Message* clone() const { return new MyAsyncProcessorAsyncMessage(*this); }
// virtual EncodeStream& encode(EncodeStream& strm) const { strm << "MyAsyncProcessorAsyncMessage(tid="<<mTid<<")"; return strm; }
//
// Data mDataRequiredToCallBlockingFunction;
diff --git a/repro/AsyncProcessorMessage.hxx b/repro/AsyncProcessorMessage.hxx
index a63b6e5..a1cd062 100644
--- a/repro/AsyncProcessorMessage.hxx
+++ b/repro/AsyncProcessorMessage.hxx
@@ -18,13 +18,8 @@ public:
{
}
- AsyncProcessorMessage(const AsyncProcessorMessage& orig):
- ProcessorMessage(orig),
- mAsyncProcessor(orig.mAsyncProcessor)
- {
- }
+ virtual Message* clone() const { assert(false); return 0; }
- virtual Message* clone() const = 0;
virtual EncodeStream& encode(EncodeStream& strm) const { strm << "AsyncProcessorMessage(tid="<<mTid<<")"; return strm; }
virtual EncodeStream& encodeBrief(EncodeStream& strm) const { return encode(strm);}
diff --git a/repro/FilterStore.cxx b/repro/FilterStore.cxx
index d1fb482..728c75d 100644
--- a/repro/FilterStore.cxx
+++ b/repro/FilterStore.cxx
@@ -36,7 +36,7 @@ FilterStore::FilterStore(AbstractDb& db):
filter.pcond2 = 0;
int flags = REG_EXTENDED;
- if(filter.filterRecord.mActionData.find("$") == Data::npos )
+ if(filter.filterRecord.mActionData.find("$") == Data::npos)
{
flags |= REG_NOSUB;
}
diff --git a/repro/MySqlDb.cxx b/repro/MySqlDb.cxx
index 18d4be4..2c76f47 100644
--- a/repro/MySqlDb.cxx
+++ b/repro/MySqlDb.cxx
@@ -28,6 +28,42 @@ using namespace std;
#define RESIPROCATE_SUBSYSTEM Subsystem::REPRO
+extern "C"
+{
+ void mysqlThreadEnd(void*)
+ {
+ mysql_thread_end();
+ }
+}
+
+// This class helps ensure that each thread using the MySQL API's
+// initialize by calling mysql_thread_init before calling any mySQL functions
+class MySQLInitializer
+{
+ public:
+ MySQLInitializer()
+ {
+ ThreadIf::tlsKeyCreate(mThreadStorage, mysqlThreadEnd);
+ }
+ ~MySQLInitializer()
+ {
+ ThreadIf::tlsKeyDelete(mThreadStorage);
+ }
+ void setInitialized()
+ {
+ ThreadIf::tlsSetValue(mThreadStorage, (void*) true);
+ }
+ bool isInitialized()
+ {
+ // Note: if value is not set yet then 0 (false) is returned
+ return ThreadIf::tlsGetValue(mThreadStorage) != 0;
+ }
+
+ private:
+ ThreadIf::TlsKey mThreadStorage;
+};
+static MySQLInitializer g_MySQLInitializer;
+
MySqlDb::MySqlDb(const Data& server,
const Data& user,
const Data& password,
@@ -50,7 +86,15 @@ MySqlDb::MySqlDb(const Data& server,
mResult[i]=0;
}
- connectToDatabase();
+ mysql_library_init(0, 0, 0);
+ if(!mysql_thread_safe())
+ {
+ ErrLog( << "Repro uses MySQL from multiple threads - you MUST link with a thread safe version of the mySQL client library!");
+ }
+ else
+ {
+ connectToDatabase();
+ }
}
@@ -60,6 +104,16 @@ MySqlDb::~MySqlDb()
}
void
+MySqlDb::initialize() const
+{
+ if(!g_MySQLInitializer.isInitialized())
+ {
+ g_MySQLInitializer.setInitialized();
+ mysql_thread_init();
+ }
+}
+
+void
MySqlDb::disconnectFromDatabase() const
{
if(mConn)
@@ -104,6 +158,7 @@ MySqlDb::connectToDatabase() const
mDBPort, // port
0, // unix socket file
0); // client flags
+
if (ret == 0)
{
int rc = mysql_errno(mConn);
@@ -120,13 +175,16 @@ MySqlDb::connectToDatabase() const
}
}
-int
-MySqlDb::query(const Data& queryCommand) const
+int
+MySqlDb::query(const Data& queryCommand, MYSQL_RES** result) const
{
int rc = 0;
+ initialize();
+
DebugLog( << "MySqlDb::query: executing query: " << queryCommand);
+ Lock lock(mMutex);
if(mConn == 0 || !mConnected)
{
rc = connectToDatabase();
@@ -161,6 +219,20 @@ MySqlDb::query(const Data& queryCommand) const
}
}
+ // Now store result - if pointer to result pointer was supplied and no errors
+ if(rc == 0 && result)
+ {
+ *result = mysql_store_result(mConn);
+ if(*result == 0)
+ {
+ rc = mysql_errno(mConn);
+ if(rc != 0)
+ {
+ ErrLog( << "MySQL store result failed: error=" << rc << ": " << mysql_error(mConn));
+ }
+ }
+ }
+
if(rc != 0)
{
ErrLog( << " SQL Command was: " << queryCommand) ;
@@ -168,26 +240,26 @@ MySqlDb::query(const Data& queryCommand) const
return rc;
}
-
int
-MySqlDb::singleResultQuery(const Data& queryCommand, Data& resultData) const
+MySqlDb::singleResultQuery(const Data& queryCommand, std::vector<Data>& fields) const
{
- int rc = query(queryCommand);
+ MYSQL_RES* result=0;
+ int rc = query(queryCommand, &result);
if(rc == 0)
{
- MYSQL_RES* result = mysql_store_result(mConn);
if(result == 0)
{
- rc = mysql_errno(mConn);
- ErrLog( << "MySQL store result failed: error=" << rc << ": " << mysql_error(mConn));
return rc;
}
MYSQL_ROW row = mysql_fetch_row(result);
if(row)
{
- resultData = Data(row[0]);
+ for(unsigned int i = 0; i < result->field_count; i++)
+ {
+ fields.push_back(Data(row[i]));
+ }
}
else
{
@@ -202,6 +274,12 @@ MySqlDb::singleResultQuery(const Data& queryCommand, Data& resultData) const
return rc;
}
+resip::Data&
+MySqlDb::escapeString(const resip::Data& str, resip::Data& escapedStr) const
+{
+ escapedStr.truncate2(mysql_real_escape_string(mConn, (char*)escapedStr.getBuf(str.size()*2+1), str.c_str(), str.size()));
+ return escapedStr;
+}
bool
MySqlDb::addUser(const AbstractDb::Key& key, const AbstractDb::UserRecord& rec)
@@ -218,7 +296,7 @@ MySqlDb::addUser(const AbstractDb::Key& key, const AbstractDb::UserRecord& rec)
<< "', forwardAddress='" << rec.forwardAddress
<< "'";
}
- return query(command) == 0;
+ return query(command, 0) == 0;
}
@@ -231,7 +309,7 @@ MySqlDb::eraseUser(const AbstractDb::Key& key )
ds << "DELETE FROM users ";
userWhereClauseToDataStream(key, ds);
}
- query(command);
+ query(command, 0);
}
@@ -247,12 +325,12 @@ MySqlDb::getUser( const AbstractDb::Key& key ) const
userWhereClauseToDataStream(key, ds);
}
- if(query(command) != 0)
+ MYSQL_RES* result=0;
+ if(query(command, &result) != 0)
{
return ret;
}
- MYSQL_RES* result = mysql_store_result(mConn);
if (result==0)
{
ErrLog( << "MySQL store result failed: error=" << mysql_errno(mConn) << ": " << mysql_error(mConn));
@@ -280,7 +358,7 @@ MySqlDb::getUser( const AbstractDb::Key& key ) const
resip::Data
MySqlDb::getUserAuthInfo( const AbstractDb::Key& key ) const
{
- Data ret;
+ std::vector<Data> ret;
Data command;
{
@@ -301,14 +379,14 @@ MySqlDb::getUserAuthInfo( const AbstractDb::Key& key ) const
}
}
- if(singleResultQuery(command, ret) != 0)
+ if(singleResultQuery(command, ret) != 0 || ret.size() == 0)
{
return Data::Empty;
}
- DebugLog( << "Auth password is " << ret);
+ DebugLog( << "Auth password is " << ret.front());
- return ret;
+ return ret.front();
}
@@ -324,12 +402,11 @@ MySqlDb::firstUserKey()
Data command("SELECT user, domain FROM users");
- if(query(command) != 0)
+ if(query(command, &mResult[UserTable]) != 0)
{
return Data::Empty;
}
- mResult[UserTable] = mysql_store_result(mConn);
if(mResult[UserTable] == 0)
{
ErrLog( << "MySQL store result failed: error=" << mysql_errno(mConn) << ": " << mysql_error(mConn));
@@ -372,13 +449,14 @@ MySqlDb::dbWriteRecord(const Table table,
// Check if there is a secondary key or not and get it's value
char* secondaryKey;
unsigned int secondaryKeyLen;
+ Data escapedKey;
if(AbstractDb::getSecondaryKey(table, pKey, pData, (void**)&secondaryKey, &secondaryKeyLen) == 0)
{
Data sKey(Data::Share, secondaryKey, secondaryKeyLen);
DataStream ds(command);
ds << "REPLACE INTO " << tableName(table)
- << " SET attr='" << pKey
- << "', attr2='" << sKey
+ << " SET attr='" << escapeString(pKey, escapedKey)
+ << "', attr2='" << escapeString(sKey, escapedKey)
<< "', value='" << pData.base64encode()
<< "'";
}
@@ -386,34 +464,34 @@ MySqlDb::dbWriteRecord(const Table table,
{
DataStream ds(command);
ds << "REPLACE INTO " << tableName(table)
- << " SET attr='" << pKey
+ << " SET attr='" << escapeString(pKey, escapedKey)
<< "', value='" << pData.base64encode()
<< "'";
}
- return query(command) == 0;
+ return query(command, 0) == 0;
}
-
bool
MySqlDb::dbReadRecord(const Table table,
const resip::Data& pKey,
resip::Data& pData) const
{
Data command;
+ Data escapedKey;
{
DataStream ds(command);
ds << "SELECT value FROM " << tableName(table)
- << " WHERE attr='" << pKey
+ << " WHERE attr='" << escapeString(pKey, escapedKey)
<< "'";
}
- if(query(command) != 0)
+ MYSQL_RES* result = 0;
+ if(query(command, &result) != 0)
{
return false;
}
- MYSQL_RES* result = mysql_store_result(mConn);
if (result == 0)
{
ErrLog( << "MySQL store result failed: error=" << mysql_errno(mConn) << ": " << mysql_error(mConn));
@@ -442,17 +520,18 @@ MySqlDb::dbEraseRecord(const Table table,
Data command;
{
DataStream ds(command);
+ Data escapedKey;
ds << "DELETE FROM " << tableName(table);
if(isSecondaryKey)
{
- ds << " WHERE attr2='" << pKey << "'";
+ ds << " WHERE attr2='" << escapeString(pKey, escapedKey) << "'";
}
else
{
- ds << " WHERE attr='" << pKey << "'";
+ ds << " WHERE attr='" << escapeString(pKey, escapedKey) << "'";
}
}
- query(command);
+ query(command, 0);
}
@@ -474,22 +553,23 @@ MySqlDb::dbNextKey(const Table table, bool first)
ds << "SELECT attr FROM " << tableName(table);
}
- if(query(command) != 0)
+ if(query(command, &mResult[table]) != 0)
{
return Data::Empty;
}
- mResult[table] = mysql_store_result(mConn);
if (mResult[table] == 0)
{
ErrLog( << "MySQL store result failed: error=" << mysql_errno(mConn) << ": " << mysql_error(mConn));
return Data::Empty;
}
}
-
- if (mResult[table] == 0)
- {
- return Data::Empty;
+ else
+ {
+ if (mResult[table] == 0)
+ {
+ return Data::Empty;
+ }
}
MYSQL_ROW row = mysql_fetch_row(mResult[table]);
@@ -526,9 +606,10 @@ MySqlDb::dbNextRecord(const Table table,
ds << "SELECT value FROM " << tableName(table);
if(!key.empty())
{
+ Data escapedKey;
// dbNextRecord is used to iterator through database tables that support duplication records
// it is only appropriate for MySQL tables that contain the attr2 non-unique index (secondary key)
- ds << " WHERE attr2='" << key << "'";
+ ds << " WHERE attr2='" << escapeString(key, escapedKey) << "'";
}
if(forUpdate)
{
@@ -536,12 +617,11 @@ MySqlDb::dbNextRecord(const Table table,
}
}
- if(query(command) != 0)
+ if(query(command, &mResult[table]) != 0)
{
return false;
}
- mResult[table] = mysql_store_result(mConn);
if (mResult[table] == 0)
{
ErrLog( << "MySQL store result failed: error=" << mysql_errno(mConn) << ": " << mysql_error(mConn));
@@ -571,10 +651,10 @@ bool
MySqlDb::dbBeginTransaction(const Table table)
{
Data command("SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ");
- if(query(command) == 0)
+ if(query(command, 0) == 0)
{
command = "START TRANSACTION";
- return query(command) == 0;
+ return query(command, 0) == 0;
}
return false;
}
@@ -583,14 +663,14 @@ bool
MySqlDb::dbCommitTransaction(const Table table)
{
Data command("COMMIT");
- return query(command) == 0;
+ return query(command, 0) == 0;
}
bool
MySqlDb::dbRollbackTransaction(const Table table)
{
Data command("ROLLBACK");
- return query(command) == 0;
+ return query(command, 0) == 0;
}
static const char usersavp[] = "usersavp";
diff --git a/repro/MySqlDb.hxx b/repro/MySqlDb.hxx
index 7c05506..6286c83 100644
--- a/repro/MySqlDb.hxx
+++ b/repro/MySqlDb.hxx
@@ -39,7 +39,8 @@ class MySqlDb: public AbstractDb
virtual Key firstUserKey();// return empty if no more
virtual Key nextUserKey(); // return empty if no more
- virtual int singleResultQuery(const resip::Data& queryCommand, resip::Data& resultData) const;
+ // Perform a query that expects a single result/row - returns all column/field data in a vector
+ virtual int singleResultQuery(const resip::Data& queryCommand, std::vector<resip::Data>& fields) const;
private:
// Db manipulation routines
@@ -63,9 +64,11 @@ class MySqlDb: public AbstractDb
virtual bool dbCommitTransaction(const Table table);
virtual bool dbRollbackTransaction(const Table table);
+ void initialize() const;
void disconnectFromDatabase() const;
int connectToDatabase() const;
- int query(const resip::Data& queryCommand) const;
+ int query(const resip::Data& queryCommand, MYSQL_RES** result) const;
+ resip::Data& escapeString(const resip::Data& str, resip::Data& escapedStr) const;
resip::Data mDBServer;
resip::Data mDBUser;
@@ -76,7 +79,11 @@ class MySqlDb: public AbstractDb
mutable MYSQL* mConn;
mutable MYSQL_RES* mResult[MaxTable];
- mutable bool mConnected;
+ mutable volatile bool mConnected;
+ // when multiple threads are in use with the same connection, you need to
+ // mutex calls to mysql_query and mysql_store_result:
+ // http://dev.mysql.com/doc/refman/5.1/en/threaded-clients.html
+ mutable resip::Mutex mMutex;
const char* tableName( Table table ) const;
void userWhereClauseToDataStream(const Key& key, resip::DataStream& ds) const;
diff --git a/repro/ReproRunner.cxx b/repro/ReproRunner.cxx
index 0485bc0..33a089b 100644
--- a/repro/ReproRunner.cxx
+++ b/repro/ReproRunner.cxx
@@ -251,6 +251,7 @@ ReproRunner::run(int argc, char** argv)
}
mRunning = true;
+
return true;
}
@@ -487,6 +488,7 @@ ReproRunner::createSipStack()
InteropHelper::setOutboundVersion(mProxyConfig->getConfigInt("OutboundVersion", 5626));
InteropHelper::setOutboundSupported(mProxyConfig->getConfigBool("DisableOutbound", false) ? false : true);
InteropHelper::setRRTokenHackEnabled(mProxyConfig->getConfigBool("EnableFlowTokens", false));
+ InteropHelper::setAssumeFirstHopSupportsOutboundEnabled(mProxyConfig->getConfigBool("AssumeFirstHopSupportsOutbound", false));
Data clientNATDetectionMode = mProxyConfig->getConfigData("ClientNatDetectionMode", "DISABLED");
if(isEqualNoCase(clientNATDetectionMode, "ENABLED"))
{
@@ -1240,7 +1242,7 @@ ReproRunner::makeRequestProcessorChain(ProcessorChain& chain)
// add simple static route monkey
chain.addProcessor(std::auto_ptr<Processor>(new SimpleStaticRoute(*mProxyConfig)));
}
-
+
// Add location server monkey
chain.addProcessor(std::auto_ptr<Processor>(new LocationServer(*mProxyConfig, *mRegistrationPersistenceManager, mAuthRequestDispatcher)));
diff --git a/repro/RouteStore.cxx b/repro/RouteStore.cxx
index 506d816..50e844d 100644
--- a/repro/RouteStore.cxx
+++ b/repro/RouteStore.cxx
@@ -32,22 +32,22 @@ RouteStore::RouteStore(AbstractDb& db):
route.key = key;
route.preq = 0;
- if( !route.routeRecord.mMatchingPattern.empty() )
+ if(!route.routeRecord.mMatchingPattern.empty())
{
- int flags = REG_EXTENDED;
- if( route.routeRecord.mRewriteExpression.find("$") == Data::npos )
- {
- flags |= REG_NOSUB;
- }
- route.preq = new regex_t;
- int ret = regcomp( route.preq, route.routeRecord.mMatchingPattern.c_str(), flags );
- if( ret != 0 )
- {
- delete route.preq;
- ErrLog( << "Routing rule has invalid match expression: "
- << route.routeRecord.mMatchingPattern );
- route.preq = 0;
- }
+ int flags = REG_EXTENDED;
+ if(route.routeRecord.mRewriteExpression.find("$") == Data::npos)
+ {
+ flags |= REG_NOSUB;
+ }
+ route.preq = new regex_t;
+ int ret = regcomp(route.preq, route.routeRecord.mMatchingPattern.c_str(), flags);
+ if(ret != 0)
+ {
+ delete route.preq;
+ ErrLog(<< "Routing rule has invalid match expression: "
+ << route.routeRecord.mMatchingPattern);
+ route.preq = 0;
+ }
}
mRouteOperators.insert( route );
diff --git a/repro/SiloStore.cxx b/repro/SiloStore.cxx
index 615d3b8..9f083de 100644
--- a/repro/SiloStore.cxx
+++ b/repro/SiloStore.cxx
@@ -3,7 +3,6 @@
#include "rutil/Lock.hxx"
#include "resip/stack/SipMessage.hxx"
-#include "resip/stack/ExtensionHeader.hxx"
#include "repro/SiloStore.hxx"
#include "rutil/WinLeakCheck.hxx"
diff --git a/repro/monkeys/MessageSilo.cxx b/repro/monkeys/MessageSilo.cxx
index f04ea0c..d2dc3be 100644
--- a/repro/monkeys/MessageSilo.cxx
+++ b/repro/monkeys/MessageSilo.cxx
@@ -33,13 +33,7 @@ public:
{
}
- AsyncAddToSiloMessage(const AsyncAddToSiloMessage& orig):
- AsyncProcessorMessage(orig)
- {
- }
-
- virtual Message* clone() const { return new AsyncAddToSiloMessage(*this); }
- virtual EncodeStream& encode(EncodeStream& strm) const { strm << "AsyncAddToSiloMessage(tid=" << mTid << ")"; return strm; }
+ virtual EncodeStream& encode(EncodeStream& strm) const { strm << "AsyncAddToSiloMessage(tid=" << mTid << ", aor=" << mDestUri << ")"; return strm; }
Data mDestUri;
Data mSourceUri;
@@ -58,13 +52,7 @@ public:
{
}
- AsyncDrainSiloMessage(const AsyncAddToSiloMessage& orig):
- AsyncProcessorMessage(orig)
- {
- }
-
- virtual Message* clone() const { return new AsyncDrainSiloMessage(*this); }
- virtual EncodeStream& encode(EncodeStream& strm) const { strm << "AsyncDrainSiloMessage(tid=" << mTid << ")"; return strm; }
+ virtual EncodeStream& encode(EncodeStream& strm) const { strm << "AsyncDrainSiloMessage(aor=" << mAor << ")"; return strm; }
Data mAor;
ContactList mRequestContacts;
@@ -88,7 +76,7 @@ MessageSilo::MessageSilo(ProxyConfig& config, Dispatcher* asyncDispatcher) :
if(!destFilterRegex.empty())
{
mDestFilterRegex= new regex_t;
- int ret = regcomp(mDestFilterRegex, destFilterRegex.c_str(), REG_EXTENDED);
+ int ret = regcomp(mDestFilterRegex, destFilterRegex.c_str(), REG_EXTENDED | REG_NOSUB);
if( ret != 0 )
{
delete mDestFilterRegex;
@@ -99,7 +87,7 @@ MessageSilo::MessageSilo(ProxyConfig& config, Dispatcher* asyncDispatcher) :
if(!mimeTypeFilterRegex.empty())
{
mMimeTypeFilterRegex= new regex_t;
- int ret = regcomp(mMimeTypeFilterRegex, mimeTypeFilterRegex.c_str(), REG_EXTENDED);
+ int ret = regcomp(mMimeTypeFilterRegex, mimeTypeFilterRegex.c_str(), REG_EXTENDED | REG_NOSUB);
if( ret != 0 )
{
delete mMimeTypeFilterRegex;
diff --git a/repro/monkeys/RequestFilter.cxx b/repro/monkeys/RequestFilter.cxx
index 96e0f9d..5cb58c5 100644
--- a/repro/monkeys/RequestFilter.cxx
+++ b/repro/monkeys/RequestFilter.cxx
@@ -35,17 +35,11 @@ public:
{
}
- RequestFilterAsyncMessage(const RequestFilterAsyncMessage& orig):
- AsyncProcessorMessage(orig)
- {
- }
-
- virtual Message* clone() const { return new RequestFilterAsyncMessage(*this); }
- virtual EncodeStream& encode(EncodeStream& strm) const { strm << "RequestFilterAsyncMessage(tid="<<mTid<<")"; return strm; }
+ virtual EncodeStream& encode(EncodeStream& strm) const { strm << "RequestFilterAsyncMessage(tid=" << mTid << ")"; return strm; }
Data mQuery;
int mQueryResult;
- Data mQueryResultData;
+ std::vector<Data> mQueryResultData;
};
RequestFilter::RequestFilter(ProxyConfig& config,
@@ -146,14 +140,16 @@ RequestFilter::process(RequestContext &rc)
if (async)
{
- InfoLog(<< "RequestFilter query complete: queryResult=" << async->mQueryResult << ", resultData=" << async->mQueryResultData);
-
- if(async->mQueryResult == 0) // If query was successful, then get query result
+ if(async->mQueryResult == 0 && async->mQueryResultData.size() > 0) // If query was successful, then get query result
{
- return applyActionResult(rc, async->mQueryResultData);
+ InfoLog(<< "RequestFilter query completed successfully: queryResult=" << async->mQueryResult << ", resultData=" << async->mQueryResultData.front());
+
+ return applyActionResult(rc, async->mQueryResultData.front());
}
else
{
+ InfoLog(<< "RequestFilter query failed: queryResult=" << async->mQueryResult);
+
return applyActionResult(rc, mDefaultDBErrorBehavior);
}
}
diff --git a/repro/repro.config b/repro/repro.config
index 284c4c4..be19cfd 100644
--- a/repro/repro.config
+++ b/repro/repro.config
@@ -323,6 +323,19 @@ DisableOutbound = true
# (ie. 5, 8, etc.)
OutboundVersion = 5626
+# There are cases where the first hop in a particular network supports the concept of outbound
+# and ensures all messaging for a client is delivered over the same connection used for
+# registration. This could be a SBC or other NAT traversal aid router that uses the Path
+# header. However such endpoints may not be 100% compliant with outbound RFC and may not
+# include a ;ob parameter in the path header. This parameter is required in order for repro
+# to have knowledge that the first hop does support outbound, and it will reject registrations
+# that appear to be using outboud (ie. instanceId and regId) with a 439 (First Hop Lacks Outbound
+# Support). In this case it can be desirable when using repro as the registrar to not reject
+# REGISTRATION requests that contain an instanceId and regId with a 439.
+# If this setting is enabled, then repro will assume the first hop supports outbound
+# and not return this error.
+AssumeFirstHopSupportsOutbound = false
+
# Enable use of flow-tokens in non-outbound cases
# WARNING: Before enabling this, ensure you have a RecordRouteUri setup, or are using
# the alternate transport specification mechanism and defining a RecordRouteUri per
diff --git a/repro/repro_10_0.vcxproj b/repro/repro_10_0.vcxproj
index c5cf84d..0e567a8 100644
--- a/repro/repro_10_0.vcxproj
+++ b/repro/repro_10_0.vcxproj
@@ -269,7 +269,7 @@ endlocal
</Command>
</PreBuildEvent>
<ClCompile>
- <AdditionalIncludeDirectories>$(ProjectDir)../;$(ProjectDir)../resip/stack;$(ProjectDir)../contrib/db/build_windows;$(ProjectDir)../contrib/MySQLConnectorC/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>$(ProjectDir)../;$(ProjectDir)../resip/stack;$(ProjectDir)../contrib/db/build_windows;$(ProjectDir)../contrib/MySQLConnectorC/include;$(ProjectDir)../contrib/pcre;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;USE_IPV6;USE_MYSQL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<RuntimeTypeInfo>true</RuntimeTypeInfo>
diff --git a/resip/dum/RegistrationHandler.cxx b/resip/dum/RegistrationHandler.cxx
index 15fcad2..c05fe85 100644
--- a/resip/dum/RegistrationHandler.cxx
+++ b/resip/dum/RegistrationHandler.cxx
@@ -8,12 +8,12 @@
using namespace resip;
-void
-ClientRegistrationHandler::onFlowTerminated(ClientRegistrationHandle h)
-{
+void
+ClientRegistrationHandler::onFlowTerminated(ClientRegistrationHandle h)
+{
InfoLog (<< "ClientRegistrationHandler::onFlowTerminated, refreshing registration to open new flow");
h->requestRefresh();
-}
+}
void
ServerRegistrationHandler::getGlobalExpires(const SipMessage& msg, SharedPtr<MasterProfile> masterProfile,
diff --git a/resip/dum/ServerRegistration.cxx b/resip/dum/ServerRegistration.cxx
index 8e2ab23..44fe12a 100644
--- a/resip/dum/ServerRegistration.cxx
+++ b/resip/dum/ServerRegistration.cxx
@@ -461,7 +461,8 @@ ServerRegistration::tryFlow(ContactInstanceRecord& rec,
resip::NameAddr& contact(rec.mContact);
if(contact.exists(p_Instance) && contact.exists(p_regid))
{
- if(!msg.empty(h_Paths) && msg.header(h_Paths).back().uri().exists(p_ob))
+ if(!msg.empty(h_Paths) && (msg.header(h_Paths).back().uri().exists(p_ob) ||
+ InteropHelper::getAssumeFirstHopSupportsOutboundEnabled()))
{
rec.mRegId=contact.param(p_regid);
// Edge-proxy is directly connected to the client, and ready to
diff --git a/resip/stack/InteropHelper.cxx b/resip/stack/InteropHelper.cxx
index aa467ba..3a8cbf5 100644
--- a/resip/stack/InteropHelper.cxx
+++ b/resip/stack/InteropHelper.cxx
@@ -8,6 +8,7 @@ unsigned int InteropHelper::flowTimerSeconds=0; // 0 = disabled
unsigned int InteropHelper::flowTimerGracePeriodSeconds=30;
bool InteropHelper::useRRTokenHack=false;
InteropHelper::ClientNATDetectionMode InteropHelper::clientNATDetection=InteropHelper::ClientNATDetectionDisabled;
+bool InteropHelper::assumeFirstHopSupportsOutbound=false;
}
/* ====================================================================
diff --git a/resip/stack/InteropHelper.hxx b/resip/stack/InteropHelper.hxx
index 21098dc..edf8224 100644
--- a/resip/stack/InteropHelper.hxx
+++ b/resip/stack/InteropHelper.hxx
@@ -57,6 +57,20 @@ class InteropHelper
static InteropHelper::ClientNATDetectionMode getClientNATDetectionMode(){return clientNATDetection;}
static void setClientNATDetectionMode(InteropHelper::ClientNATDetectionMode mode) {clientNATDetection=mode;}
+ // There are cases where the first hop in a particular network supports the concept of outbound
+ // and ensures all messaging for a client is delivered over the same connection used for
+ // registration. This could be a SBC or other NAT traversal aid router that uses the Path
+ // header. However such endpoints may not be 100% compliant with outbound RFC and may not
+ // include a ;ob parameter in the path header. This parameter is required in order for repro
+ // to have knowledge that the first hop does support outbound, and it will reject registrations
+ // that appear to be using outboud (ie. instanceId and regId) with a 439 (First Hop Lacks Outbound
+ // Support). In this case it can be desirable when using repro as the registrar to not reject
+ // REGISTRATION requests that contain an instanceId and regId with a 439.
+ // If this setting is enabled, then repro will assume the first hop supports outbound
+ // and not return this error.
+ static bool getAssumeFirstHopSupportsOutboundEnabled(){return assumeFirstHopSupportsOutbound;}
+ static void setAssumeFirstHopSupportsOutboundEnabled(bool enabled) {assumeFirstHopSupportsOutbound=enabled;}
+
private:
InteropHelper();
~InteropHelper();
@@ -67,6 +81,7 @@ class InteropHelper
static unsigned int flowTimerGracePeriodSeconds;
static bool useRRTokenHack;
static ClientNATDetectionMode clientNATDetection;
+ static bool assumeFirstHopSupportsOutbound;
};
}
diff --git a/resip/stack/TransportSelector.cxx b/resip/stack/TransportSelector.cxx
index 1317bdc..d21151a 100644
--- a/resip/stack/TransportSelector.cxx
+++ b/resip/stack/TransportSelector.cxx
@@ -563,13 +563,14 @@ TransportSelector::findTransportByVia(SipMessage* msg, const Tuple& target,
assert(!msg->const_header(h_Vias).empty());
const Via& via = msg->const_header(h_Vias).front();
- if (via.sentHost().empty())
+ if (via.sentHost().empty() && via.transport().empty())
{
- return NULL;
+ return 0;
}
// XXX: Is there better way to do below (without the copy)?
- source = Tuple(via.sentHost(), via.sentPort(), target.ipVersion(), target.getType());
+ source = Tuple(via.sentHost(), via.sentPort(), target.ipVersion(),
+ via.transport().empty() ? target.getType() : toTransportType(via.transport())); // Transport type is pre-populated in via, lock to it
if ( target.mFlowKey!=0 && (source.getPort()==0 || source.isAnyInterface()) )
{
@@ -585,6 +586,7 @@ TransportSelector::findTransportByVia(SipMessage* msg, const Tuple& target,
// transmit() will later use determineSourceInterface() to
// get the actual interface to populate the Contact & Via headers.
// Not sure if we should support this case or just assert.
+ // .gh. This should be supported, in case only the transport part of the Via is set
msg->header(h_Vias).front().sentHost().clear();
}
--
reSIProcate
More information about the Pkg-voip-commits
mailing list