< Previous by Date Date Index Next by Date >
  Thread Index Next in Thread >

[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; 
	}
}