[reSIProcate] Dum segfaulting when dns is unavailable
Hi,
I've found a problem with resiprocate that causes the stack to segfault when
returning 503 errors caused by failed dns requests. I've attached a short
test program that demonstrates the failure.
Basically, the program continually loops creating a new dum, sending a
registration to an address that needs to be resolved, then deleting the dum.
The program runs indefinately without error if there is a configured network
interface on the machine. If there is no network available however (ifdown
eth0 or similar on linux), the program loops a few times then segfaults.
I haven't figured out exactly what's wrong yet but valgrind is showing lots of
errors. The stack only seems to crash whenever
TransactionState::processNoDnsResults is called to generate a "503 Service
Unavailable" message. The problem is also not specific to registration,
sending subscription requests has the same effect. It looks like someone's
data is getting stomped somewhere between processNoDnsResults and the various
Client Handlers. Can anyone else reproduce this?
~Scott
#include "resiprocate/SipMessage.hxx"
#include "resiprocate/SipStack.hxx"
#include "resiprocate/dum/DialogUsageManager.hxx"
#include "resiprocate/dum/DumShutdownHandler.hxx"
#include "resiprocate/dum/Profile.hxx"
#include "resiprocate/dum/RegistrationHandler.hxx"
#include "resiprocate/dum/SubscriptionHandler.hxx"
#include "resiprocate/dum/AppDialog.hxx"
#include "resiprocate/dum/AppDialogSet.hxx"
#include "resiprocate/dum/AppDialogSetFactory.hxx"
#include "resiprocate/os/Log.hxx"
#include <ostream>
using namespace resip;
using namespace std;
class testAppDialog : public AppDialog
{
public:
Data mSampleAppData;
testAppDialog(HandleManager& ham, Data &SampleAppData) : AppDialog(ham), mSampleAppData(SampleAppData)
{ cout << mSampleAppData << ": testAppDialog: created." << endl; }
virtual ~testAppDialog()
{ cout << mSampleAppData << ": testAppDialog: destroyed." << endl; }
};
class testAppDialogSet : public AppDialogSet
{
public:
Data mSampleAppData;
testAppDialogSet(DialogUsageManager& dum, Data SampleAppData) : AppDialogSet(dum), mSampleAppData(SampleAppData)
{ cout << mSampleAppData << ": testAppDialogSet: created." << endl; }
virtual ~testAppDialogSet()
{ cout << mSampleAppData << ": testAppDialogSet: destroyed." << endl; }
virtual AppDialog* createAppDialog(const SipMessage& msg)
{ return new testAppDialog(mDum, mSampleAppData); }
};
class testAppDialogSetFactory : public AppDialogSetFactory
{
public:
virtual AppDialogSet* createAppDialogSet(DialogUsageManager& dum, const SipMessage& msg)
{ return new testAppDialogSet(dum, Data("UAS") + Data("(") + getMethodName(msg.header(h_RequestLine).getMethod()) + Data(")")); }
};
class TestClientRegistrationHandler : public ClientRegistrationHandler
{
public:
Data name;
bool regcallbackcalled;
TestClientRegistrationHandler(const Data& n) : name(n), regcallbackcalled(false) {}
virtual ~TestClientRegistrationHandler() {}
virtual void onSuccess(ClientRegistrationHandle h, const SipMessage& response)
{
cout << name << ": TestClientRegistration-onSuccess - " << response.brief() << endl;
regcallbackcalled = true;
}
virtual void onFailure(ClientRegistrationHandle, const SipMessage& msg)
{
cout << name << ": TestClientRegistration-onFailure - " << msg << endl;
regcallbackcalled = true;
}
virtual void onRemoved(ClientRegistrationHandle)
{
cout << name << ": TestClientRegistration-onRemoved" << endl;
regcallbackcalled = true;
}
};
class TestClientSubscriptionHandler : public ClientSubscriptionHandler
{
public:
Data name;
bool subcallbackcalled;
TestClientSubscriptionHandler(const Data& n) : name(n), subcallbackcalled(false){};
virtual ~TestClientSubscriptionHandler(){};
virtual void onRefreshRejected(ClientSubscriptionHandle h, const SipMessage& rejection)
{
cout << name << ": TestClientSubscription-onRefreshRejected - " << rejection << endl;
subcallbackcalled = true;
}
virtual void onUpdatePending(resip::ClientSubscriptionHandle h, const SipMessage& notify)
{
cout << name << ": TestClientSubscription-onUpdatePending - " << notify << endl;
subcallbackcalled = true;
}
virtual void onUpdateActive(resip::ClientSubscriptionHandle h, const SipMessage& notify)
{
cout << name << ": TestClientSubscription-onUpdateActive - " << notify << endl;
subcallbackcalled = true;
}
virtual void onUpdateExtension(resip::ClientSubscriptionHandle h, const SipMessage& notify)
{
cout << name << ": TestClientSubscription-onUpdateExtension - " << notify << endl;
subcallbackcalled = true;
}
virtual void onTerminated(resip::ClientSubscriptionHandle h, const SipMessage& msg)
{
cout << name << ": TestClientSubscription-onTerminated - " << msg << endl;
subcallbackcalled = true;
}
virtual void onNewSubscription(resip::ClientSubscriptionHandle h, const SipMessage& notify)
{
cout << name << ": TestClientSubscription-onNewSubscription - " << notify << endl;
subcallbackcalled = true;
}
};
class TestShutdownHandler : public DumShutdownHandler
{
public:
Data name;
bool dumShutDown;
TestShutdownHandler(const Data& n) : name(n), dumShutDown(false) { }
virtual ~TestShutdownHandler(){}
virtual void onDumCanBeDeleted()
{
cout << name << ": onDumCanBeDeleted." << endl;
dumShutDown = true;
}
};
// Set this to 1 to run test with register requests, 0 to run with subscribe requests.
// Makes no difference, stack segfaults in both cases.
#define TEST_WITH_REGISTER 1
int main (int argc, char** argv)
{
Log::initialize(Log::Cout, resip::Log::Debug, argv[0]);
//Log::initialize(Log::Cout, resip::Log::Warning, argv[0]);
while ( 1 )
//for (int i = 0; i<10; ++i)
{
DialogUsageManager* dumUac = new DialogUsageManager();
dumUac->addTransport(UDP, 10000);
Profile uacProfile;
dumUac->setProfile(&uacProfile);
TestClientRegistrationHandler uacCrh("UAC Reg Handler");
dumUac->setClientRegistrationHandler(&uacCrh);
TestClientSubscriptionHandler uacCsh("UAC Sub Handler");
dumUac->addClientSubscriptionHandler( Data("Presence"), &uacCsh );
auto_ptr<testAppDialogSetFactory> uacDsf(new testAppDialogSetFactory());
dumUac->setAppDialogSetFactory( static_cast<std::auto_ptr<resip::AppDialogSetFactory> >( uacDsf ) );
// Please set to your own host/domain - cannot be an IP address.
NameAddr uacAor("sip:user@xxxxxxxxxxxxxxxxxxxxxx:10000");
NameAddr subTo("sip:user2@xxxxxxxxxxxxxxxxxxxxxx:10000");
dumUac->getProfile()->setDefaultFrom(uacAor);
#if TEST_WITH_REGISTER
SipMessage& regMessage = dumUac->makeRegistration(uacAor, new testAppDialogSet(*dumUac, "UAC(REGISTER)"));
//cout << "Sending register for Uac: " << endl << regMessage << endl;
dumUac->send(regMessage);
#else
SipMessage& subMessage = dumUac->makeSubscription( subTo, uacAor, Data("Presence"), 30, new testAppDialogSet(*dumUac, "UAC(SUBSCRIBE)") );
dumUac->send(subMessage);
#endif
TestShutdownHandler uacShutdownHandler("UAC Shutdown Handler");
while (!(uacShutdownHandler.dumShutDown))
{
if (!uacShutdownHandler.dumShutDown)
{
FdSet fdset;
dumUac->buildFdSet(fdset);
int err = fdset.selectMilliSeconds(dumUac->getTimeTillNextProcessMS());
assert ( err != -1 );
dumUac->process(fdset);
}
#if TEST_WITH_REGISTER
if( uacCrh.regcallbackcalled && !uacShutdownHandler.dumShutDown )
#else
if( uacCsh.subcallbackcalled && !uacShutdownHandler.dumShutDown )
#endif
dumUac->shutdown(&uacShutdownHandler);
}
delete dumUac;
cout << "!!!!!!!!!!! DUM Deleted - Starting up again!!!!!!!!!!! " << endl << endl;
}
}