Bug#681387: unblock: resiprocate
On 14/07/12 01:28, Adam D. Barratt wrote:
> On 14.07.2012 00:14, Daniel Pocock wrote:
>> On 12/07/12 22:11, Adam D. Barratt wrote:
>>> On 12.07.2012 20:39, Daniel Pocock wrote:
>>>> Short summary of request: please give authorization to
>>>> a) upload resiprocate 1.8.4-1 source package to unstable
>>>> b) for unblocking 1.8.4-1 to wheezy
>>>
>>> Please could you provide a debdiff between the current source package
>>> in wheezy and the proposed 1.8.4-1 package?
>>>
>>
>> Attached
>
> Thanks. I was really after a source debdiff though - i.e. between the
> old and new .dscs
Src debdiff attached
It is about 2,500 lines - the biggest change is the addition of a
ChangeLog file
diff -Nru resiprocate-1.8.2/apps/sipdial/DialerConfiguration.cpp resiprocate-1.8.4/apps/sipdial/DialerConfiguration.cpp
--- resiprocate-1.8.2/apps/sipdial/DialerConfiguration.cpp 2012-05-25 16:27:28.000000000 +0000
+++ resiprocate-1.8.4/apps/sipdial/DialerConfiguration.cpp 2012-07-05 15:09:56.000000000 +0000
@@ -1,5 +1,6 @@
#include <iostream>
+#include <stdexcept>
#include <string>
#include "rutil/Data.hxx"
@@ -10,61 +11,58 @@
using namespace resip;
using namespace std;
-DialerConfiguration::DialerConfiguration()
+DialerConfiguration::DialerConfiguration() :
+ mDialerIdentity("anonymous@localhost"),
+ mAuthRealm(""),
+ mAuthUser(""),
+ mAuthPassword(""),
+ mCallerUserAgentAddress(""),
+ mCallerUserAgentVariety(Generic),
+ mTargetPrefix(""),
+ mTargetDomain("localhost"),
+ mCertPath(""),
+ mCADirectory("")
{
}
-DialerConfiguration::~DialerConfiguration()
+DialerConfiguration::DialerConfiguration(int argc, char** argv, const resip::Data& defaultConfigFilename, int skipCount) :
+ resip::ConfigParse(argc, argv, defaultConfigFilename, skipCount),
+ mDialerIdentity(getConfigData("dialerIdentity", "anonymous@example.org")),
+ mAuthRealm(getConfigData("authRealm", "")),
+ mAuthUser(getConfigData("authUser", "")),
+ mAuthPassword(getConfigData("authPassword", "")),
+ mCallerUserAgentAddress(getConfigData("callerUserAgentAddress", "")),
+ mCallerUserAgentVariety(Generic),
+ mTargetPrefix(getConfigData("targetPrefix", "")),
+ mTargetDomain(getConfigData("targetDomain", "localhost")),
+ mCertPath(getConfigData("certPath", "")),
+ mCADirectory(getConfigData("CADirectory", ""))
{
+ Data value(getConfigData("callerUserAgentVariety", "Generic"));
+ if(value == "LinksysSPA941")
+ setCallerUserAgentVariety(LinksysSPA941);
+ else if(value == "AlertInfo")
+ setCallerUserAgentVariety(AlertInfo);
+ else if(value == "Cisco7940")
+ setCallerUserAgentVariety(Cisco7940);
+ else if(value == "Generic")
+ setCallerUserAgentVariety(Generic);
+ else
+ throw std::runtime_error("Unexpected value for config setting callerUserAgentVariety");
}
-void DialerConfiguration::loadStream(std::istream& in)
+DialerConfiguration::~DialerConfiguration()
{
- while(!in.eof())
- {
- string param;
- string value;
- in >> param >> value;
- cerr << "param = " << param << " and value = " << value << endl;
- if(param == string("dialerIdentity"))
- setDialerIdentity(NameAddr(Uri(Data(value))));
- else if(param == string("authRealm"))
- setAuthRealm(Data(value));
- else if(param == string("authUser"))
- setAuthUser(Data(value));
- else if(param == string("authPassword"))
- setAuthPassword(Data(value));
- else if(param == string("callerUserAgentAddress"))
- setCallerUserAgentAddress(Uri(Data(value)));
- else if(param == string("callerUserAgentVariety"))
- {
- if(value == string("LinksysSPA941"))
- setCallerUserAgentVariety(LinksysSPA941);
- else if(value == string("PolycomIP501"))
- setCallerUserAgentVariety(PolycomIP501);
- else if(value == string("Cisco7940"))
- setCallerUserAgentVariety(Cisco7940);
- else if(value == string("Generic"))
- setCallerUserAgentVariety(Generic);
- else
- assert(0); // FIXME
- }
- else if(param == string("targetPrefix"))
- setTargetPrefix(Data(value));
- else if(param == string("targetDomain"))
- setTargetDomain(Data(value));
-/* else if(param.size() > 0 &&
- (param[0] == '#' || param[0] == ';'))
- / / skip comment lines
- { } */
- else if(param == string(""))
- // skip empty lines
- { }
- else
- assert(0); // FIXME
- }
}
+void
+DialerConfiguration::printHelpText(int argc, char **argv)
+{
+ std::cerr << "Command line format is:" << std::endl;
+ std::cerr << " " << argv[0] << " <targetUri> [<ConfigFilename>] [--<ConfigValueName>=<ConfigValue>] [--<ConfigValueName>=<ConfigValue>] ..." << std::endl;
+ std::cerr << "Sample Command line(s):" << std::endl;
+ std::cerr << " " << argv[0] << " user@example.org" << std::endl;
+}
/* ====================================================================
*
diff -Nru resiprocate-1.8.2/apps/sipdial/DialerConfiguration.hxx resiprocate-1.8.4/apps/sipdial/DialerConfiguration.hxx
--- resiprocate-1.8.2/apps/sipdial/DialerConfiguration.hxx 2012-05-25 16:27:28.000000000 +0000
+++ resiprocate-1.8.4/apps/sipdial/DialerConfiguration.hxx 2012-07-05 15:09:56.000000000 +0000
@@ -3,18 +3,23 @@
#define __DIALERCONFIGURATION_H
#include <iostream>
+#include <map>
+
+#include <rutil/ConfigParse.hxx>
#include "resip/stack/NameAddr.hxx"
#include "resip/stack/Uri.hxx"
#include "rutil/Data.hxx"
-class DialerConfiguration {
+class DialerConfiguration : public resip::ConfigParse {
public:
DialerConfiguration();
+ DialerConfiguration(int argc, char** argv, const resip::Data& defaultConfigFilename, int skipCount);
virtual ~DialerConfiguration();
- void loadStream(std::istream& in);
+ void printHelpText(int argc, char **argv);
+ using resip::ConfigParse::getConfigValue;
void setDialerIdentity(const resip::NameAddr& dialerIdentity)
{ mDialerIdentity = dialerIdentity; };
@@ -40,7 +45,7 @@
{
Generic,
LinksysSPA941,
- PolycomIP501,
+ AlertInfo,
Cisco7940
} UserAgentVariety;
void setCallerUserAgentVariety(UserAgentVariety callerUserAgentVariety)
@@ -55,6 +60,14 @@
{ mTargetDomain = targetDomain; };
const resip::Data& getTargetDomain()
{ return mTargetDomain; };
+ void setCertPath(const resip::Data& certPath)
+ { mCertPath = certPath; };
+ const resip::Data& getCertPath()
+ { return mCertPath; };
+ void setCADirectory(const resip::Data& caDirectory)
+ { mCADirectory = caDirectory; };
+ const resip::Data& getCADirectory()
+ { return mCADirectory; };
protected:
@@ -83,6 +96,9 @@
// construct a SIP URI
resip::Data mTargetDomain;
+ resip::Data mCertPath;
+ resip::Data mCADirectory;
+
};
diff -Nru resiprocate-1.8.2/apps/sipdial/DialInstance.cpp resiprocate-1.8.4/apps/sipdial/DialInstance.cpp
--- resiprocate-1.8.2/apps/sipdial/DialInstance.cpp 2012-05-25 16:27:28.000000000 +0000
+++ resiprocate-1.8.4/apps/sipdial/DialInstance.cpp 2012-07-05 15:09:56.000000000 +0000
@@ -8,6 +8,8 @@
#include "resip/stack/Uri.hxx"
#include "resip/stack/ssl/Security.hxx"
#include "rutil/Data.hxx"
+#include "rutil/Log.hxx"
+#include "rutil/Logger.hxx"
#include "rutil/SharedPtr.hxx"
#include "DialerConfiguration.hxx"
@@ -17,6 +19,10 @@
using namespace resip;
using namespace std;
+#define RESIPROCATE_SUBSYSTEM resip::Subsystem::APP
+
+#define REFER_TIMEOUT 10
+
DialInstance::DialInstance(const DialerConfiguration& dialerConfiguration, const resip::Uri& targetUri) :
mDialerConfiguration(dialerConfiguration),
mTargetUri(targetUri),
@@ -30,10 +36,18 @@
prepareAddress();
Security* security = 0;
- Data certPath(getenv("HOME"));
- certPath += "/.sipdial/certs";
+
+ Data certPath(mDialerConfiguration.getCertPath());
+ if(certPath.size() == 0)
+ {
+ certPath = getenv("HOME");
+ certPath += "/.sipdial/certs";
+ }
security = new Security(certPath);
+ if(mDialerConfiguration.getCADirectory().size() > 0)
+ security->addCADirectory(mDialerConfiguration.getCADirectory());
+
mSipStack = new SipStack(security);
mDum = new DialogUsageManager(*mSipStack);
//mDum->addTransport(UDP, 5067, V4);
@@ -61,10 +75,26 @@
// Process all SIP stack activity
mSipStack->process(fdset);
while(mDum->process());
+
+ // FIXME - we should wait a little and make sure it really worked
+ if(mProgress == ReferSent)
+ {
+ time_t now;
+ time(&now);
+ if(mReferSentTime + REFER_TIMEOUT < now)
+ {
+ ErrLog(<< "REFER timeout");
+ mProgress = Done;
+ }
+ }
+
if(mProgress == Connected && mClient->isConnected())
{
+ InfoLog(<< "Sending the REFER");
mClient->refer(NameAddr(mFullTarget));
+ InfoLog(<< "Done sending the REFER");
mProgress = ReferSent;
+ time(&mReferSentTime);
}
if(mProgress == Done)
@@ -98,7 +128,10 @@
if(num[0] == '+')
{
// E.164
- mFullTarget = Uri("sip:" + mDialerConfiguration.getTargetPrefix() + num.substr(1, num.size() - 1) + "@" + mDialerConfiguration.getTargetDomain());
+ if(mDialerConfiguration.getTargetPrefix().size() > 0)
+ mFullTarget = Uri("sip:" + mDialerConfiguration.getTargetPrefix() + num.substr(1, num.size() - 1) + "@" + mDialerConfiguration.getTargetDomain());
+ else
+ mFullTarget = Uri("sip:" + num + "@" + mDialerConfiguration.getTargetDomain());
return;
}
mFullTarget = Uri("sip:" + num + "@" + mDialerConfiguration.getTargetDomain());
@@ -124,7 +157,7 @@
hfv = new HeaderFieldValue("\\;answer-after=0", 16);
msg->header(h_CallInfos).push_back(GenericUri(*hfv, Headers::CallInfo));
break;
- case DialerConfiguration::PolycomIP501:
+ case DialerConfiguration::AlertInfo:
hfv = new HeaderFieldValue("AA", 2);
msg->header(h_AlertInfos).push_back(GenericUri(*hfv, Headers::AlertInfo));
break;
@@ -192,18 +225,21 @@
void DialInstance::onReferSuccess()
{
+ InfoLog(<< "Refer was successful");
mResult = ReferSuccessful;
mProgress = Done;
}
void DialInstance::onReferFailed()
{
+ ErrLog(<< "Refer failed");
mResult = ReferUnsuccessful;
mProgress = Done;
}
void DialInstance::onTerminated()
{
+ InfoLog(<< "onTerminated()");
mProgress = Done;
}
diff -Nru resiprocate-1.8.2/apps/sipdial/DialInstance.hxx resiprocate-1.8.4/apps/sipdial/DialInstance.hxx
--- resiprocate-1.8.2/apps/sipdial/DialInstance.hxx 2012-05-25 16:27:28.000000000 +0000
+++ resiprocate-1.8.4/apps/sipdial/DialInstance.hxx 2012-07-05 15:09:56.000000000 +0000
@@ -2,6 +2,8 @@
#ifndef __DIALINSTANCE_H
#define __DIALINSTANCE_H
+#include <time.h>
+
#include "resip/dum/DialogUsageManager.hxx"
#include "resip/stack/Uri.hxx"
#include "rutil/Data.hxx"
@@ -68,6 +70,8 @@
} DialProgress;
DialProgress mProgress;
+ time_t mReferSentTime;
+
DialResult mResult;
};
diff -Nru resiprocate-1.8.2/apps/sipdial/MyInviteSessionHandler.cpp resiprocate-1.8.4/apps/sipdial/MyInviteSessionHandler.cpp
--- resiprocate-1.8.2/apps/sipdial/MyInviteSessionHandler.cpp 2012-05-25 16:27:28.000000000 +0000
+++ resiprocate-1.8.4/apps/sipdial/MyInviteSessionHandler.cpp 2012-07-05 15:09:56.000000000 +0000
@@ -5,6 +5,8 @@
#include "resip/stack/SipMessage.hxx"
#include "resip/stack/Tuple.hxx"
#include "rutil/Data.hxx"
+#include "rutil/Log.hxx"
+#include "rutil/Logger.hxx"
#include "DialInstance.hxx"
#include "MyInviteSessionHandler.hxx"
@@ -12,6 +14,8 @@
using namespace resip;
using namespace std;
+#define RESIPROCATE_SUBSYSTEM resip::Subsystem::APP
+
MyInviteSessionHandler::MyInviteSessionHandler(DialInstance& dialInstance) :
mDialInstance(dialInstance)
{
@@ -23,22 +27,27 @@
void MyInviteSessionHandler::onSuccess(ClientRegistrationHandle h, const SipMessage& response)
{
+ InfoLog(<< "Unhandled method invoked");
}
void MyInviteSessionHandler::onFailure(ClientRegistrationHandle, const SipMessage& msg)
{
+ InfoLog(<< "Unhandled method invoked");
}
void MyInviteSessionHandler::onMessage(InviteSessionHandle, const resip::SipMessage& msg)
{
+ InfoLog(<< "Unhandled method invoked");
}
void MyInviteSessionHandler::onMessageSuccess(InviteSessionHandle, const resip::SipMessage&)
{
+ InfoLog(<< "Unhandled method invoked");
}
void MyInviteSessionHandler::onMessageFailure(InviteSessionHandle, const resip::SipMessage&)
{
+ InfoLog(<< "Unhandled method invoked");
}
void MyInviteSessionHandler::onFailure(ClientInviteSessionHandle cis, const SipMessage& msg)
@@ -48,18 +57,22 @@
void MyInviteSessionHandler::onForkDestroyed(ClientInviteSessionHandle)
{
+ InfoLog(<< "Unhandled method invoked");
}
void MyInviteSessionHandler::onInfoSuccess(InviteSessionHandle, const SipMessage& msg)
{
+ InfoLog(<< "Unhandled method invoked");
}
void MyInviteSessionHandler::onInfoFailure(InviteSessionHandle, const SipMessage& msg)
{
+ InfoLog(<< "Unhandled method invoked");
}
void MyInviteSessionHandler::onProvisional(ClientInviteSessionHandle cis, const SipMessage& msg)
{
+ InfoLog(<< "Unhandled method invoked");
}
void MyInviteSessionHandler::onConnected(ClientInviteSessionHandle cis, const SipMessage& msg)
@@ -72,42 +85,52 @@
void MyInviteSessionHandler::onStaleCallTimeout(ClientInviteSessionHandle)
{
+ InfoLog(<< "Unhandled method invoked");
}
void MyInviteSessionHandler::onConnected(InviteSessionHandle, const SipMessage& msg)
{
+ InfoLog(<< "Unhandled method invoked");
}
void MyInviteSessionHandler::onRedirected(ClientInviteSessionHandle, const SipMessage& msg)
{
+ InfoLog(<< "Unhandled method invoked");
}
void MyInviteSessionHandler::onAnswer(InviteSessionHandle is, const SipMessage& msg, const SdpContents& sdp)
{
+ InfoLog(<< "Unhandled method invoked");
}
void MyInviteSessionHandler::onEarlyMedia(ClientInviteSessionHandle cis, const SipMessage& msg, const SdpContents& sdp)
{
+ InfoLog(<< "Unhandled method invoked");
}
void MyInviteSessionHandler::onOfferRequired(InviteSessionHandle, const SipMessage& msg)
{
+ InfoLog(<< "Unhandled method invoked");
}
void MyInviteSessionHandler::onOfferRejected(InviteSessionHandle, const SipMessage *msg)
{
+ InfoLog(<< "Unhandled method invoked");
}
void MyInviteSessionHandler::onDialogModified(InviteSessionHandle, InviteSession::OfferAnswerType oat, const SipMessage& msg)
{
+ InfoLog(<< "Unhandled method invoked");
}
void MyInviteSessionHandler::onInfo(InviteSessionHandle, const SipMessage& msg)
{
+ InfoLog(<< "Unhandled method invoked");
}
void MyInviteSessionHandler::onRefer(InviteSessionHandle, ServerSubscriptionHandle, const SipMessage& msg)
{
+ InfoLog(<< "Unhandled method invoked");
}
void MyInviteSessionHandler::onReferAccepted(InviteSessionHandle, ClientSubscriptionHandle, const SipMessage& msg)
@@ -122,10 +145,12 @@
void MyInviteSessionHandler::onReferNoSub(InviteSessionHandle is, const resip::SipMessage& msg)
{
+ InfoLog(<< "Unhandled method invoked");
}
void MyInviteSessionHandler::onRemoved(ClientRegistrationHandle)
{
+ InfoLog(<< "Unhandled method invoked");
}
int MyInviteSessionHandler::onRequestRetry(ClientRegistrationHandle, int retrySeconds, const SipMessage& response)
@@ -135,10 +160,12 @@
void MyInviteSessionHandler::onNewSession(ServerInviteSessionHandle sis, InviteSession::OfferAnswerType oat, const SipMessage& msg)
{
+ InfoLog(<< "Unhandled method invoked");
}
void MyInviteSessionHandler::onNewSession(ClientInviteSessionHandle cis, InviteSession::OfferAnswerType oat, const SipMessage& msg)
{
+ InfoLog(<< "Unhandled method invoked");
}
void MyInviteSessionHandler::onTerminated(InviteSessionHandle is, InviteSessionHandler::TerminatedReason reason, const SipMessage* msg)
@@ -148,6 +175,7 @@
void MyInviteSessionHandler::onOffer(InviteSessionHandle is, const SipMessage& msg, const SdpContents& sdp)
{
+ InfoLog(<< "Unhandled method invoked");
}
diff -Nru resiprocate-1.8.2/apps/sipdial/README.txt resiprocate-1.8.4/apps/sipdial/README.txt
--- resiprocate-1.8.2/apps/sipdial/README.txt 2012-05-25 16:27:28.000000000 +0000
+++ resiprocate-1.8.4/apps/sipdial/README.txt 2012-07-05 15:09:56.000000000 +0000
@@ -18,7 +18,11 @@
The configuration file:
-----------------------
- The configuration file must be located in $HOME/.sipdial/sipdial.cfg
+ sipdialer looks for a configuration file located in
+ $HOME/.sipdial/sipdial.cfg
+
+ You can also specify a configuration file on the command line
+ as the second parameter (after the target URI).
You can copy the the example file included in the source
@@ -28,7 +32,8 @@
supported, and the same mechanisms may work with other phones
from the same manufacturer:
- PolycomIP501: adds the header field "AlertInfo: AA"
+ AlertInfo: adds the header field "AlertInfo: AA"
+ (this value was formerly called PolycomIP501)
LinksysSPA941: adds the attribute answer-after=0 to header Callinfo
Cisco7940: same as generic
Generic: adds no special header fields
@@ -38,28 +43,23 @@
Using TLS
---------
- sipdial expects to use TLS to security the exchange of
+ sipdial expects to use TLS to secure the exchange of
SIP REFER messages.
sipdial expects to find CA root certificates in files matching
- the pattern ~/.sipdial/certs/root_cert_*.pem
+ the pattern $HOME/.sipdial/certs/root_cert_*.pem
+ (the legacy reSIProcate SSL convention) or it can be told
+ to load all CA root certificates from a directory such
+ as /etc/ssl/certs on Debian by using the config option
+ CADirectory = /etc/ssl/certs
If multiple certificates are concatenated in a PEM file, it will only
load the first.
- To symlink all the standard root certs on a Debian system, you
- can do the following:
-
- mkdir -p ~/.sipdial/certs && \
- cd /etc/ssl/certs && \
- for i in *.pem ;
- do ln -s /etc/ssl/certs/$i ~/.sipdial/certs/root_cert_${i}
- done
-
In ~/.sipdial/sipdial.cfg, the callerUserAgentAddress must use
a sips URI:
- callerUserAgentAddress sips:mydeskphone@example.org
+ callerUserAgentAddress = sips:mydeskphone@example.org
Install in gconf:
-----------------
@@ -88,7 +88,7 @@
sipdialer tel:00442071357000
SIP addresses:
- sipdialer sip:442071357000@lvdx.com
+ sipdialer sip:helpdesk@sip5060.net
Testing with a SIP proxy:
diff -Nru resiprocate-1.8.2/apps/sipdial/sipdial.cfg resiprocate-1.8.4/apps/sipdial/sipdial.cfg
--- resiprocate-1.8.2/apps/sipdial/sipdial.cfg 2012-05-25 16:27:28.000000000 +0000
+++ resiprocate-1.8.4/apps/sipdial/sipdial.cfg 2012-07-05 15:09:56.000000000 +0000
@@ -1,10 +1,68 @@
-dialerIdentity sip:80009999@lvdx.com
-authRealm lvdx.com
-authUser 80009999
-authPassword xxx
-callerUserAgentAddress sip:80008888@lvdx.com
-callerUserAgentVariety LinksysSPA941
-targetPrefix 00
-targetDomain lvdx.com
+
+
+# the identity that sipdial should use in the SIP From
+# header for identifying itself to the SIP proxy
+# (may be the same as the callerUserAgentAddress
+# or a different value):
+dialerIdentity = sip:80009999@sip5060.net
+
+# the credentials used by sipdial to authenticate itself
+# to the SIP proxy:
+authRealm = sip5060.net
+authUser = 80009999
+authPassword = xxx
+
+# the identity of the phone that should be told to
+# make the call to the target URI (e.g.
+# the SIP address of the phone on your desk)
+callerUserAgentAddress = sip:80008888@sip5060.net
+
+# AlertInfo: adds the header field "AlertInfo: AA"
+# (this value was formerly called PolycomIP501)
+# LinksysSPA941: adds the attribute answer-after=0 to header Callinfo
+# Cisco7940: same as generic
+# Generic: adds no special header fields
+callerUserAgentVariety = LinksysSPA941
+
+# when a tel: URI is dialed with an E.164 argument
+# (a number preceded by a `+' symbol), sipdial
+# will remove the `+' symbol and replace it with the
+# `targetPrefix' string, if the string is defined,
+# if it is not defined, the dialed value is sent
+# unmodified
+targetPrefix = 00
+
+# when a tel: URI is dialed, the targetDomain value
+# will be appended to the number to create a SIP
+# address, e.g. if you dial
+#
+# tel:1234
+#
+# sipdial will dial the SIP address:
+#
+# sip:1234@targetDomain
+#
+targetDomain = sip5060.net
+
+# certPath works just like CertificatePath in repro.config
+# If NOT specified, sipdial will automatically try
+# to use $HOME/.sipdial/certs
+# Note that sipdial loads ALL root certificates found by the settings
+# CertificatePath and CADirectory. Setting one option does
+# not disable the other options.
+# Certificates in this location have to match one of the filename
+# patterns expected by the legacy reSIProcate SSL code:
+# domain_cert_NAME.pem, root_cert_NAME.pem, ...
+#certPath =
+
+# Path to load root certificates from
+# Iff this directory is specified, all files in the directory
+# will be loaded as root certificates, prefixes and suffixes are
+# not considered
+# Note that sipdial loads ALL root certificates found by the settings
+# certPath and CADirectory. Setting one option does
+# not disable the other options.
+# On Debian, the typical location is /etc/ssl/certs
+#CADirectory = /etc/ssl/certs
diff -Nru resiprocate-1.8.2/apps/sipdial/sipdialer.cpp resiprocate-1.8.4/apps/sipdial/sipdialer.cpp
--- resiprocate-1.8.2/apps/sipdial/sipdialer.cpp 2012-05-25 16:27:28.000000000 +0000
+++ resiprocate-1.8.4/apps/sipdial/sipdialer.cpp 2012-07-05 15:09:56.000000000 +0000
@@ -14,38 +14,31 @@
using namespace resip;
using namespace std;
-string getFullFilename()
+Data getFullFilename()
{
#ifdef WIN32
char *home_drive = getenv("HOMEDRIVE");
assert(home_drive); // FIXME
char *home_path = getenv("HOMEPATH");
assert(home_path); // FIXME
- string full_filename(string(home_drive) + string(home_dir) + string("\sipdial\sipdial.cfg"));
+ Data full_filename(string(home_drive) + string(home_dir) + string("\sipdial\sipdial.cfg"));
return full_filename;
#else
char *home_dir = getenv("HOME");
assert(home_dir); // FIXME
- string full_filename(string(home_dir) + string("/.sipdial/sipdial.cfg"));
+ Data full_filename(string(home_dir) + string("/.sipdial/sipdial.cfg"));
return full_filename;
#endif
}
int main(int argc, char *argv[])
{
- if(argc != 2)
- // FIXME
- assert(0);
-
- DialerConfiguration *dc = new DialerConfiguration();
- ifstream in(getFullFilename().c_str());
- if(!in.is_open())
- assert(0); // FIXME
+ Data defaultConfig(getFullFilename());
+ DialerConfiguration dc(argc, argv, defaultConfig, 1);
- dc->loadStream(in);
- in.close();
+ Data targetUri(argv[1]);
- DialInstance di(*dc, Uri(Data(argv[1])));
+ DialInstance di(dc, Uri(targetUri));
di.execute();
}
diff -Nru resiprocate-1.8.2/apps/sipdial/todo.txt resiprocate-1.8.4/apps/sipdial/todo.txt
--- resiprocate-1.8.2/apps/sipdial/todo.txt 2012-05-25 16:27:28.000000000 +0000
+++ resiprocate-1.8.4/apps/sipdial/todo.txt 2012-07-05 15:09:56.000000000 +0000
@@ -1,15 +1,12 @@
-Ensure that app does not keep running
-Generalise config options (e.g. PolycomIP501 rename to AlertInfo)
+Make the REFER_TIMEOUT logic more robust and report errors in a more useful way
+Generalise config options (e.g. rename Cisco7940)
Configurable protocol selection (UDP, TCP or TLS)
-Configurable cert dir location
Better cert loading algorithm (also fix for repro)
UDP: Must pick random SIP port
Look in /etc/sipdial for
- global config settings, overlay with local settings
- certs
-Specify config file on command line or environment variable
-Support comments in config file (using rutil/ConfigParse class)
Correct SDP generation (some phones don't work well without any SDP)
Remove FIXMEs
Create a namespace
diff -Nru resiprocate-1.8.2/ChangeLog resiprocate-1.8.4/ChangeLog
--- resiprocate-1.8.2/ChangeLog 1970-01-01 00:00:00.000000000 +0000
+++ resiprocate-1.8.4/ChangeLog 2012-07-05 15:12:17.000000000 +0000
@@ -0,0 +1,340 @@
+= Release Notes v 1.8 =
+
+==General==
+===New features===
+*added new REND project for for Registration and Presence load testing
+
+
+==Build system==
+===New features===
+*the old build system was completely replaced with an autotools build system
+*many components are now optional and must be enabled at configure time
+*autotools dist functionality now used to produce official release tarball
+*libtool now sets SONAME using the release number convention
+*resip now builds on Solaris SunPro (tested with third-party libs from OpenCSW)
+*update BerkeleyDb to 4.8 in contrib
+*added MaxMind GeoIP library to contrib
+*added MySQL client connector library to contrib
+*allow resip's asio drop to build with OpenSSL 1.0 and above
+*allow testStack to use popt for VS2010 projects
+
+===Bug fixes===
+*fixed many compilation errors and warnings on various platforms
+
+
+==rutil==
+===New features===
+*added Timer::resetT1 to make it easier to tweak T1
+*added ConfigParse class to aid with configuration file and command line parsing
+*Data class enhancements
+**made Data class smaller, without sacrificing functionality. Data is 20 (56 vs 36) bytes smaller on 64-bit libs, and 4 (36 vs 32) bytes smaller on 32-bit libs.
+**several very simple functions have been inlined.
+**Data::md5() has been changed to Data::md5(Data::EncodingType type=HEX); this allows the output of md5() to be encoded as hex or Base64, or not encoded at all (binary).
+**Data::replace(const Data& match, const Data& target) has been updated to Data::replace(const Data& match, const Data& target, int max=INT_MAX); this allows the maximum number of replacements to be specified.
+**specialized hashing and comparison functions have been added:
+***Data::caseInsensitiveTokenHash(); this is a case-insensitive hash that assumes that the Data is an RFC 3261 token (eg; branch params). This hash function is based on the Hsieh hash.
+***bool Data::caseInsensitiveTokenCompare(const Data& rhs); this is an equality comparison that assumes that both Datas are RFC 3261 tokens (eg; branch parameters) and is faster than strncasecmp().
+**Data& schemeLowercase(); this is an optimized variant of lowercase() that assumes the Data is an RFC 3261 scheme.
+*performance improvements to ParseBuffer
+**most functions that returned a Pointer now return a much more lightweight CurrentPosition object.
+**allow some of the simpler functions to be inlined
+**integer parsing code is more efficient, and overflow detection is better
+*performance enhancements to DnsUtil
+**DnsUtil::inet_ntop(): For some reason, the stock system inet_ntop is dreadfully inefficient on OS X. A dirt-simple hand-rolled implementation was 5-6 times as fast. This is shocking. The Linux implementation is plenty efficient, though, so we're using preprocessor to activate the hand-rolled code.
+**DnsUtil::isIpV4Address(): The implementation uses sscanf(), which is pretty expensive. Hand-rolled some code that is much faster.
+*moved XMLCursor class from resip/stack to rutil
+*custom ares build was moved from /contrib/ares to /rutil/dns/ares, since it is a heavily customize version of the ares library - building with c-ares as an alternative is still possible
+*added new ServerProcess class to encapsulate method for daemonizing and other server/daemon requirements like PID files
+*added new KeyValueStore class for highly efficient generic storage
+**keys are simple integer indexes into a vector and must be allocated before they are used
+**currently supports storage and retrieval of the following types: Data, bool, short, unsigned short, int, unsigned int, and UInt64
+*added Inserter functionality for collections that store pointers to items. Use InserterP instead of Inserter for such collections.
+
+===Bug fixes===
+*fixed a Windows API issue with ThreadLocalStorage. The Windows API functions for TLS do not guarantee that the id / index number will be less than 1088. Change the code to use a std::map<DWORD> instead of a fixed size array. The previous code would cause heap corruption if the OS passed back an index number of 1088.
+*fixed a bad assert in Random class - we shouldn't be using RAND_MAX to look at what is returned by random()
+*fix bug in Data. If Data is wrapping memory allocated externally (ie. Share mode = BORROW) and you start appending to it. It is possible that the append method will write a NULL character off the end of the buffer. Changed the resize condition to make the buffer larger 1 character sooner, to accommodate for this.
+*fix for IPv6 - If localhost is used at init time, then IP family wasn't properly populated in ares
+*fix for IPv6 - If DNS servers are reached over IPv6, then they were not printed to the logs correctly
+
+
+==stack==
+===New features===
+*the various parameter types now have their scope restricted to the grammar element/s for which they are defined, instead of having them all be equally valid for all grammar elements.
+*added two new flags added to MessageDecorators that instruct the stack to copy the decorator from the INVITE request to any resulting stack generated CANCEL requests or ACK failure requests. This functionality was added so that it is possible to decorate all request messaging on the wire.
+*enhanced the MarkListener class to allow control over the DNS Grey / Black list. The onMark function is now called before insertion to the list and you can now change the expiry value to 0 if you don't want the entry added to the grey/black list, or change the amount of time it is on the list.
+*reduced the memory footprint associated with storing URIs
+*change how branch parameters are encoded.
+**old format: z9hG4bK-d8754z-<branch>-<transportseq>-<clientData>-<sigcompCompartment>-d8754z-
+**new Format: z9hG4bK-524287-<transportseq>-<clientData>-<sigcompComprtment>-<branch>
+***this format encodes faster, parses faster (with _much_ simpler code), and takes up less space on the wire.
+**some other small optimizations; avoid copies associated with calling Data::base64encode()/base64decode() on empty Datas, and reorder the SIP cookie comparisons to be more efficient.
+*reduced the memory consumed by storing TransationState
+*reduction in buffer reallocations while encoding a SipMessage
+*added multiple threads in the stack. Allow transaction processing, transport processing, and DNS processing to be broken off into separate threads.
+**SipStack::run() causes the creation and run of three threads; a TransactionControllerThread, and TransportSelectorThread, and a DnsThread. You continue to use stuff like StackThread and EventStackThread to give cycles to the rest of the stack (mainly processing app timers and statistics logging). In other words, to use the new multi-threaded mode, all you have to do is throw in a call to SipStack::run() before you fire up your normal SipStack processing, and a SipStack::shutdownAndJoinThreads() when you're done.
+**in the Connection read/write code, process reads/writes until EAGAIN, or we run out of stuff to send. Gives a healthy performance boost on connection-based transports.
+**in TransactionController, put transaction timers in their own fifo. This prevents timers from firing late when the state machine fifo gets congested.
+**process at most 16 TransactionMessages from the state machine fifo at a time, to prevent starving other parts of the system.
+**unhook the TransactionController's processing loop from that of the TransportSelector. This simplifies this API considerably, but required the addition of a new feature to Fifo. Fifo can now take an (optional) AsyncProcessHandler* that will be notified when the fifo goes from empty to non-empty. Actually pretty useful.
+**allow setPollGrp() to be called multiple times on the various classes that have this function. This allows the FdPollGrp to be re-set when the SipStack enters multithreaded mode.
+**added a "multithreadedstack" --thread-type option to testStack. Exercise this option in testStackStd.sh
+**added the ability to run any of the existing Transport objects in their own thread, by a combination of a new transport flag (RESIP_TRANSPORT_FLAG_OWNTHREAD), and a new TransportThread class. Added support for this mode to testStack using the --tf option. Also exercised this feature in testStackStd.sh.
+**installed SelectInterruptors at the TransportSelector, each Transport object, and the DnsStub (this last one required moving SelectInterruptor to rutil). This is critical to making multithreaded mode work in a performant manner, and imposes almost no performance penalty due to the way they are invoked.
+**SipStack now creates its own SelectInterruptor if one is not supplied externally. This is because it is critical to be able to wake the TransactionController up when new work comes down from the TU, or from the transports.
+*new congestion-management framework
+**allow testStack, tfm/repro/sanityTests, and repro to be run with a congestion manager via a configuration flag.
+**efficient wait-time estimation in AbstractFifo; keeps track of how rapidly messages are consumed, allowing good estimates of how long a new message will take to be serviced. More efficient than the time-depth logic in TimeLimitFifo, and a better predictor too.
+**the ability to shed load at the transport level when the TransactionController is congested, in a very efficient manner, using new functionality in Helper and SipMessage (Helper::makeRawResponse() and SipMessage::encodeSingleHeader())
+**the ability to shed load coming from the TU when the TransactionController is congested. This is crucial when congestion is being caused by a TU trying to do too much.
+**changed the way load-shedding is handled for TransactionUsers to use the new API
+**a flexible congestion-management API, allowing load-shedding decisions to be made in an arbitrary fashion.
+**a generalized CongestionManager implementation that is powerful enough to be useful.
+**the TransactionController will now defer retransmissions of requests if sufficiently congested (ie; the response is probably stuck in mStateMacFifo)
+*the TransactionController now determines its hostname with a single call to DnsUtil::getLocalHostName() on construction, for use in 503s. Previously, it would make this call every time a 503 was sent; this call blocks sometimes!
+*don't call DnsResult::blacklistLast() on a Retry-After: 0
+*several fixes for the processing loop in testStack that were causing starvation of one type of work or another when congestion occurred.
+*small efficiency improvement in Random::getCryptoRandom(int) Random::getCryptoRandom(unsigned int len) was implemented by calling Random::getCryptoRandom() repeatedly, and collecting the return values in a buffer. In the openssl case, we now use a single call to RAND_bytes().
+*use a priority_queue instead of a multiset for storing timers.
+*slight refactoring of Timer so that transaction timers and payload timers (ie; timers that carry a Message*) are a separate classes. Transaction timers no longer have an unused Message* member, and payload timers no longer have the unused transaction-id, Timer::Type, and duration. This saves a _lot_ of memory for apps that use lots of app timers with long lifetimes.
+*less wasteful population of Call-IDs: When generating Call-IDs, Helper was computing an md5 hash of the hostname and some salt, hex-encoding it, and then Base64 encoding the hex data. We now Base64 encode the md5 hash directly. This is less computationally expensive, requires less memory because the resulting string is half the size, and requires fewer bytes on the wire.
+*make TransactionMap case-insensitive; Data::caseInsensitiveTokenHash() is fast enough that performance actually increases a little.
+*std::bitset-based parsing in a number of places for improved performance
+*don't check whether the encoding tables are initted for every single character; check once before the encode operation begins. Also, checking the value of a static bool to determine whether an init has been carried out is pointless; that bool might not be initted yet, and it could have any value. The static init code now copes with both accesses to the encoding tables during static initialization, and from multiple threads during runtime.
+*don't bother generating a transaction identifier unless the parse fails to extract one.
+*some refactoring of the FdPollGrp stuff. Now is compatible with cares, using a bit of a hack. Also compatible with being driven with the old buildFdSet()/select()/process(FdSet&) call sequence, although this is now deprecated. Fixing these compatibility problems allowed us to switch over to using FdPollGrp in all cases, instead of having dual mode everywhere.
+*buffer classes for Fifo to reduce lock contention. Using them in a few places, will use them in more once we phase out TimeLimitFifo with the new congestion management code.
+*use the --ignore-case option for generation of ParameterHash.cxx, instead of the nasty sed rewriting we are using now. Should also be slightly faster, since gperf handles case-insensitive hashing more efficiently than our hack was.
+*added a local memory pool to SipMessage, to cut down (dramatically) on heap allocation overhead. Some minor refactoring to free up wasted space in SipMessage as well (makes more room for the pool). Changing the way the start-line is stored to no longer use a full-blown ParserContainer+ HeaderFieldValueList.
+*added method to SipStack to be able to retrieve a dump of the DNS cache
+*added operator<< for Statistics Payload
+*allow SipStack statistics to be reset/zero'd out
+*modified GetStackStats command to be able to retrieve statistics that are accurate at the time of the request, instead of just returning the statistics as of the last statistics interval
+*added a new method to SipStack so that you can post to TU without needing to clone/copy the message
+*tls: add support for loading a directory of root certificates or a file containing a bundle of roort certificates
+*tls: support for mutual TLS/client certificate verification
+*tls: optional facility to accept email address subjectAltNames as if they were SIP URIs
+*added new Helper method: Tuple getClientPublicAddress(const SipMessage& request) - look at Via headers, and finds the first public IP address closest to the sending client.
+*renamed Helper::isSenderBehindNAT to isClientBehindNAT for consistency
+*allow a DateCategory to be created from time_t
+*allow transport type be pre-populated in a via header to force the stack to use a particular transport type (ie. UDP, TCP, TLS)
+
+===Bug fixes===
+*fix for testStack running on OS X
+*fixed issue where resiprocate would encode headers that are not directly modified, potentially causing header formatting to change where there is a difference in resip encoding vs received encoding.
+**modified LazyParser to encode from the raw HeaderFieldValue if it has not been modified (or at least, the non-const version of checkParsed() has not been called).
+**added SipMessage::const_header for the various header types, to allow explicit const-only access with a non-const SipMessage
+**use this const_header function in a number of places where we do not want the LazyParser marking itself as "dirty".
+*fixed a bug in URI parsing code when an @ or : appeared in a quoted parameter
+*fix for DtlsTransport - fix in _doHandshake(), switch must be done on SSL_get_error() return value
+*fixed a static initialization race with the Uri encoding tables
+*fix for missing statistics in output string for stack statistics
+*fix possible memory corruption in SdpContents::Session::Medium::codecs() due to Codec::parse() and the Medium's AttributeHelper, the AttributeHelper free's up the memory that was used by parse()
+*fix to make nc (nonce count) lowercase, per definition of LHEX in RFC2831
+*use getaddrinfo() instead of the non-threadsafe gethostbyname().
+*remove unused (and non-threadsafe) Timer::mTimerCount/Timer::mId.
+*get rid of a wasteful double-encode, in Message.cxx
+*fixed a nasty bug in NameAddr - where unknown parameters uri parameters on a NameAddr/Uri with no angle brackets are treated as NameAddr parameters. When this is done, the memory for these parameters was only a temporary Data object.
+*resip TCP transports can crash repro on uncaught exception - if garbage is received on the socket, and there is no Content-Length header, then SipMessage::Exception can throw, and it was not caught with the existing ParseException catch handler. Changed to catch BaseException instead.
+*fixed possible assert if a transport error is seen after trying to send an ACK message
+*added TlsDestructorInitializer as a field to LogStaticInitializer in order to make sure an instance of TlsDestructorInitializer is created before LogStaticInitializer is initialized
+*removed print in TcpConnection that could end up printing garbage at the end of messages that are not null terminated
+*added loopback address checking to Tuple::isPrivateAddress
+*fixed a bad value passed to the macro RESIP_HeapCount in KeepAlivePong.h
+
+
+==DUM==
+===New features===
+*added a getRequest() method to ClientOutOfDialogReq so that the request for the response can be accessed
+*implemented InviteSession::reject while in the SentReinviteAnswered state. This is useful when needing to reject with an empty ACK an offer that was requested (using an empty INVITE) while in a dialog.
+*added ability to asynchronously end an AppDialogSet using AppDialogSet::endCommand.
+*added new public APIs to DialogUsageManager so that the application can find AppDialogs/AppDialogSets from a DialogId or a DialogSetId. This is useful if the application wants to find a dialog set from a SIP message alone.
+*added the ability to end a publication without sending a final PUBLISH with an expires of 0
+*modified client subscription to allow a subscription to be terminated without sending a final SUBSCRIBE request, useful in cases where an extension Subscription-State is used that signifies that the subscription is terminated
+*added ServerAuthManager support for UA's who set auth username="user@domain" rather than username="user"
+*support for mutual TLS/client certificate verification (as DUM feature)
+*enhanced ServerRegistration:
+**ensure that ContactInstanceRecord::mReceivedFrom is always populated - not just in outbound use cases - added a new flag to indicate when flow routing is required
+**added a new mPublicAddress flag member to ContactInstanceRecord - to assist repro feature to do geo proximity routing
+*test/basicClient - allow subscription and call if not registering
+
+===Bug fixes===
+*fixed a bug where we were using a description parameter in a Reason header, instead of a text parameter
+*fixed incorrect assert in ServerSubscription due to missing break statement
+*removed unsafe logging statement in DumTimeout - if DUM and stack are in different threads, then crash could occur
+*fixed a bug where the CSeq can be wrong in a client subscription re-subscribe / refresh in the case where we receive the first NOTIFY before the 200/SUB response
+*dum/test/basicClient - fixed a trap during shutdown, due to order of destructed objects
+*fixed a bug when using the registration sync mechanism - the ServerRegistration onRefresh callback could be incorrectly generated instead of the onAdd callback when a registration is added, due to the record lingering in memory
+
+
+==repro==
+===New features===
+*added new configuration mechanism for repro
+**removed use of popt, now using a new name/value pair approach (using new rutil/ConfigParser classs) to read settings from a .config file
+**allows command line options - but is not backwards compatible with old popt command line format
+*added a new Command interface/server to repro that operates over a TCP socket and uses XML formatted messaging. Supporting the following commands:
+**GetStackInfo
+**GetStackStats
+**ResetStackStats
+**LogDnsCache
+**ClearDnsCache
+**GetDnsCache
+**GetCongestionStats
+**SetCongestionTolerance
+**Shutdown
+**Restart
+**GetProxyConfig
+*added new reprocmd executable that connects to repro via new command socket server and sends commands based on command line arguments
+*upgraded the MySQL support in repro to a deployable state
+**allow MySQL connection parameters to be specified in repro config
+**cleaned up MySQL initialization, so we fail to start if there is a db connect error
+**remove all generic throws from MySQL implementation
+**implemented MySQL connection recovery on errors - when connection errors occur on query, try to re-connect immediately (once)
+**optimized query building in MySQLDb class
+**added ability for repro.config to provide a select statement that allows a1 password retrieval from an arbitrary database table on the MySQL server
+**added .sql script to create repro tables on MySQL
+**added a singleResultQuery API to MySqlDb
+**added my sql implementation of AVPs (attribute-value-pair) with two indexes/attributes
+**increase MySQL AVP (attribute-value-pair) table size for value field from 1024 to 4096
+**modifications to make MySQL client use properly protected for multi-threaded access - refuse to start if linked with mysql library that doesn't support multi-threading
+**use CLIENT_MULTI_RESULTS flag when opening mysql database (enables multiple results, since some custom stored procedures might require this)
+*add ability for a repro admin to add manual / permanent registrations (including Path information) - such manually added registrations are persisted to the database, and loaded at startup - manual registrations can be added on the Registration Web Page
+*added new Baboon: GeoProximityTargetSorter - If enabled, then this baboon can post-process the target list. This includes targets from the StaticRoute monkey and/or targets from the LocationServer monkey. Requests that meet the filter criteria will have their Target list, flatened (serialized) and ordered based on the proximity of the target to the client sending the request. Proximity is determined by looking for a x-repro-geolocation="<latitude>,<longitude>" parameter on the Contact header of a received request, or the Contact headers of Registration requests. If this parameter is not found, then this processor will attempt to determine the public IP address closest to the client or target and use the MaxMind Geo IP library to lookup the geo location.
+*added new RequestFilter monkey
+**allows user to configure conditions under which an inbound request should be rejected or not
+**allows two regular expression conditions that can be applied to any SIP message header: this includes the request-line, standard SIP headers and custom SIP headers. If a header that can appear multiple time is specified, then each instance of the header is checked.
+**When conditions are met, allows the action carried out to be defined:
+***Accept - accepts this request and stops further processing in Request Filter monkey
+***Reject - rejects this request with the provided SIP status code and reason text
+***SQL query - only available when MySQL support is compiled in - runs an arbitrary stored procedure or query, using replacement strings from the 2 condition regular expressions
+****query must return an empty string or "0" to instruct repro to Accept the request, or a string containing "<SIP Reject Status Code>[, <SIP Reject Reason>]" to Reject the request
+****using the repro configuration file the SQL Query can be configured to operate on a completely different mySQL instance/server than the repro configuration
+**filters are defined in the HTTP web interface via new Add Filter, Edit Filter and Show Filters web pages. There is an ability to test the condition regular expressions from the web page as well.
+**other Monkey settings are configured in the repro configuration file or via command line: DisableRequestFilterProcessor, RequestFilterDefaultNoMatchBehavior, RequestFilterDefaultDBErrorBehavior, RequestFilterMySQLServer (and other mySQL related settings)
+**can be used to implement a User Blocking functionality - ie. calls and instant messages from user X to user Y should always be blocked, because user X is in user Y's block list
+**introduced new FilterStore configuration database table to store the Filters configured on the web pages
+*added optional MessageSilo support to repro
+**stores IM's (ie. SIP MESSAGE requests) for offline users
+**replays messages to users when they register (ie. come back online)
+**records are persisted to a database table, so they survive shutdowns
+**configurable filters exist for DestUri, MimeType, MessageBody size
+*Web Admin GUI improvements
+**made use of HTML tables consistent across all web interfaces pages
+**made table backgrounds white to improved appearance
+**added title to right hand side pane
+**cleaned up formatting on many pages
+**added warning to Domains page, that repro must be restarted
+**added bottom banner with link to www.resiprocate.org
+**added repro version display on top banner
+**added new Settings page to repro web interface to show current command line / files settings in use - will also display some some low level stack info, congestion stats (if enabled), and the contents of the DNS cache
+**added Clear DNS Cache button to settings page
+**added Restart Proxy button to settings page (reloads everything, applies new configuration, but keeps in memory registration table)
+**added display of registered contact's QValue on registrations web page
+**Routes: stop webpage from being able to add two routes with the same Key, optimized data fetch for displaying routes on web page
+**propagate db insert/update failures to callers - web interface now shows errors if record fails to update in db
+*added an ability to configure a different database instance for some of the repro database tables. New configuration file settings, RuntimeMySQLServer and it's subsettings, were added to facilitate this. The Users and MessageSilo database tables are different from the other repro configuration database tables, in that they are accessed at runtime as SIP requests arrive. It may be desirable to use BerkeleyDb for the other repro tables (which are read at starup time, then cached in memory), and MySQL for the runtime accessed tables; or two separate MySQL instances for these different table sets. The new configuration settings allow you to achieve this.
+*added option to enable some basic P-Asserted-Identity header handling
+**After auth is successful
+***if P-Perferred-Identity header is present remove it
+***if no P-Asserted-Identity header is present, then add one
+**Removal of P-Asserted-Identity if Privacy header is set to "id"
+***Note: Since we have no better mechanism to determine if destination is trusted or not we assume that all destinations outside our domain are not-trusted and will remove the P-Asserted-Identity header
+*added ability for repro to report a 404 error when attempting to reach a user that does not exist - previously repro would always send a 480 response when attempting to reach an AOR that wasn't registered
+*major changes to how repro is started up, to allow easier additions of custom startup logic, such as adding custom Processors (Monkeys, Lemurs and Baboons) to the default Processor chains
+**almost all logic that was in repro.cxx has been moved out to a new class (ReproRunner), and split into smaller virtual methods that can be overridden
+**see comments at the top of repro.cxx for an example of how to add custom processors
+*add support for daemonizing on platforms supporting fork()
+*added ability to create a UNIX PID file on startup
+*add support for loading a directory of root certificates or a file containing a bundle of root certificates
+*support for mutual TLS/client certificate verification (as repro monkey)
+*tls: config option to accept email address subjectAltNames as if they were SIP URIs
+*added congestion manager settings to be configured in repro configuration file
+*added KeyValueStore to three strategic locations in repro, allowing custom Processors (Monkeys, Lemurs and Baboons) to store state scoped as follows:
+**Global Proxy Scope - Proxy::getKeyValueStore
+**Request Scope - RequestContext::getKeyValueStore
+**Target Scope - Target::getKeyValueStore
+**Before this storage can be used you must statically allocate a storage key. See mFromTrustedNodeKey use in the IsTrustedNode class for an example.
+*implemented proper q-value processing of contacts in a redirect response
+*modified repro so that Registration authentication uses the same pool of worker threads that the DigestAuthenticator uses when looking up credentials from the database. Previously only auth look ups for non-REGISTER requests (ie. INVITE, SUBSCRIBE, etc.) would be done in a manner that didn't block inbound message processing. A lengthy auth check for a REGISTER request would cause delays in processing all other REGISTER requests.
+*allow custom repro implementations to add themselves to the RegistrarHandler so that registration messages can be processed and reacted to
+*added abililty to tweak timer T1 in repro configuration
+*allow specifying a ;lr flag on static routes to perform loose routing, instead of re-writing the request URI
+*modified repro to allow an application overridden RequestContext to be able to provide a virtual fn for cancelClientTransaction
+*added resip ExternalLogger to repro, so that Error logs are also logged to the console when file logging is enabled
+*added some new configuration settings: LogFileName, LogFileMaxBytes
+*made the number of worker threads in the repro authgrabber dispatcher configurable via the repro configuration file
+*modified UserAuthGrabber to use UserStore::getUserAuthInfo, instead of UserStore::getUserInfo API - we don't use the other fields retrieved, so this will provide an optimization
+*optimized the Worker thread to avoid making a copy of the Message when posting to the stack
+*added new config setting StatisticsLogInterval to specify how often statistics are dumped to the log files
+*added two new constructors to QValueTarget to make is easier to form targets from a NameAddr or Uri only
+*renamed Target::targetPtrCompare to Target::priorityMetricCompare to be more descriptive
+*cleanup some old hacks now that we have the ability to manually add registrations
+**ParallelForkStaticRoutes no longer combines StaticRoutes Targets and LocationServer Targets
+**static Routes are no longer added as QValueTargets, they are now added as simple Targets. So they are no longer susceptible to the various QValue Settings - ie. QValueMsBeforeCancel.
+**added new ContinueProcessingAfterRoutesFound setting: By default (false) we will stop looking for more Targets if we have found matching routes. Setting this value to true will allow the LocationServer Monkey to run after StaticRoutes have been found. In this case the matching StaticRoutes become fallback targets, processed only after all location server Targets fail.
+*cleaned up Processor and ProcessorChain classes
+**added mName property in anticipation of a future capability to define processor chains in the configuration file
+**simplified operator<< for processors, to use Name
+*added a series of interfaces to make is easier to implement new Asynchronous Monkey's / Processors that utilize a common thread pool
+*removed getTransactionId from ForkControlMessage - method exists on base class, so it's not needed
+*removed getTransactionId and tid() from UserInfoMessage - getTransactionId method exists on base class, so they are not needed
+*added AsyncProcessorDispatcher / thread pool to repro that be shared by all AsyncProcessors - currently used by new RequestFilter and Message Silo monkeys
+*cleaned up some implementation in AbstractDb to remove some code duplication
+*remove unused AbstractDb API's: writeRoute and writeFilter
+*added ability for tables to have non-unique keys (ie. duplicate records)
+*added secondary database support to BerkeleyDb - allows tables with a secondary index
+*optimized data copies when reading records from BerkeleyDb
+*modified WorkerThread to support work that does not require a response to be queued back to the stack
+*added database transaction support to BerekelyDb and MySQL implementations
+*removed unused SipStack parameter to DigestAuthenticator monkey
+*option to enforce the requirement of a client certificate for third party domains
+*added new repro setting to assume that first hop supports outbound
+*support for storing passwordHashAlt - changes users schema and users db version. passwordHashAlt can be used with MySQLCustomUserAuthQuery, in future it will work seamlessly in conjunction with passwordHash
+*avoid unnecessary iteration through target list in StaticRoute when try to determine if auth is required
+*removed some unused code in ResponseContext: addOutboundBatch and mOutboundMap
+
+===Bug fixes===
+*fix for a long standing issue in repro that started in rev6794, where repro can be over protective and issue 403 responses for legitimate mid-dialog requests. The issue occurs when a repro domain user forms a dialog with a user in another external domain. Any mid-dialog requests coming from the external domain would get 403'd. This was due to the logic in the AmIResponsible monkey, and the fact that such requests have the repro endpoints contact address in the RequestUri (typically the endpoints IP address), so not belonging to repro's domain, and the From user is not being from repro's domain.
+*fix a bug in repro web interface, where fragmented HTTP messages were not being handled correctly
+
+
+==reTurn==
+===New features===
+*reTurnServer: read config settings from reTurnServer.config instead of using hard coded values
+*add support for daemonizing on platforms supporting fork()
+*log error in UdpServer if failure to bind
+*add StackLog logging of request type when encoding a message
+*added a man page for reTurnServer
+*added ability to create a UNIX PID file on startup
+*return server - suppress socket errors when closing relay
+
+===Bug fixes===
+*fixed problem where classic stun responses come from the wrong socket
+*ensure asio doesn't throw exceptions under error conditions
+*added missing request type TurnCreatePermissionMethod to operator<<
+*log hex() version of HMAC keys, since they are binary
+*client API: TurnSocket - ensure we are connected before allowing send
+*client API: Remove warning about 'this' use in initiator list - pointer is only stored
+*client API: Increase allowed send size from 1024 bytes to 2048
+*client API: fix potential memory leak with mActiveRequestMap (TurnAsyncSocket class)
+*client API: ensure retrans timer is stopped when request is removed from map
+
+
+==tfm (repro)==
+===New features===
+*added VS2008 project files for Windows
+*move tfm/contrib items to top level contrib directory
+*make file logging the default on tfm, since console logging blocks the run too much
+
+===Bug fixes===
+*adjust some timeout values so that tests will pass on slower systems
+
+
+==tfm (dum)==
+===Bug fixes===
+*fixed a place where a NameAddr param (methods) was being used as a Uri param
+
+
+==apps/sipdial==
+===New features===
+*add support for TLS and sips uri scheme
diff -Nru resiprocate-1.8.2/configure resiprocate-1.8.4/configure
--- resiprocate-1.8.2/configure 2012-05-25 16:33:37.000000000 +0000
+++ resiprocate-1.8.4/configure 2012-07-05 15:15:44.000000000 +0000
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.67 for resiprocate 1.8.2.
+# Generated by GNU Autoconf 2.67 for resiprocate 1.8.4.
#
#
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
@@ -698,8 +698,8 @@
# Identity of this package.
PACKAGE_NAME='resiprocate'
PACKAGE_TARNAME='resiprocate'
-PACKAGE_VERSION='1.8.2'
-PACKAGE_STRING='resiprocate 1.8.2'
+PACKAGE_VERSION='1.8.4'
+PACKAGE_STRING='resiprocate 1.8.4'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
@@ -1476,7 +1476,7 @@
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures resiprocate 1.8.2 to adapt to many kinds of systems.
+\`configure' configures resiprocate 1.8.4 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1546,7 +1546,7 @@
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of resiprocate 1.8.2:";;
+ short | recursive ) echo "Configuration of resiprocate 1.8.4:";;
esac
cat <<\_ACEOF
@@ -1665,7 +1665,7 @@
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-resiprocate configure 1.8.2
+resiprocate configure 1.8.4
generated by GNU Autoconf 2.67
Copyright (C) 2010 Free Software Foundation, Inc.
@@ -2208,7 +2208,7 @@
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by resiprocate $as_me 1.8.2, which was
+It was created by resiprocate $as_me 1.8.4, which was
generated by GNU Autoconf 2.67. Invocation command line was
$ $0 $@
@@ -3036,7 +3036,7 @@
# Define the identity of the package.
PACKAGE='resiprocate'
- VERSION='1.8.2'
+ VERSION='1.8.4'
cat >>confdefs.h <<_ACEOF
@@ -16342,7 +16342,7 @@
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by resiprocate $as_me 1.8.2, which was
+This file was extended by resiprocate $as_me 1.8.4, which was
generated by GNU Autoconf 2.67. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -16408,7 +16408,7 @@
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-resiprocate config.status 1.8.2
+resiprocate config.status 1.8.4
configured by $0, generated by GNU Autoconf 2.67,
with options \\"\$ac_cs_config\\"
diff -Nru resiprocate-1.8.2/configure.ac resiprocate-1.8.4/configure.ac
--- resiprocate-1.8.2/configure.ac 2012-05-25 16:27:29.000000000 +0000
+++ resiprocate-1.8.4/configure.ac 2012-07-05 15:12:17.000000000 +0000
@@ -1,5 +1,5 @@
-AC_INIT(resiprocate,1.8.2)
+AC_INIT(resiprocate,1.8.4)
AC_CONFIG_SRCDIR(repro/repro.cxx)
SO_RELEASE=`echo $PACKAGE_VERSION | cut -f1,2 -d.`
diff -Nru resiprocate-1.8.2/debian/changelog resiprocate-1.8.4/debian/changelog
--- resiprocate-1.8.2/debian/changelog 2012-05-25 17:32:22.000000000 +0000
+++ resiprocate-1.8.4/debian/changelog 2012-07-13 22:32:24.000000000 +0000
@@ -1,3 +1,12 @@
+resiprocate (1.8.4-1) unstable; urgency=low
+
+ * New upstream release
+ * Make sure repro hashed passwords are not world readable
+ * Remove /var/lib/repro on purge (Closes: #675273)
+ * Delay in postrm in case process hasn't finished stopping
+
+ -- Daniel Pocock <daniel@pocock.com.au> Sat, 14 Jul 2012 00:30:10 +0200
+
resiprocate (1.8.2-1) unstable; urgency=low
* Initial release (Closes: #412427)
diff -Nru resiprocate-1.8.2/debian/repro.docs resiprocate-1.8.4/debian/repro.docs
--- resiprocate-1.8.2/debian/repro.docs 2012-05-20 17:01:03.000000000 +0000
+++ resiprocate-1.8.4/debian/repro.docs 2012-05-25 22:20:58.000000000 +0000
@@ -1 +1,2 @@
repro/README_MySQL.txt
+repro/create_mysql_reprodb.sql
diff -Nru resiprocate-1.8.2/debian/repro.install resiprocate-1.8.4/debian/repro.install
--- resiprocate-1.8.2/debian/repro.install 2012-05-23 12:06:19.000000000 +0000
+++ resiprocate-1.8.4/debian/repro.install 2012-05-25 22:21:04.000000000 +0000
@@ -2,4 +2,3 @@
usr/sbin/repro
usr/sbin/reprocmd
debian/conf/repro.config etc/repro
-repro/create_mysql_reprodb.sql usr/share/doc/repro
diff -Nru resiprocate-1.8.2/debian/repro.lintian-overrides resiprocate-1.8.4/debian/repro.lintian-overrides
--- resiprocate-1.8.2/debian/repro.lintian-overrides 2012-05-22 12:12:17.000000000 +0000
+++ resiprocate-1.8.4/debian/repro.lintian-overrides 2012-05-28 13:36:30.000000000 +0000
@@ -4,3 +4,5 @@
repro binary: possible-gpl-code-linked-with-openssl
# this is needed because of bug #673112
repro binary: hardening-no-fortify-functions
+# repro db files contain passwords, can't be world readable
+repro binary: non-standard-dir-perm
diff -Nru resiprocate-1.8.2/debian/repro.postinst resiprocate-1.8.4/debian/repro.postinst
--- resiprocate-1.8.2/debian/repro.postinst 2012-05-22 15:53:03.000000000 +0000
+++ resiprocate-1.8.4/debian/repro.postinst 2012-05-28 13:34:59.000000000 +0000
@@ -43,6 +43,7 @@
then
mkdir -p ${REPRO_HOME} || exit 1
chown ${REPRO_USER}:${REPRO_GROUP} "${REPRO_HOME}"
+ chmod 0700 "${REPRO_HOME}"
fi
}
diff -Nru resiprocate-1.8.2/debian/repro.postrm resiprocate-1.8.4/debian/repro.postrm
--- resiprocate-1.8.2/debian/repro.postrm 2012-05-20 18:43:19.000000000 +0000
+++ resiprocate-1.8.4/debian/repro.postrm 2012-05-28 13:52:39.000000000 +0000
@@ -3,6 +3,17 @@
set -e
if [ "$1" = "purge" ] ; then
+
+ # wait in case process still shutting down...
+ echo "Waiting for process to stop..."
+ sleep 8
+
+ # MySQL uses debconf to get user confirmation before
+ # wiping it's lib database directory, a similar
+ # approach might be desirable for repro
+ rm -rf /var/lib/repro
+ rm -rf /var/run/repro
+
if getent passwd repro >/dev/null; then
userdel repro
fi
diff -Nru resiprocate-1.8.2/Makefile.in resiprocate-1.8.4/Makefile.in
--- resiprocate-1.8.2/Makefile.in 2012-05-25 16:33:40.000000000 +0000
+++ resiprocate-1.8.4/Makefile.in 2012-07-05 15:15:47.000000000 +0000
@@ -46,9 +46,9 @@
DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \
$(srcdir)/Makefile.in $(srcdir)/config.h.in \
$(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
+ COPYING ChangeLog 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 -Nru resiprocate-1.8.2/repro/monkeys/RequestFilter.cxx resiprocate-1.8.4/repro/monkeys/RequestFilter.cxx
--- resiprocate-1.8.2/repro/monkeys/RequestFilter.cxx 2012-05-25 16:25:55.000000000 +0000
+++ resiprocate-1.8.4/repro/monkeys/RequestFilter.cxx 2012-07-05 15:09:41.000000000 +0000
@@ -51,32 +51,32 @@
mDefaultDBErrorBehavior(config.getConfigData("RequestFilterDefaultDBErrorBehavior", "500, Server Internal DB Error"))
{
#ifdef USE_MYSQL
+ Data mySQLSettingPrefix("RequestFilter");
Data mySQLServer = config.getConfigData("RequestFilterMySQLServer", "");
if(mySQLServer.empty())
{
- // If RequestFilterMySQLServer setting is blank, then fallback to global
- // MySql settings - if set
- mySQLServer = config.getConfigData("MySQLServer", "");
- if(!mySQLServer.empty())
+ // If RequestFilterMySQLServer setting is blank, then fallback to
+ // RuntimeMySql settings
+ mySQLSettingPrefix = "Runtime";
+ mySQLServer = config.getConfigData("RuntimeMySQLServer", "");
+ if(mySQLServer.empty())
{
- // Initialize My SQL using Global settings
- mMySqlDb = new MySqlDb(mySQLServer,
- config.getConfigData("MySQLUser", ""),
- config.getConfigData("MySQLPassword", ""),
- config.getConfigData("MySQLDatabaseName", ""),
- config.getConfigUnsignedLong("MySQLPort", 0),
- config.getConfigData("MySQLCustomUserAuthQuery", ""));
+ // If RuntimeMySQLServer setting is blank, then fallback to
+ // global MySql settings
+ mySQLSettingPrefix.clear();
+ mySQLServer = config.getConfigData("MySQLServer", "");
}
}
- else // RequestFilterMySQLServer is set
+
+ if(!mySQLServer.empty())
{
- // Initialize My SQL settings using RequestFilter specific settings
- mMySqlDb = new MySqlDb(mySQLServer,
- config.getConfigData("RequestFilterMySQLUser", ""),
- config.getConfigData("RequestFilterMySQLPassword", ""),
- config.getConfigData("RequestFilterMySQLDatabaseName", ""),
- config.getConfigUnsignedLong("RequestFilterMySQLPort", 0),
- config.getConfigData("RequestFilterMySQLCustomUserAuthQuery", ""));
+ // Initialize My SQL using Global settings
+ mMySqlDb = new MySqlDb(mySQLServer,
+ config.getConfigData(mySQLSettingPrefix + "MySQLUser", ""),
+ config.getConfigData(mySQLSettingPrefix + "MySQLPassword", ""),
+ config.getConfigData(mySQLSettingPrefix + "MySQLDatabaseName", ""),
+ config.getConfigUnsignedLong(mySQLSettingPrefix + "MySQLPort", 0),
+ Data::Empty);
}
#endif
}
diff -Nru resiprocate-1.8.2/repro/MySqlDb.cxx resiprocate-1.8.4/repro/MySqlDb.cxx
--- resiprocate-1.8.2/repro/MySqlDb.cxx 2012-05-25 16:25:58.000000000 +0000
+++ resiprocate-1.8.4/repro/MySqlDb.cxx 2012-07-05 15:09:45.000000000 +0000
@@ -466,11 +466,12 @@
Data escapedKey;
if(AbstractDb::getSecondaryKey(table, pKey, pData, (void**)&secondaryKey, &secondaryKeyLen) == 0)
{
+ Data escapedSKey;
Data sKey(Data::Share, secondaryKey, secondaryKeyLen);
DataStream ds(command);
ds << "REPLACE INTO " << tableName(table)
<< " SET attr='" << escapeString(pKey, escapedKey)
- << "', attr2='" << escapeString(sKey, escapedKey)
+ << "', attr2='" << escapeString(sKey, escapedSKey)
<< "', value='" << pData.base64encode()
<< "'";
}
diff -Nru resiprocate-1.8.2/repro/ProxyConfig.cxx resiprocate-1.8.4/repro/ProxyConfig.cxx
--- resiprocate-1.8.2/repro/ProxyConfig.cxx 2012-05-25 16:25:58.000000000 +0000
+++ resiprocate-1.8.4/repro/ProxyConfig.cxx 2012-07-05 15:09:45.000000000 +0000
@@ -96,10 +96,10 @@
}
void
-ProxyConfig::createDataStore(AbstractDb* db)
+ProxyConfig::createDataStore(AbstractDb* db, AbstractDb* runtimedb)
{
assert(db);
- mStore = new Store(*db);
+ mStore = new Store(*db, runtimedb);
}
}
diff -Nru resiprocate-1.8.2/repro/ProxyConfig.hxx resiprocate-1.8.4/repro/ProxyConfig.hxx
--- resiprocate-1.8.2/repro/ProxyConfig.hxx 2012-05-25 16:25:59.000000000 +0000
+++ resiprocate-1.8.4/repro/ProxyConfig.hxx 2012-07-05 15:09:45.000000000 +0000
@@ -19,7 +19,7 @@
virtual void printHelpText(int argc, char **argv);
- void createDataStore(AbstractDb* db);
+ void createDataStore(AbstractDb* db, AbstractDb* runtimedb=0);
Store* getDataStore() { return mStore; }
using resip::ConfigParse::getConfigValue;
diff -Nru resiprocate-1.8.2/repro/repro.config resiprocate-1.8.4/repro/repro.config
--- resiprocate-1.8.2/repro/repro.config 2012-05-25 16:25:58.000000000 +0000
+++ resiprocate-1.8.4/repro/repro.config 2012-07-05 15:09:45.000000000 +0000
@@ -193,7 +193,7 @@
# The Path to read and write Berkely DB database files
DatabasePath = ./
-# The hostname running MySQL server to connect to, leave blank to use BerkelyDB
+# The hostname running MySQL server to connect to, leave blank to use BerkelyDB.
# The value of host may be either a host name or an IP address. If host is "localhost",
# a connection to the local host is assumed. For Windows, the client connects using a
# shared-memory connection, if the server has shared-memory connections enabled. Otherwise,
@@ -218,9 +218,30 @@
# the host parameter determines the type of the connection.
MySQLPort = 3306
-# If you would like to be able to authenticate uses from a MySQL source other than the repro user
+# The Users and MessageSilo database tables are different from the other repro configuration
+# database tables, in that they are accessed at runtime as SIP requests arrive. It may be
+# desirable to use BerkeleyDb for the other repro tables (which are read at starup time, then
+# cached in memory), and MySQL for the runtime accessed tables; or two seperate MySQL instances
+# for these different table sets. Use the following settings in order to specify a seperate
+# MySQL instance for use by the Users and MessageSilo tables.
+#
+# WARNING: repro must be compiled with the USE_MYSQL flag in order for this work.
+#
+# Note: If this setting is left blank then repro will fallback all remaining my sql
+# settings to use the global MySQLServer settings. If the MySQLServer setting is also
+# blank, then repro will use BerkelyDB for all configuration tables. See the
+# documentation on the global MySQLServer settings for more details on the following
+# individual settings.
+RuntimeMySQLServer =
+RuntimeMySQLUser = root
+RuntimeMySQLPassword = root
+RuntimeMySQLDatabaseName = repro
+RuntimeMySQLPort = 3306
+
+# If you would like to be able to authenticate users from a MySQL source other than the repro user
# database table itself, then specify the query here. The following conditions apply:
-# 1. The database table must reside on the same MySQL server instance as the repro database.
+# 1. The database table must reside on the same MySQL server instance as the repro database
+# or Runtime tables database.
# 2. The statement provided will be UNION'd with the hardcoded repro query, so that auth from
# both sources is possible. Note: If the same user exists in both tables, then the repro
# auth info will be used.
@@ -428,37 +449,16 @@
# The hostname running MySQL server to connect to for any blocked entries
# that are configured to used a SQL statement.
-# The value of host may be either a host name or an IP address. If host is "localhost",
-# a connection to the local host is assumed. For Windows, the client connects using a
-# shared-memory connection, if the server has shared-memory connections enabled. Otherwise,
-# TCP/IP is used. For Unix, the client connects using a Unix socket file. For a host value of
-# "." on Windows, the client connects using a named pipe, if the server has named-pipe
-# connections enabled. If named-pipe connections are not enabled, an error occurs.
# WARNING: repro must be compiled with the USE_MYSQL flag in order for this work.
#
# Note: If this setting is left blank then repro will fallback all remaining my sql
-# settings to use the global MySQLServer settings.
+# settings to use the global RuntimeMySQLServer or MySQLServer settings. See the
+# documentation on the global MySQLServer settings for more details on the following
+# individual settings.
RequestFilterMySQLServer =
-
-# The MySQL login ID to use when connecting to the MySQL Server.
-# Note: If the RequestFilterMySQLServer setting is left blank then repro will fallback to
-# using the global MySQL settings.
RequestFilterMySQLUser = root
-
-# The password for the MySQL login ID specified.
-# Note: If the RequestFilterMySQLServer setting is left blank then repro will fallback to
-# using the global MySQL settings.
RequestFilterMySQLPassword = root
-
-# The database name on the MySQL server that contains the repro tables
-# Note: If the RequestFilterMySQLServer setting is left blank then repro will fallback to
-# using the global MySQL settings.
RequestFilterMySQLDatabaseName =
-
-# If port is not 0, the value is used as the port number for the TCP/IP connection. Note that
-# the host parameter determines the type of the connection.
-# Note: If the RequestFilterMySQLServer setting is left blank then repro will fallback to
-# using the global MySQL settings.
RequestFilterMySQLPort = 3306
diff -Nru resiprocate-1.8.2/repro/repro.cxx resiprocate-1.8.4/repro/repro.cxx
--- resiprocate-1.8.2/repro/repro.cxx 2012-05-25 16:25:58.000000000 +0000
+++ resiprocate-1.8.4/repro/repro.cxx 2012-07-05 15:09:45.000000000 +0000
@@ -6,9 +6,13 @@
#include <signal.h>
#include "repro/ReproRunner.hxx"
#include "rutil/Socket.hxx"
+#include "rutil/Log.hxx"
+#include "rutil/Logger.hxx"
#include "rutil/WinLeakCheck.hxx"
+#define RESIPROCATE_SUBSYSTEM resip::Subsystem::REPRO
+
using namespace repro;
using namespace resip;
using namespace std;
@@ -23,10 +27,21 @@
}
/*
- Extending Repro by adding custom processors to the chain is as easy as overriding the
- ReproRunner class virtual methods makeRequestProcessorChain, makeResponseProcessorChain
- and/or makeTargetProcessorChain and adding your Processor to the chain. Create
- an instance of your overridden ReproRunner class and call run to start everything
+ Extending Repro by adding custom processors to the chain is as easy as overriding one of the
+ ReproRunner class virtual methods:
+ virtual void addProcessor(repro::ProcessorChain& chain, std::auto_ptr<repro::Processor> processor);
+ virtual void makeRequestProcessorChain(repro::ProcessorChain& chain);
+ virtual void makeResponseProcessorChain(repro::ProcessorChain& chain);
+ virtual void makeTargetProcessorChain(repro::ProcessorChain& chain);
+
+ Override the makeXXXProcessorChain methods to add processors to the beginning or end of any chain,
+ or override the addProcessor method, and you can examine the name of the processor being
+ added and add your own process either before or after the correct processor.
+
+ WARNING: Be careful when checking for names of optional processors. Depending on
+ the configuration some processors may not be enabled.
+
+ Create an instance of your overridden ReproRunner class and call run to start everything
up.
Example:
@@ -55,10 +70,14 @@
virtual ~MyReproRunner() {}
protected:
- virtual void makeRequestProcessorChain(repro::ProcessorChain& chain)
+ virtual void addProcessor(repro::ProcessorChain& chain, std::auto_ptr<repro::Processor> processor)
{
- ReproRunner::makeRequestProcessorChain(chain);
- chain.addProcessor(std::auto_ptr<Processor>(new MyCustomProcessor(*mProxyConfig)));
+ if(processor->getName() == "LocationServer")
+ {
+ // Add MyCustomProcessor before LocationServer
+ addProcessor(chain, std::auto_ptr<Processor>(new MyCustomProcessor(*mProxyConfig)));
+ }
+ ReproRunner::addProcessor(chain, processor); // call base class implementation
}
};
diff -Nru resiprocate-1.8.2/repro/ReproRunner.cxx resiprocate-1.8.4/repro/ReproRunner.cxx
--- resiprocate-1.8.2/repro/ReproRunner.cxx 2012-05-25 16:25:58.000000000 +0000
+++ resiprocate-1.8.4/repro/ReproRunner.cxx 2012-07-05 15:09:45.000000000 +0000
@@ -108,6 +108,7 @@
, mSipStack(0)
, mStackThread(0)
, mAbstractDb(0)
+ , mRuntimeAbstractDb(0)
, mRegistrationPersistenceManager(0)
, mAuthRequestDispatcher(0)
, mAsyncProcessorDispatcher(0)
@@ -377,6 +378,7 @@
delete mRegistrationPersistenceManager; mRegistrationPersistenceManager = 0;
}
delete mAbstractDb; mAbstractDb = 0;
+ delete mRuntimeAbstractDb; mRuntimeAbstractDb = 0;
delete mStackThread; mStackThread = 0;
delete mSipStack; mSipStack = 0;
delete mAsyncProcessHandler; mAsyncProcessHandler = 0;
@@ -581,10 +583,11 @@
{
// Create Database access objects
assert(!mAbstractDb);
+ assert(!mRuntimeAbstractDb);
#ifdef USE_MYSQL
Data mySQLServer;
mProxyConfig->getConfigValue("MySQLServer", mySQLServer);
- if (!mySQLServer.empty())
+ if(!mySQLServer.empty())
{
mAbstractDb = new MySqlDb(mySQLServer,
mProxyConfig->getConfigData("MySQLUser", ""),
@@ -593,6 +596,17 @@
mProxyConfig->getConfigUnsignedLong("MySQLPort", 0),
mProxyConfig->getConfigData("MySQLCustomUserAuthQuery", ""));
}
+ Data runtimeMySQLServer;
+ mProxyConfig->getConfigValue("RuntimeMySQLServer", runtimeMySQLServer);
+ if(!runtimeMySQLServer.empty())
+ {
+ mRuntimeAbstractDb = new MySqlDb(runtimeMySQLServer,
+ mProxyConfig->getConfigData("RuntimeMySQLUser", ""),
+ mProxyConfig->getConfigData("RuntimeMySQLPassword", ""),
+ mProxyConfig->getConfigData("RuntimeMySQLDatabaseName", ""),
+ mProxyConfig->getConfigUnsignedLong("RuntimeMySQLPort", 0),
+ mProxyConfig->getConfigData("MySQLCustomUserAuthQuery", ""));
+ }
#endif
if (!mAbstractDb)
{
@@ -605,7 +619,13 @@
cleanupObjects();
return false;
}
- mProxyConfig->createDataStore(mAbstractDb);
+ if(mRuntimeAbstractDb && !mRuntimeAbstractDb->isSane())
+ {
+ CritLog(<<"Failed to open runtime configuration database");
+ cleanupObjects();
+ return false;
+ }
+ mProxyConfig->createDataStore(mAbstractDb, mRuntimeAbstractDb);
// Create ImMemory Registration Database
mRegSyncPort = mProxyConfig->getConfigInt("RegSyncPort", 0);
@@ -1176,6 +1196,12 @@
return true;
}
+void
+ReproRunner::addProcessor(repro::ProcessorChain& chain, std::auto_ptr<Processor> processor)
+{
+ chain.addProcessor(processor);
+}
+
void // Monkeys
ReproRunner::makeRequestProcessorChain(ProcessorChain& chain)
{
@@ -1183,10 +1209,10 @@
assert(mRegistrationPersistenceManager);
// Add strict route fixup monkey
- chain.addProcessor(std::auto_ptr<Processor>(new StrictRouteFixup));
+ addProcessor(chain, std::auto_ptr<Processor>(new StrictRouteFixup));
// Add is trusted node monkey
- chain.addProcessor(std::auto_ptr<Processor>(new IsTrustedNode(*mProxyConfig)));
+ addProcessor(chain, std::auto_ptr<Processor>(new IsTrustedNode(*mProxyConfig)));
// Add Certificate Authenticator - if required
if(mProxyConfig->getConfigBool("EnableCertificateAuthenticator", false))
@@ -1197,7 +1223,7 @@
// Should we used the same trustedPeers object that was
// passed to TlsPeerAuthManager perhaps?
std::set<Data> trustedPeers;
- chain.addProcessor(std::auto_ptr<Processor>(new CertificateAuthenticator(*mProxyConfig, mSipStack, trustedPeers)));
+ addProcessor(chain, std::auto_ptr<Processor>(new CertificateAuthenticator(*mProxyConfig, mSipStack, trustedPeers)));
}
// Add digest authenticator monkey - if required
@@ -1206,18 +1232,18 @@
assert(mAuthRequestDispatcher);
DigestAuthenticator* da = new DigestAuthenticator(*mProxyConfig, mAuthRequestDispatcher);
- chain.addProcessor(std::auto_ptr<Processor>(da));
+ addProcessor(chain, std::auto_ptr<Processor>(da));
}
// Add am I responsible monkey
- chain.addProcessor(std::auto_ptr<Processor>(new AmIResponsible));
+ addProcessor(chain, std::auto_ptr<Processor>(new AmIResponsible));
// Add RequestFilter monkey
if(!mProxyConfig->getConfigBool("DisableRequestFilterProcessor", false))
{
if(mAsyncProcessorDispatcher)
{
- chain.addProcessor(std::auto_ptr<Processor>(new RequestFilter(*mProxyConfig, mAsyncProcessorDispatcher)));
+ addProcessor(chain, std::auto_ptr<Processor>(new RequestFilter(*mProxyConfig, mAsyncProcessorDispatcher)));
}
else
{
@@ -1235,16 +1261,16 @@
if (routeSet.empty())
{
// add static route monkey
- chain.addProcessor(std::auto_ptr<Processor>(new StaticRoute(*mProxyConfig)));
+ addProcessor(chain, std::auto_ptr<Processor>(new StaticRoute(*mProxyConfig)));
}
else
{
// add simple static route monkey
- chain.addProcessor(std::auto_ptr<Processor>(new SimpleStaticRoute(*mProxyConfig)));
+ addProcessor(chain, std::auto_ptr<Processor>(new SimpleStaticRoute(*mProxyConfig)));
}
// Add location server monkey
- chain.addProcessor(std::auto_ptr<Processor>(new LocationServer(*mProxyConfig, *mRegistrationPersistenceManager, mAuthRequestDispatcher)));
+ addProcessor(chain, std::auto_ptr<Processor>(new LocationServer(*mProxyConfig, *mRegistrationPersistenceManager, mAuthRequestDispatcher)));
// Add message silo monkey
if(mProxyConfig->getConfigBool("MessageSiloEnabled", false))
@@ -1253,7 +1279,7 @@
{
MessageSilo* silo = new MessageSilo(*mProxyConfig, mAsyncProcessorDispatcher);
mRegistrar->addRegistrarHandler(silo);
- chain.addProcessor(std::auto_ptr<Processor>(silo));
+ addProcessor(chain, std::auto_ptr<Processor>(silo));
}
else
{
@@ -1267,13 +1293,14 @@
{
assert(mProxyConfig);
assert(mRegistrationPersistenceManager);
+
// Add outbound target handler lemur
- chain.addProcessor(std::auto_ptr<Processor>(new OutboundTargetHandler(*mRegistrationPersistenceManager)));
+ addProcessor(chain, std::auto_ptr<Processor>(new OutboundTargetHandler(*mRegistrationPersistenceManager)));
if (mProxyConfig->getConfigBool("RecursiveRedirect", false))
{
// Add recursive redirect lemur
- chain.addProcessor(std::auto_ptr<Processor>(new RecursiveRedirect));
+ addProcessor(chain, std::auto_ptr<Processor>(new RecursiveRedirect));
}
}
@@ -1285,18 +1312,18 @@
#ifndef RESIP_FIXED_POINT
if(mProxyConfig->getConfigBool("GeoProximityTargetSorting", false))
{
- chain.addProcessor(std::auto_ptr<Processor>(new GeoProximityTargetSorter(*mProxyConfig)));
+ addProcessor(chain, std::auto_ptr<Processor>(new GeoProximityTargetSorter(*mProxyConfig)));
}
#endif
if(mProxyConfig->getConfigBool("QValue", true))
{
// Add q value target handler baboon
- chain.addProcessor(std::auto_ptr<Processor>(new QValueTargetHandler(*mProxyConfig)));
+ addProcessor(chain, std::auto_ptr<Processor>(new QValueTargetHandler(*mProxyConfig)));
}
// Add simple target handler baboon
- chain.addProcessor(std::auto_ptr<Processor>(new SimpleTargetHandler));
+ addProcessor(chain, std::auto_ptr<Processor>(new SimpleTargetHandler));
}
diff -Nru resiprocate-1.8.2/repro/ReproRunner.hxx resiprocate-1.8.4/repro/ReproRunner.hxx
--- resiprocate-1.8.2/repro/ReproRunner.hxx 2012-05-25 16:25:58.000000000 +0000
+++ resiprocate-1.8.4/repro/ReproRunner.hxx 2012-07-05 15:09:45.000000000 +0000
@@ -3,6 +3,7 @@
#include "rutil/Data.hxx"
#include "rutil/ServerProcess.hxx"
+#include <memory>
namespace resip
{
@@ -33,6 +34,7 @@
class RegSyncServerThread;
class CommandServer;
class CommandServerThread;
+class Processor;
class ReproRunner : public resip::ServerProcess
{
@@ -60,6 +62,8 @@
virtual resip::Data addDomains(resip::TransactionUser& tu, bool log);
virtual bool addTransports(bool& allTransportsSpecifyRecordRoute);
+ // Override this and examine the processor name to selectively add custom processors before or after the standard ones
+ virtual void addProcessor(repro::ProcessorChain& chain, std::auto_ptr<repro::Processor> processor);
virtual void makeRequestProcessorChain(repro::ProcessorChain& chain);
virtual void makeResponseProcessorChain(repro::ProcessorChain& chain);
virtual void makeTargetProcessorChain(repro::ProcessorChain& chain);
@@ -80,6 +84,7 @@
resip::SipStack* mSipStack;
resip::ThreadIf* mStackThread;
AbstractDb* mAbstractDb;
+ AbstractDb* mRuntimeAbstractDb;
resip::RegistrationPersistenceManager* mRegistrationPersistenceManager;
Dispatcher* mAuthRequestDispatcher;
Dispatcher* mAsyncProcessorDispatcher;
diff -Nru resiprocate-1.8.2/repro/Store.cxx resiprocate-1.8.4/repro/Store.cxx
--- resiprocate-1.8.2/repro/Store.cxx 2012-05-25 16:25:58.000000000 +0000
+++ resiprocate-1.8.4/repro/Store.cxx 2012-07-05 15:09:45.000000000 +0000
@@ -13,14 +13,14 @@
#define RESIPROCATE_SUBSYSTEM Subsystem::REPRO
-Store::Store( AbstractDb& db ):
- mUserStore(db),
+Store::Store(AbstractDb& db, AbstractDb* runtimedb):
+ mUserStore(runtimedb ? *runtimedb : db),
mRouteStore(db),
mAclStore(db),
mConfigStore(db),
mStaticRegStore(db),
mFilterStore(db),
- mSiloStore(db)
+ mSiloStore(runtimedb ? *runtimedb : db)
{
}
diff -Nru resiprocate-1.8.2/repro/Store.hxx resiprocate-1.8.4/repro/Store.hxx
--- resiprocate-1.8.2/repro/Store.hxx 2012-05-25 16:25:58.000000000 +0000
+++ resiprocate-1.8.4/repro/Store.hxx 2012-07-05 15:09:45.000000000 +0000
@@ -19,7 +19,15 @@
class Store
{
public:
- Store( AbstractDb& db );
+ // If a seperate instance of AbstractDb is desired for the runtime database tables
+ // (ie. UserStore and SiloStore), then is can be provided, otherwise pass NULL.
+ // The Users and MessageSilo database tables are different from the other repro
+ // configuration database tables, in that they are accessed at runtime as SIP
+ // requests arrive. It may be desirable to use BerkeleyDb for the other repro
+ // tables (which are read at starup time, then cached in memory), and MySQL for
+ // the runtime accessed tables; or two seperate MySQL instances for these different
+ // table sets.
+ Store(AbstractDb& db, AbstractDb* runtimedb=0);
~Store();
UserStore mUserStore;
diff -Nru resiprocate-1.8.2/repro/WebAdmin.cxx resiprocate-1.8.4/repro/WebAdmin.cxx
--- resiprocate-1.8.2/repro/WebAdmin.cxx 2012-05-25 16:25:58.000000000 +0000
+++ resiprocate-1.8.4/repro/WebAdmin.cxx 2012-07-05 15:09:45.000000000 +0000
@@ -62,12 +62,12 @@
}
}
-WebAdmin::WebAdmin( Proxy& proxy,
- RegistrationPersistenceManager& regDb,
- const Data& realm, // this realm is used for http challenges
- int port,
- IpVersion version ):
- HttpBase( port, version, realm ),
+WebAdmin::WebAdmin(Proxy& proxy,
+ RegistrationPersistenceManager& regDb,
+ const Data& realm, // this realm is used for http challenges
+ int port,
+ IpVersion version ):
+ HttpBase(port, version, realm),
mProxy(proxy),
mStore(*mProxy.getConfig().getDataStore()),
mRegDb(regDb),
@@ -79,44 +79,44 @@
#include "repro/webadmin/pageOutlinePost.ixx"
)
{
- const Data adminName("admin");
- const Data adminPassword= proxy.getConfig().getConfigData("HttpAdminPassword", "admin");
+ const Data adminName("admin");
+ const Data adminPassword= mProxy.getConfig().getConfigData("HttpAdminPassword", "admin");
- // Place repro version into PageOutlinePre
- mPageOutlinePre.replace("VERSION", VersionUtils::instance().releaseVersion().c_str());
+ // Place repro version into PageOutlinePre
+ mPageOutlinePre.replace("VERSION", VersionUtils::instance().releaseVersion().c_str());
- Data dbA1 = mStore.mUserStore.getUserAuthInfo( adminName, Data::Empty );
+ Data dbA1 = mStore.mUserStore.getUserAuthInfo( adminName, Data::Empty );
- DebugLog(<< " Looking to see if admin user exists (creating WebAdmin)");
- if ( dbA1.empty() ) // if the admin user does not exist, add it
- {
- DebugLog(<< "Creating admin user" );
+ DebugLog(<< " Looking to see if admin user exists (creating WebAdmin)");
+ if ( dbA1.empty() ) // if the admin user does not exist, add it
+ {
+ DebugLog(<< "Creating admin user" );
- mStore.mUserStore.addUser( adminName, // user
- Data::Empty, // domain
- Data::Empty, // realm
- (adminPassword==""?Data("admin"):adminPassword), // password
- true, // applyA1HashToPassword
- Data::Empty, // name
- Data::Empty ); // email
- dbA1 = mStore.mUserStore.getUserAuthInfo( adminName, Data::Empty );
- assert( !dbA1.empty() );
- }
- else if (adminPassword!=Data(""))
- {
- //All we're using for admin is the password.
- //This next bit of code relies on it being ok that we
- //blow away any other information
- //in that row. It also expects addUser to replace anything matching the existing key
- DebugLog(<< "Changing the web admin password" );
- mStore.mUserStore.addUser( adminName,
- Data::Empty,
- Data::Empty,
- adminPassword,
- true, // applyA1HashToPassword
- Data::Empty,
- Data::Empty);
- }
+ mStore.mUserStore.addUser(adminName, // user
+ Data::Empty, // domain
+ Data::Empty, // realm
+ (adminPassword == "" ? Data("admin") : adminPassword), // password
+ true, // applyA1HashToPassword
+ Data::Empty, // name
+ Data::Empty ); // email
+ dbA1 = mStore.mUserStore.getUserAuthInfo( adminName, Data::Empty );
+ assert(!dbA1.empty());
+ }
+ else if (adminPassword!=Data(""))
+ {
+ //All we're using for admin is the password.
+ //This next bit of code relies on it being ok that we
+ //blow away any other information
+ //in that row. It also expects addUser to replace anything matching the existing key
+ DebugLog(<< "Changing the web admin password" );
+ mStore.mUserStore.addUser(adminName,
+ Data::Empty,
+ Data::Empty,
+ adminPassword,
+ true, // applyA1HashToPassword
+ Data::Empty,
+ Data::Empty);
+ }
}
@@ -157,6 +157,7 @@
( pageName != Data("showRoutes.html") )&&
( pageName != Data("registrations.html") ) &&
( pageName != Data("settings.html") ) &&
+ ( pageName != Data("restart.html") ) &&
( pageName != Data("user.html") ) )
{
setPage( resip::Data::Empty, pageNumber, 301 );
@@ -282,10 +283,10 @@
}
}
- // parse any URI tags from form entry
+ // parse any URI tags from form entry
mRemoveSet.clear();
mHttpParams.clear();
-
+
if (!pb.eof())
{
pb.skipChar('?');
@@ -322,7 +323,6 @@
mHttpParams[key] = value.urlDecoded(); // add other parameters to the Map
}
}
-
}
DebugLog( << "building page for user=" << authenticatedUser );
@@ -353,7 +353,8 @@
if ( pageName == Data("registrations.html")) buildRegistrationsSubPage(s);
if ( pageName == Data("settings.html")) buildSettingsSubPage(s);
-
+ if ( pageName == Data("restart.html")) buildRestartSubPage(s);
+
s << mPageOutlinePost;
s.flush();
@@ -567,7 +568,7 @@
void
-WebAdmin::buildAddUserSubPage( DataStream& s)
+WebAdmin::buildAddUserSubPage(DataStream& s)
{
Dictionary::iterator pos;
Data user;
@@ -659,7 +660,7 @@
void
-WebAdmin::buildEditUserSubPage( DataStream& s)
+WebAdmin::buildEditUserSubPage(DataStream& s)
{
Dictionary::iterator pos;
pos = mHttpParams.find("key");
@@ -1780,6 +1781,11 @@
void
WebAdmin::buildSettingsSubPage(DataStream& s)
{
+ if (mHttpParams["action"] == "Clear DNS Cache")
+ {
+ mProxy.getStack().clearDnsCache();
+ }
+
s << "<h2>Settings</h2>" << endl <<
"<pre>" << mProxy.getConfig() << "</pre>";
@@ -1802,8 +1808,101 @@
<< "<pre>" << buffer << "</pre>"
<< endl;
}
+
+ // Get Dns Cache
+ {
+ Lock lock(mDnsCacheMutex);
+ mProxy.getStack().getDnsCacheDump(make_pair(0, 0), this);
+ // Retrieving DNS cache is asyncronous
+ // Use condition variable to wait for DNS results to be returned in onDnsCacheDumpRetrieved
+ mDnsCacheCondition.wait(mDnsCacheMutex);
+ s << "<br>DNS Cache<br>"
+ << "<pre>" << mDnsCache << "</pre>"
+ << endl;
+ }
+
+ s << "<form id=\"clearDnsCache\" method=\"get\" action=\"settings.html\" name=\"clearDnsCache\">" << endl
+ << " <br><input type=\"submit\" name=\"action\" value=\"Clear DNS Cache\"/>" << endl
+ << "</form>" << endl;
+
+ if(mProxy.getConfig().getConfigUnsignedShort("CommandPort", 0) != 0)
+ {
+ s << "<form id=\"restartProxy\" method=\"get\" action=\"restart.html\" name=\"restart\">" << endl
+ << " <input type=\"submit\" name=\"action\" value=\"Restart Proxy\"/>" << endl
+ << "</form>" << endl;
+ }
+}
+
+void
+WebAdmin::onDnsCacheDumpRetrieved(std::pair<unsigned long, unsigned long> key, const resip::Data& dnsEntryStrings)
+{
+ Lock lock(mDnsCacheMutex); (void)lock;
+ if(dnsEntryStrings.empty())
+ {
+ mDnsCache = "<i>empty</i>";
+ }
+ else
+ {
+ mDnsCache = dnsEntryStrings;
+ }
+ mDnsCacheCondition.signal();
}
+void
+WebAdmin::buildRestartSubPage(DataStream& s)
+{
+ unsigned short port = mProxy.getConfig().getConfigUnsignedShort("CommandPort", 0);
+ if(port != 0)
+ {
+ // Send restart command to command server - it is not safe to invoke a restart from here
+ // since the webadmin thread and server is destroyed on the blocking ReproRunner::restart call
+ int sd, rc;
+ struct sockaddr_in localAddr, servAddr;
+ struct hostent *h;
+ char* host = "127.0.0.1";
+ h = gethostbyname(host);
+ if(h!=0)
+ {
+ servAddr.sin_family = h->h_addrtype;
+ memcpy((char *) &servAddr.sin_addr.s_addr, h->h_addr_list[0], h->h_length);
+ servAddr.sin_port = htons(port);
+
+ // Create TCP Socket
+ sd = (int)socket(AF_INET, SOCK_STREAM, 0);
+ if(sd > 0)
+ {
+ // bind to any local interface/port
+ localAddr.sin_family = AF_INET;
+ localAddr.sin_addr.s_addr = htonl(INADDR_ANY);
+ localAddr.sin_port = 0;
+
+ rc = bind(sd, (struct sockaddr *) &localAddr, sizeof(localAddr));
+ if(rc >= 0)
+ {
+ // Connect to server
+ rc = connect(sd, (struct sockaddr *) &servAddr, sizeof(servAddr));
+ if(rc >= 0)
+ {
+ Data request("<Restart>\r\n <Request>\r\b </Request>\r\n</Restart>\r\n");
+ rc = send(sd, request.c_str(), request.size(), 0);
+ if(rc >= 0)
+ {
+ s << "Restarting proxy..." << endl;
+ closeSocket(sd);
+ return;
+ }
+ }
+ }
+ closeSocket(sd);
+ }
+ }
+ s << "Error issuing restart command." << endl;
+ }
+ else
+ {
+ s << "CommandServer must be running to use restart feature." << endl;
+ }
+}
Data
WebAdmin::buildUserPage()
@@ -1839,13 +1938,13 @@
Data
WebAdmin::buildCertPage(const Data& domain)
{
- assert(!domain.empty());
+ assert(!domain.empty());
#ifdef USE_SSL
- assert( mProxy.getStack().getSecurity() );
- return mProxy.getStack().getSecurity()->getDomainCertDER(domain);
+ assert( mProxy.getStack().getSecurity() );
+ return mProxy.getStack().getSecurity()->getDomainCertDER(domain);
#else
- ErrLog( << "Proxy not build with support for certificates" );
- return Data::Empty;
+ ErrLog( << "Proxy not build with support for certificates" );
+ return Data::Empty;
#endif
}
diff -Nru resiprocate-1.8.2/repro/WebAdmin.hxx resiprocate-1.8.4/repro/WebAdmin.hxx
--- resiprocate-1.8.2/repro/WebAdmin.hxx 2012-05-25 16:25:58.000000000 +0000
+++ resiprocate-1.8.4/repro/WebAdmin.hxx 2012-07-05 15:09:45.000000000 +0000
@@ -2,6 +2,8 @@
#define RESIP_WEBADMIN_HXX
#include "rutil/Data.hxx"
+#include "rutil/Condition.hxx"
+#include "rutil/dns/DnsStub.hxx"
#include "rutil/TransportType.hxx"
#include "resip/stack/Tuple.hxx"
#include "repro/HttpBase.hxx"
@@ -24,14 +26,15 @@
typedef std::map<resip::Data, resip::Data> Dictionary;
class Proxy;
-class WebAdmin: public HttpBase
+class WebAdmin : public HttpBase,
+ public resip::GetDnsCacheDumpHandler
{
public:
- WebAdmin( Proxy& proxy,
- resip::RegistrationPersistenceManager& regDb,
- const resip::Data& realm, // this realm is used for http challenges
- int port=5080,
- resip::IpVersion version=resip::V4 );
+ WebAdmin(Proxy& proxy,
+ resip::RegistrationPersistenceManager& regDb,
+ const resip::Data& realm, // this realm is used for http challenges
+ int port=5080,
+ resip::IpVersion version=resip::V4);
protected:
virtual void buildPage( const resip::Data& uri,
@@ -39,6 +42,9 @@
const resip::Data& user,
const resip::Data& password);
+ // Handler
+ virtual void onDnsCacheDumpRetrieved(std::pair<unsigned long, unsigned long> key, const resip::Data& dnsEntryStrings);
+
private:
resip::Data buildDefaultPage();
resip::Data buildUserPage();
@@ -60,6 +66,7 @@
void buildRegistrationsSubPage(resip::DataStream& s);
void buildSettingsSubPage(resip::DataStream& s);
+ void buildRestartSubPage(resip::DataStream& s);
resip::Data buildCertPage(const resip::Data& domain);
@@ -67,6 +74,10 @@
Store& mStore;
resip::RegistrationPersistenceManager& mRegDb;
+ resip::Data mDnsCache;
+ resip::Mutex mDnsCacheMutex;
+ resip::Condition mDnsCacheCondition;
+
bool mNoWebChallenges;
Dictionary mHttpParams;
diff -Nru resiprocate-1.8.2/resip/dum/ContactInstanceRecord.hxx resiprocate-1.8.4/resip/dum/ContactInstanceRecord.hxx
--- resiprocate-1.8.2/resip/dum/ContactInstanceRecord.hxx 2012-05-25 16:25:17.000000000 +0000
+++ resiprocate-1.8.4/resip/dum/ContactInstanceRecord.hxx 2012-07-05 15:10:08.000000000 +0000
@@ -12,7 +12,7 @@
namespace resip
{
-static const UInt64 NeverExpire = 0xFFFFFFFFFFFFFFFFL;
+static const UInt64 NeverExpire = 0xFFFFFFFFFFFFFFFFUL;
/** A single contact record, bound to an Aor during registration.
*/
diff -Nru resiprocate-1.8.2/resip/dum/Dialog.cxx resiprocate-1.8.4/resip/dum/Dialog.cxx
--- resiprocate-1.8.2/resip/dum/Dialog.cxx 2012-05-25 16:25:17.000000000 +0000
+++ resiprocate-1.8.4/resip/dum/Dialog.cxx 2012-07-05 15:10:08.000000000 +0000
@@ -158,7 +158,20 @@
}
mRemoteCSeq = request.header(h_CSeq).sequence();
- mLocalCSeq = 1;
+
+ // This may actually be a UAC dialogset - ie. the case where the first NOTIFY creates the
+ // SUBSCRIPTION dialog, instead of the 200/SUB. If so, then we need to make sure the local
+ // CSeq is correct - it's value may be greator than 1, if the original request (SUBSCRIBE)
+ // got digest challenged.
+ BaseCreator* creator = mDialogSet.getCreator();
+ if(creator)
+ {
+ mLocalCSeq = creator->getLastRequest()->header(h_CSeq).sequence();
+ }
+ else
+ {
+ mLocalCSeq = 1;
+ }
DebugLog ( << "************** Created Dialog as UAS **************" );
DebugLog ( << "mRemoteNameAddr: " << mRemoteNameAddr );
@@ -208,9 +221,8 @@
if (isEqualNoCase(contact.uri().scheme(), Symbols::Sips) ||
isEqualNoCase(contact.uri().scheme(), Symbols::Sip))
{
- BaseCreator* creator = mDialogSet.getCreator();
-
- if( 0 == creator )
+ BaseCreator* creator = mDialogSet.getCreator();
+ if(0 == creator)
{
ErrLog(<< "BaseCreator is null for DialogSet");
ErrLog(<< response);
diff -Nru resiprocate-1.8.2/resip/dum/InMemorySyncRegDb.cxx resiprocate-1.8.4/resip/dum/InMemorySyncRegDb.cxx
--- resiprocate-1.8.2/resip/dum/InMemorySyncRegDb.cxx 2012-05-25 16:25:18.000000000 +0000
+++ resiprocate-1.8.4/resip/dum/InMemorySyncRegDb.cxx 2012-07-05 15:10:09.000000000 +0000
@@ -264,9 +264,18 @@
{
if (*j == rec)
{
+ update_status_t status = CONTACT_UPDATED;
+ if(mRemoveLingerSecs > 0 && j->mRegExpires == 0)
+ {
+ // If records linger, then check if updating a lingering record, if so
+ // modify status to CREATED so that ServerRegistration will properly generate
+ // an onAdd callback, instead of onRefresh.
+ // When contacts linger, their expires time is set to 0
+ status = CONTACT_CREATED;
+ }
*j=rec;
if(mHandler && !rec.mSyncContact) mHandler->onAorModified(aor, *contactList);
- return CONTACT_UPDATED;
+ return status;
}
}
diff -Nru resiprocate-1.8.2/resip/dum/test/basicClientCall.cxx resiprocate-1.8.4/resip/dum/test/basicClientCall.cxx
--- resiprocate-1.8.2/resip/dum/test/basicClientCall.cxx 2012-05-25 16:25:15.000000000 +0000
+++ resiprocate-1.8.4/resip/dum/test/basicClientCall.cxx 2012-07-05 15:10:05.000000000 +0000
@@ -104,7 +104,7 @@
// start timer for next one
auto_ptr<ApplicationMessage> timer(new CallTimer(mUserAgent, this));
- mUserAgent.mStack.post(timer, CallTimerTime, &mUserAgent.getDialogUsageManager());
+ mUserAgent.mStack->post(timer, CallTimerTime, &mUserAgent.getDialogUsageManager());
}
SharedPtr<UserProfile>
@@ -189,7 +189,7 @@
{
// Restart Call Timer
auto_ptr<ApplicationMessage> timer(new CallTimer(mUserAgent, this));
- mUserAgent.mStack.post(timer, CallTimerTime, &mUserAgent.getDialogUsageManager());
+ mUserAgent.mStack->post(timer, CallTimerTime, &mUserAgent.getDialogUsageManager());
}
// Session to replace was found - end old session
@@ -258,7 +258,7 @@
// start call timer
auto_ptr<ApplicationMessage> timer(new CallTimer(mUserAgent, this));
- mUserAgent.mStack.post(timer, CallTimerTime, &mUserAgent.getDialogUsageManager());
+ mUserAgent.mStack->post(timer, CallTimerTime, &mUserAgent.getDialogUsageManager());
}
else
{
diff -Nru resiprocate-1.8.2/resip/dum/test/basicClientUserAgent.cxx resiprocate-1.8.4/resip/dum/test/basicClientUserAgent.cxx
--- resiprocate-1.8.2/resip/dum/test/basicClientUserAgent.cxx 2012-05-25 16:25:15.000000000 +0000
+++ resiprocate-1.8.4/resip/dum/test/basicClientUserAgent.cxx 2012-07-05 15:10:05.000000000 +0000
@@ -118,9 +118,10 @@
#else
mSecurity(0),
#endif
- mStack(mSecurity, DnsStub::EmptyNameserverList, &mSelectInterruptor),
- mDum(new DialogUsageManager(mStack)),
- mStackThread(mStack, mSelectInterruptor),
+ mSelectInterruptor(new SelectInterruptor),
+ mStack(new SipStack(mSecurity, DnsStub::EmptyNameserverList, mSelectInterruptor)),
+ mStackThread(new InterruptableStackThread(*mStack, *mSelectInterruptor)),
+ mDum(new DialogUsageManager(*mStack)),
mDumShutdownRequested(false),
mDumShutdown(false),
mRegistrationRetryDelayTime(0),
@@ -143,7 +144,7 @@
#endif
// Disable Statistics Manager
- mStack.statisticsManagerEnabled() = false;
+ mStack->statisticsManagerEnabled() = false;
// Supported Methods
mProfile->clearSupportedMethods();
@@ -307,16 +308,20 @@
BasicClientUserAgent::~BasicClientUserAgent()
{
- mStackThread.shutdown();
- mStackThread.join();
+ mStackThread->shutdown();
+ mStackThread->join();
delete mDum;
+ delete mStack;
+ delete mStackThread;
+ delete mSelectInterruptor;
+ // Note: mStack descructor will delete mSecurity
}
void
BasicClientUserAgent::startup()
{
- mStackThread.run();
+ mStackThread->run();
if (mRegisterDuration)
{
@@ -402,13 +407,13 @@
{
if (!mNoV4)
{
- mStack.addTransport(type, port+i, V4, StunEnabled, Data::Empty, mTlsDomain);
+ mStack->addTransport(type, port+i, V4, StunEnabled, Data::Empty, mTlsDomain);
return;
}
if (mEnableV6)
{
- mStack.addTransport(type, port+i, V6, StunEnabled, Data::Empty, mTlsDomain);
+ mStack->addTransport(type, port+i, V6, StunEnabled, Data::Empty, mTlsDomain);
return;
}
}
@@ -453,7 +458,7 @@
// start timer for next one
auto_ptr<ApplicationMessage> timer(new NotifyTimer(*this, ++mCurrentNotifyTimerId));
- mStack.post(timer, NotifySendTime, mDum);
+ mStack->post(timer, NotifySendTime, mDum);
}
}
@@ -890,7 +895,6 @@
mServerSubscriptionHandle = h;
mServerSubscriptionHandle->setSubscriptionState(Active);
mServerSubscriptionHandle->send(mServerSubscriptionHandle->accept());
-
sendNotify();
}
diff -Nru resiprocate-1.8.2/resip/dum/test/basicClientUserAgent.hxx resiprocate-1.8.4/resip/dum/test/basicClientUserAgent.hxx
--- resiprocate-1.8.2/resip/dum/test/basicClientUserAgent.hxx 2012-05-25 16:25:15.000000000 +0000
+++ resiprocate-1.8.4/resip/dum/test/basicClientUserAgent.hxx 2012-07-05 15:10:05.000000000 +0000
@@ -131,11 +131,12 @@
void onCallTimeout(BasicClientCall* call);
SharedPtr<MasterProfile> mProfile;
+ // Using pointers for the following classes so that we can control object descruction order
Security* mSecurity;
- SipStack mStack;
- DialogUsageManager* mDum; // DUM holds pointers to alot of objects that access this UserAgent class - using a pointer to DUM so that we can have more control over it's lifetime
- SelectInterruptor mSelectInterruptor;
- InterruptableStackThread mStackThread;
+ SelectInterruptor* mSelectInterruptor;
+ SipStack* mStack;
+ InterruptableStackThread* mStackThread;
+ DialogUsageManager* mDum;
volatile bool mDumShutdownRequested;
bool mDumShutdown;
ClientRegistrationHandle mRegHandle;
diff -Nru resiprocate-1.8.2/resip/stack/ConnectionManager.cxx resiprocate-1.8.4/resip/stack/ConnectionManager.cxx
--- resiprocate-1.8.2/resip/stack/ConnectionManager.cxx 2012-05-25 16:25:40.000000000 +0000
+++ resiprocate-1.8.4/resip/stack/ConnectionManager.cxx 2012-07-05 15:10:32.000000000 +0000
@@ -153,7 +153,7 @@
{
if ( mPollGrp )
{
- mPollGrp->modPollItem(conn->mPollItemHandle, FPEM_Read|FPEM_Write);
+ mPollGrp->modPollItem(conn->mPollItemHandle, FPEM_Read|FPEM_Write|FPEM_Error);
}
else
{
@@ -166,7 +166,7 @@
{
if ( mPollGrp )
{
- mPollGrp->modPollItem(conn->mPollItemHandle, FPEM_Read);
+ mPollGrp->modPollItem(conn->mPollItemHandle, FPEM_Read|FPEM_Error);
}
else
{
@@ -189,7 +189,7 @@
if ( mPollGrp )
{
connection->mPollItemHandle = mPollGrp->addPollItem(
- connection->getSocket(), FPEM_Read, connection);
+ connection->getSocket(), FPEM_Read|FPEM_Error, connection);
}
else
{
diff -Nru resiprocate-1.8.2/resip/stack/KeepAlivePong.hxx resiprocate-1.8.4/resip/stack/KeepAlivePong.hxx
--- resiprocate-1.8.2/resip/stack/KeepAlivePong.hxx 2012-05-25 16:25:42.000000000 +0000
+++ resiprocate-1.8.4/resip/stack/KeepAlivePong.hxx 2012-07-05 15:10:34.000000000 +0000
@@ -11,7 +11,7 @@
class KeepAlivePong : public TransactionMessage
{
public:
- RESIP_HeapCount(ConnectionPingStarted);
+ RESIP_HeapCount(KeepAlivePong);
KeepAlivePong(const Tuple& flow) :
mFlow(flow)
diff -Nru resiprocate-1.8.2/resip/stack/ssl/Security.cxx resiprocate-1.8.4/resip/stack/ssl/Security.cxx
--- resiprocate-1.8.2/resip/stack/ssl/Security.cxx 2012-05-25 16:25:23.000000000 +0000
+++ resiprocate-1.8.4/resip/stack/ssl/Security.cxx 2012-07-05 15:10:13.000000000 +0000
@@ -285,9 +285,12 @@
FileSystem::Directory::iterator it(dir);
for (; it != dir.end(); ++it)
{
- Data name = *it;
- Data fileName = _dir + name;
- addCAFile(fileName);
+ if(!it.is_directory())
+ {
+ Data name = *it;
+ Data fileName = _dir + name;
+ addCAFile(fileName);
+ }
}
}
std::list<Data>::iterator it_f = mCAFiles.begin();
@@ -297,6 +300,7 @@
try
{
addRootCertPEM(readIntoData(_file));
+ InfoLog(<<"Successfully loaded " << _file);
}
catch (Exception& e)
{
diff -Nru resiprocate-1.8.2/resip.spec resiprocate-1.8.4/resip.spec
--- resiprocate-1.8.2/resip.spec 2012-05-25 16:33:48.000000000 +0000
+++ resiprocate-1.8.4/resip.spec 2012-07-05 15:15:56.000000000 +0000
@@ -1,5 +1,5 @@
Name: resiprocate
-Version: 1.8.2
+Version: 1.8.4
Release: 1
Summary: Resiprocate SIP Stack
License: Vovida Software License http://opensource.org/licenses/vovidapl.php
diff -Nru resiprocate-1.8.2/rutil/ConfigParse.cxx resiprocate-1.8.4/rutil/ConfigParse.cxx
--- resiprocate-1.8.2/rutil/ConfigParse.cxx 2012-05-25 16:26:06.000000000 +0000
+++ resiprocate-1.8.4/rutil/ConfigParse.cxx 2012-07-05 15:10:52.000000000 +0000
@@ -2,6 +2,7 @@
#include <fstream>
#include <iterator>
#include <stdexcept>
+#include <map>
#include "rutil/ConfigParse.hxx"
#include "rutil/Log.hxx"
@@ -17,7 +18,8 @@
namespace resip
{
-ConfigParse::ConfigParse(int argc, char** argv, const resip::Data& defaultConfigFilename)
+ConfigParse::ConfigParse(int argc, char** argv, const resip::Data& defaultConfigFilename, int skipCount) :
+ mSkipCount(skipCount)
{
parseCommandLine(argc, argv); // will fill in mCmdLineConfigFilename if present
if(mCmdLineConfigFilename.empty())
@@ -208,16 +210,17 @@
void
ConfigParse::parseCommandLine(int argc, char** argv)
{
- int startingArgForNameValuePairs = 1;
+ int startingArgForNameValuePairs = 1 + mSkipCount;
+ char *firstArg = argv[startingArgForNameValuePairs];
// First argument is the configuration filename - it is optional and is never proceeded with a - or /
#ifdef WIN32
- if(argc >= 2 && argv[1][0] != '-' && argv[1][0] != '/')
+ if(argc >= (startingArgForNameValuePairs + 1) && firstArg[0] != '-' && firstArg[0] != '/')
#else
- if(argc >= 2 && argv[1][0] != '-')
+ if(argc >= (startingArgForNameValuePairs + 1) && firstArg[0] != '-')
#endif
{
- mCmdLineConfigFilename = argv[1];
- startingArgForNameValuePairs = 2;
+ mCmdLineConfigFilename = firstArg;
+ startingArgForNameValuePairs++;
}
// Loop through command line arguments and process them
@@ -325,10 +328,18 @@
EncodeStream&
operator<<(EncodeStream& strm, const ConfigParse& config)
{
+ // Yes this is horribly inefficient - however it's only used when a user requests it
+ // and we want to see the items in a sorted list and hash_maps are not sorted.
+ std::multimap<Data, Data> sortedMap;
ConfigParse::ConfigValuesMap::const_iterator it = config.mConfigValues.begin();
for(; it != config.mConfigValues.end(); it++)
{
- strm << it->first << " = " << it->second << endl;
+ sortedMap.insert(std::multimap<Data, Data>::value_type(it->first, it->second));
+ }
+ std::multimap<Data, Data>::iterator it2 = sortedMap.begin();
+ for(; it2 != sortedMap.end(); it2++)
+ {
+ strm << it2->first << " = " << it2->second << endl;
}
return strm;
}
diff -Nru resiprocate-1.8.2/rutil/ConfigParse.hxx resiprocate-1.8.4/rutil/ConfigParse.hxx
--- resiprocate-1.8.2/rutil/ConfigParse.hxx 2012-05-25 16:26:07.000000000 +0000
+++ resiprocate-1.8.4/rutil/ConfigParse.hxx 2012-07-05 15:10:53.000000000 +0000
@@ -24,7 +24,7 @@
};
ConfigParse();
- ConfigParse(int argc, char** argv, const resip::Data& defaultConfigFilename);
+ ConfigParse(int argc, char** argv, const resip::Data& defaultConfigFilename, int skipCount = 0);
virtual ~ConfigParse();
virtual void printHelpText(int argc, char **argv) = 0;
@@ -60,6 +60,8 @@
private:
friend EncodeStream& operator<<(EncodeStream& strm, const ConfigParse& config);
+
+ int mSkipCount;
};
EncodeStream& operator<<(EncodeStream& strm, const ConfigParse& config);
diff -Nru resiprocate-1.8.2/rutil/FileSystem.cxx resiprocate-1.8.4/rutil/FileSystem.cxx
--- resiprocate-1.8.2/rutil/FileSystem.cxx 2012-05-25 16:26:06.000000000 +0000
+++ resiprocate-1.8.4/rutil/FileSystem.cxx 2012-07-05 15:10:53.000000000 +0000
@@ -99,6 +99,12 @@
{
return &mFile;
}
+
+bool
+FileSystem::Directory::iterator::is_directory() const
+{
+ return mDirent->d_type == DT_DIR;
+}
#else
@@ -158,6 +164,7 @@
else
{
mFile = fileData.cFileName;
+ mIsDirectory = (fileData.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) > 0;
}
return *this;
}
@@ -196,6 +203,12 @@
{
return &mFile;
}
+
+bool
+FileSystem::Directory::iterator::is_directory() const
+{
+ return mIsDirectory;
+}
#endif
diff -Nru resiprocate-1.8.2/rutil/FileSystem.hxx resiprocate-1.8.4/rutil/FileSystem.hxx
--- resiprocate-1.8.2/rutil/FileSystem.hxx 2012-05-25 16:26:07.000000000 +0000
+++ resiprocate-1.8.4/rutil/FileSystem.hxx 2012-07-05 15:10:53.000000000 +0000
@@ -47,9 +47,11 @@
bool operator==(const iterator& rhs) const;
const Data& operator*() const;
const Data* operator->() const;
+ bool is_directory() const;
private:
#ifdef WIN32
HANDLE mWinSearch;
+ bool mIsDirectory;
#else
DIR* mNixDir;
struct dirent* mDirent;
Reply to: