<commit_before>// Copyright (c) 2014 Dims dev-team
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "acceptNodeAction.h"
#include "common/setResponseVisitor.h"
#include "common/commonEvents.h"
#include "common/authenticationProvider.h"
#include "common/mediumRequests.h"

#include <boost/statechart/simple_state.hpp>
#include <boost/statechart/state.hpp>
#include <boost/statechart/transition.hpp>
#include <boost/statechart/custom_reaction.hpp>

#include "acceptNodeAction.h"
#include "seedNodesManager.h"
#include "seedNodeMedium.h"

#include "seedDb.h"
#include "seedFilter.h"

namespace seed
{
extern CAddrDb db;

struct CUnconnected; struct CBothUnidentifiedConnected;

struct CUninitiated : boost::statechart::simple_state< CUninitiated, CAcceptNodeAction >
{
	typedef boost::mpl::list<
	boost::statechart::transition< common::CSwitchToConnectingEvent, CUnconnected >,
	boost::statechart::transition< common::CSwitchToConnectedEvent, CBothUnidentifiedConnected >
	> reactions;

};

struct CIdentified : boost::statechart::state< CIdentified, CAcceptNodeAction >
{
	CIdentified( my_context ctx ) : my_base( ctx )
	{
		context< CAcceptNodeAction >().setValid( true );
		context< CAcceptNodeAction >().setRequest( 0 );
	}
};

template < class Parent >
void
createIdentifyResponse( Parent & parent )
{
	uint256 hash = Hash( &parent.getPayload().front(), &parent.getPayload().back() );

	std::vector< unsigned char > signedHash;
	common::CAuthenticationProvider::getInstance()->sign( hash, signedHash );

	parent.setRequest( new common::CIdentifyResponse<SeedResponses>( new CSpecificMediumFilter( parent.getMediumPtr() ), signedHash, common::CAuthenticationProvider::getInstance()->getMyKey(), parent.getPayload(), parent.getActionKey() ) );
}

struct ConnectedToTracker;
struct ConnectedToSeed;
struct ConnectedToMonitor;

struct CPairIdentifiedConnecting : boost::statechart::state< CPairIdentifiedConnecting, CAcceptNodeAction >
{
	CPairIdentifiedConnecting( my_context ctx ) : my_base( ctx )
	{
		common::CIntroduceEvent const* requestedEvent = dynamic_cast< common::CIntroduceEvent const* >( simple_state::triggering_event() );

		uint256 hash = Hash( &requestedEvent->m_payload.front(), &requestedEvent->m_payload.back() );

		if ( requestedEvent->m_key.Verify( hash, requestedEvent->m_signed ) )
		{
			createIdentifyResponse( context< CAcceptNodeAction >() );
		}
		else
		{
			context< CAcceptNodeAction >().setRequest( 0 );
		}

	}

	boost::statechart::result react( common::CContinueEvent const & _continueEvent )
	{
		context< CAcceptNodeAction >().setRequest( new common::CContinueReqest<SeedResponses>( _continueEvent.m_keyId, new CSpecificMediumFilter( context< CAcceptNodeAction >().getMediumPtr() ) ) );
	}

	boost::statechart::result react( common::CRoleEvent const & _roleEvent )
	{
		context< CAcceptNodeAction >().setRequest( new common::CNetworkRoleRequest<SeedResponses>( context< CAcceptNodeAction >().getActionKey(), common::CRole::Seed, new CSpecificMediumFilter( context< CAcceptNodeAction >().getMediumPtr() ) ) );

		switch ( _roleEvent.m_role )
		{
		case common::CRole::Tracker:
			return transit< ConnectedToTracker >();
		case common::CRole::Seed:
			return transit< ConnectedToSeed >();
		case common::CRole::Monitor:
			return transit< ConnectedToMonitor >();
		default:
			break;
		}
	}

	typedef boost::mpl::list<
	boost::statechart::custom_reaction< common::CRoleEvent >,
	boost::statechart::custom_reaction< common::CContinueEvent >
	> reactions;

};

struct CPairIdentifiedConnected : boost::statechart::state< CPairIdentifiedConnected, CAcceptNodeAction >
{
	CPairIdentifiedConnected( my_context ctx ) : my_base( ctx )
	{
		common::CIntroduceEvent const* requestedEvent = dynamic_cast< common::CIntroduceEvent const* >( simple_state::triggering_event() );

		uint256 hash = Hash( &requestedEvent->m_payload.front(), &requestedEvent->m_payload.back() );

		if ( requestedEvent->m_key.Verify( hash, requestedEvent->m_signed ) )
		{
			m_address = requestedEvent->m_address;

			CSeedNodesManager::getInstance()->setPublicKey( m_address, requestedEvent->m_key );

			context< CAcceptNodeAction >().setRequest( new common::CNetworkRoleRequest<SeedResponses>( context< CAcceptNodeAction >().getActionKey(), common::CRole::Seed, new CSpecificMediumFilter( context< CAcceptNodeAction >().getMediumPtr() ) ) );
		}
		else
		{
			context< CAcceptNodeAction >().setValid( false );
			context< CAcceptNodeAction >().setRequest( 0 );
		}
	}

	boost::statechart::result react( const common::CContinueEvent & _continueEvent )
	{
		context< CAcceptNodeAction >().setRequest( new common::CContinueReqest<SeedResponses>( _continueEvent.m_keyId, new CSpecificMediumFilter( context< CAcceptNodeAction >().getMediumPtr() ) ) );
	}

	boost::statechart::result react( common::CRoleEvent const & _roleEvent )
	{
		switch ( _roleEvent.m_role )
		{
		case common::CRole::Tracker:
			db.Add(m_address);
			return transit< ConnectedToTracker >();
		case common::CRole::Seed:
			return transit< ConnectedToSeed >();
		case common::CRole::Monitor:
			db.Add(m_address);
			return transit< ConnectedToMonitor >();
		default:
			break;
		}
	}

	typedef boost::mpl::list<
	boost::statechart::custom_reaction< common::CRoleEvent >,
	boost::statechart::custom_reaction< common::CContinueEvent >
	> reactions;

	CAddress m_address;

};

struct CBothUnidentifiedConnecting : boost::statechart::state< CBothUnidentifiedConnecting, CAcceptNodeAction >
{
	CBothUnidentifiedConnecting( my_context ctx ) : my_base( ctx )
	{

		common::CNodeConnectedEvent const* connectedEvent = dynamic_cast< common::CNodeConnectedEvent const* >( simple_state::triggering_event() );
		context< CAcceptNodeAction >().setMediumPtr( convertToInt( connectedEvent->m_node ) );
		// looks funny that  I set it in this  state, but let  it  be
		CSeedNodesManager::getInstance()->addNode( new CSeedNodeMedium( connectedEvent->m_node ) );
		context< CAcceptNodeAction >().setRequest( new common::CIdentifyRequest<SeedResponses>( new CSpecificMediumFilter( convertToInt( connectedEvent->m_node ) ), context< CAcceptNodeAction >().getPayload(), context< CAcceptNodeAction >().getActionKey() ) );

	}

	boost::statechart::result react( const common::CContinueEvent & _continueEvent )
	{
		context< CAcceptNodeAction >().setRequest( new common::CContinueReqest<SeedResponses>( _continueEvent.m_keyId, new CSpecificMediumFilter( context< CAcceptNodeAction >().getMediumPtr() ) ) );
	}

	typedef boost::mpl::list<
	boost::statechart::transition< common::CIntroduceEvent, CPairIdentifiedConnecting >,
	boost::statechart::custom_reaction< common::CContinueEvent >
	> reactions;
};

struct CBothUnidentifiedConnected : boost::statechart::state< CBothUnidentifiedConnected, CAcceptNodeAction >
{
	CBothUnidentifiedConnected( my_context ctx ) : my_base( ctx )
	{
		createIdentifyResponse( context< CAcceptNodeAction >() );

	}

	boost::statechart::result react( const common::CContinueEvent & _continueEvent )
	{
		context< CAcceptNodeAction >().setRequest( new common::CContinueReqest<SeedResponses>( _continueEvent.m_keyId, new CSpecificMediumFilter( context< CAcceptNodeAction >().getMediumPtr() ) ) );
	}

	typedef boost::mpl::list<
	boost::statechart::transition< common::CIntroduceEvent, CPairIdentifiedConnected >,
	boost::statechart::custom_reaction< common::CContinueEvent >
	> reactions;
};

struct CCantReachNode : boost::statechart::state< CCantReachNode, CAcceptNodeAction >
{
	CCantReachNode( my_context ctx ) : my_base( ctx )
	{
		context< CAcceptNodeAction >().setValid( false );
		context< CAcceptNodeAction >().setRequest( 0 );
	}
};

struct CUnconnected : boost::statechart::state< CUnconnected, CAcceptNodeAction >
{
	CUnconnected( my_context ctx ) : my_base( ctx )
	{
		context< CAcceptNodeAction >().setRequest(
				  new common::CConnectToNodeRequest< SeedResponses >( std::string(""), context< CAcceptNodeAction >().getAddress(), new CInternalMediumFilter() ) );

	}

	typedef boost::mpl::list<
	boost::statechart::transition< common::CNodeConnectedEvent, CBothUnidentifiedConnecting >,
	boost::statechart::transition< common::CCantReachNode, CCantReachNode >
	> reactions;

};

struct ConnectedToTracker : boost::statechart::state< ConnectedToTracker, CAcceptNodeAction >
{
	// system is not suitable for sending many requests one after another
	// play  ugly here to overcome this
	// maybe instead of  this mess use ack event to  confirm
	ConnectedToTracker( my_context ctx ) : my_base( ctx ), m_request( 0 )
	{
		context< CAcceptNodeAction >().setValid( true );

		if ( !context< CAcceptNodeAction >().getRequest() )// allow execution if something is there
		{
			context< CAcceptNodeAction >().setRequest(
						new common::CKnownNetworkInfoRequest< SeedResponses >( context< CAcceptNodeAction >().getActionKey(), std::vector< common::CValidNodeInfo >(), new CSpecificMediumFilter( context< CAcceptNodeAction >().getMediumPtr() ) ) );// vicious usage of CKnownNetworkInfoRequest
		}
		else
		{
			m_request = new common::CKnownNetworkInfoRequest< SeedResponses >( context< CAcceptNodeAction >().getActionKey(), std::vector< common::CValidNodeInfo >(), new CSpecificMediumFilter( context< CAcceptNodeAction >().getMediumPtr() ) );
		}
	}

	boost::statechart::result react( common::CNetworkInfoEvent const & _networkInfo )
	{
		context< CAcceptNodeAction >().setRequest( 0 );

		BOOST_FOREACH( common::CValidNodeInfo validNodeInfo, _networkInfo.m_networkInfo )
		{
			if ( validNodeInfo.m_role == common::CRole::Tracker || validNodeInfo.m_role == common::CRole::Monitor )
			{
				db.Add( validNodeInfo.m_address );
			}
		}
	}

	boost::statechart::result react( const common::CContinueEvent & _continueEvent )
	{
		if ( m_request )
			context< CAcceptNodeAction >().setRequest( m_request );
		else
			context< CAcceptNodeAction >().setRequest( new common::CContinueReqest< SeedResponses >( _continueEvent.m_keyId, new CSpecificMediumFilter( context< CAcceptNodeAction >().getMediumPtr() ) ) );
	}

	typedef boost::mpl::list<
	boost::statechart::custom_reaction< common::CNetworkInfoEvent >,
	boost::statechart::custom_reaction< common::CContinueEvent >
	> reactions;

	common::CRequest< SeedResponses >* m_request;
};

struct ConnectedToSeed : boost::statechart::state< ConnectedToSeed, CAcceptNodeAction >
{
	ConnectedToSeed( my_context ctx ) : my_base( ctx )
	{
		context< CAcceptNodeAction >().setRequest( 0 );
	}
};

struct ConnectedToMonitor : boost::statechart::state< ConnectedToMonitor, CAcceptNodeAction >
{
	ConnectedToMonitor( my_context ctx ) : my_base( ctx )
	{
		context< CAcceptNodeAction >().setRequest( 0 );
	}
};

struct CSynchronizing : boost::statechart::simple_state< CSynchronizing, CAcceptNodeAction >
{

};

CAcceptNodeAction::CAcceptNodeAction( uint256 const & _actionKey, std::vector< unsigned char > const & _payload, uintptr_t _mediumPtr )
: common::CCommunicationAction( _actionKey )
, m_payload( _payload )
, m_request( 0 )
, m_passive( true )
, m_mediumPtr( _mediumPtr )
, m_valid( false )
{
	initiate();
	process_event( common::CSwitchToConnectedEvent() );
}

CAcceptNodeAction::CAcceptNodeAction( CAddress const & _nodeAddress )
	: common::CAction< SeedResponses >( false )
	, m_nodeAddress( _nodeAddress )
	, m_request( 0 )
	, m_passive( false )
	, m_valid( false )
{
	for ( unsigned int i = 0; i < ms_randomPayloadLenght; i++ )
	{
		m_payload.push_back( insecure_rand() % 256 );
	}
	initiate();
	process_event( common::CSwitchToConnectingEvent() );
}

common::CRequest< SeedResponses >*
CAcceptNodeAction::execute()
{
	common::CRequest< SeedResponses >* request = m_request;
	m_request = 0;
	return request;
}

void
CAcceptNodeAction::accept( common::CSetResponseVisitor< SeedResponses > & _visitor )
{
	_visitor.visit( *this );
}

void
CAcceptNodeAction::setRequest( common::CRequest< SeedResponses >* _request )
{
	m_request = _request;
}

common::CRequest< SeedResponses > const *
CAcceptNodeAction::getRequest() const
{
	return m_request;
}

CAddress
CAcceptNodeAction::getAddress() const
{
	return m_nodeAddress;
}

std::vector< unsigned char > const &
CAcceptNodeAction::getPayload() const
{
	return m_payload;
}

uintptr_t
CAcceptNodeAction::getMediumPtr() const
{
	return m_mediumPtr;
}

void
CAcceptNodeAction::setMediumPtr( uintptr_t _mediumPtr )
{
	m_mediumPtr = _mediumPtr;
}

}
<commit_msg>debugging communication  seed, tracker<commit_after>// Copyright (c) 2014 Dims dev-team
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "acceptNodeAction.h"
#include "common/setResponseVisitor.h"
#include "common/commonEvents.h"
#include "common/authenticationProvider.h"
#include "common/mediumRequests.h"

#include <boost/statechart/simple_state.hpp>
#include <boost/statechart/state.hpp>
#include <boost/statechart/transition.hpp>
#include <boost/statechart/custom_reaction.hpp>

#include "acceptNodeAction.h"
#include "seedNodesManager.h"
#include "seedNodeMedium.h"

#include "seedDb.h"
#include "seedFilter.h"

// ugly as hell, refactor as soon as possible
namespace seed
{
extern CAddrDb db;

struct CUnconnected; struct CBothUnidentifiedConnected;

struct CUninitiated : boost::statechart::simple_state< CUninitiated, CAcceptNodeAction >
{
	typedef boost::mpl::list<
	boost::statechart::transition< common::CSwitchToConnectingEvent, CUnconnected >,
	boost::statechart::transition< common::CSwitchToConnectedEvent, CBothUnidentifiedConnected >
	> reactions;

};

struct CIdentified : boost::statechart::state< CIdentified, CAcceptNodeAction >
{
	CIdentified( my_context ctx ) : my_base( ctx )
	{
		context< CAcceptNodeAction >().setValid( true );
		context< CAcceptNodeAction >().setRequest( 0 );
	}
};

template < class Parent >
void
createIdentifyResponse( Parent & parent )
{
	uint256 hash = Hash( &parent.getPayload().front(), &parent.getPayload().back() );

	std::vector< unsigned char > signedHash;
	common::CAuthenticationProvider::getInstance()->sign( hash, signedHash );

	parent.setRequest( new common::CIdentifyResponse<SeedResponses>( new CSpecificMediumFilter( parent.getMediumPtr() ), signedHash, common::CAuthenticationProvider::getInstance()->getMyKey(), parent.getPayload(), parent.getActionKey() ) );
}

struct ConnectedToTracker;
struct ConnectedToSeed;
struct ConnectedToMonitor;

struct CPairIdentifiedConnecting : boost::statechart::state< CPairIdentifiedConnecting, CAcceptNodeAction >
{
	CPairIdentifiedConnecting( my_context ctx ) : my_base( ctx )
	{
		common::CIntroduceEvent const* requestedEvent = dynamic_cast< common::CIntroduceEvent const* >( simple_state::triggering_event() );

		uint256 hash = Hash( &requestedEvent->m_payload.front(), &requestedEvent->m_payload.back() );

		if ( requestedEvent->m_key.Verify( hash, requestedEvent->m_signed ) )
		{
			createIdentifyResponse( context< CAcceptNodeAction >() );
		}
		else
		{
			context< CAcceptNodeAction >().setRequest( 0 );
		}

	}

	boost::statechart::result react( common::CContinueEvent const & _continueEvent )
	{
		context< CAcceptNodeAction >().setRequest( new common::CContinueReqest<SeedResponses>( _continueEvent.m_keyId, new CSpecificMediumFilter( context< CAcceptNodeAction >().getMediumPtr() ) ) );
	}

	boost::statechart::result react( common::CRoleEvent const & _roleEvent )
	{
		context< CAcceptNodeAction >().setRequest( new common::CNetworkRoleRequest<SeedResponses>( context< CAcceptNodeAction >().getActionKey(), common::CRole::Seed, new CSpecificMediumFilter( context< CAcceptNodeAction >().getMediumPtr() ) ) );

		switch ( _roleEvent.m_role )
		{
		case common::CRole::Tracker:
			return transit< ConnectedToTracker >();
		case common::CRole::Seed:
			return transit< ConnectedToSeed >();
		case common::CRole::Monitor:
			return transit< ConnectedToMonitor >();
		default:
			break;
		}
	}

	typedef boost::mpl::list<
	boost::statechart::custom_reaction< common::CRoleEvent >,
	boost::statechart::custom_reaction< common::CContinueEvent >
	> reactions;

};

struct CPairIdentifiedConnected : boost::statechart::state< CPairIdentifiedConnected, CAcceptNodeAction >
{
	CPairIdentifiedConnected( my_context ctx ) : my_base( ctx )
	{
		common::CIntroduceEvent const* requestedEvent = dynamic_cast< common::CIntroduceEvent const* >( simple_state::triggering_event() );

		uint256 hash = Hash( &requestedEvent->m_payload.front(), &requestedEvent->m_payload.back() );

		if ( requestedEvent->m_key.Verify( hash, requestedEvent->m_signed ) )
		{
			m_address = requestedEvent->m_address;

			CSeedNodesManager::getInstance()->setPublicKey( m_address, requestedEvent->m_key );

			context< CAcceptNodeAction >().setRequest( new common::CNetworkRoleRequest<SeedResponses>( context< CAcceptNodeAction >().getActionKey(), common::CRole::Seed, new CSpecificMediumFilter( context< CAcceptNodeAction >().getMediumPtr() ) ) );
		}
		else
		{
			context< CAcceptNodeAction >().setValid( false );
			context< CAcceptNodeAction >().setRequest( 0 );
		}
	}

	boost::statechart::result react( const common::CContinueEvent & _continueEvent )
	{
		context< CAcceptNodeAction >().setRequest( new common::CContinueReqest<SeedResponses>( _continueEvent.m_keyId, new CSpecificMediumFilter( context< CAcceptNodeAction >().getMediumPtr() ) ) );
	}

	boost::statechart::result react( common::CRoleEvent const & _roleEvent )
	{
		switch ( _roleEvent.m_role )
		{
		case common::CRole::Tracker:
			db.Add(m_address);
			return transit< ConnectedToTracker >();
		case common::CRole::Seed:
			return transit< ConnectedToSeed >();
		case common::CRole::Monitor:
			db.Add(m_address);
			return transit< ConnectedToMonitor >();
		default:
			break;
		}
	}

	typedef boost::mpl::list<
	boost::statechart::custom_reaction< common::CRoleEvent >,
	boost::statechart::custom_reaction< common::CContinueEvent >
	> reactions;

	CAddress m_address;

};

struct CBothUnidentifiedConnecting : boost::statechart::state< CBothUnidentifiedConnecting, CAcceptNodeAction >
{
	CBothUnidentifiedConnecting( my_context ctx ) : my_base( ctx )
	{

		common::CNodeConnectedEvent const* connectedEvent = dynamic_cast< common::CNodeConnectedEvent const* >( simple_state::triggering_event() );
		context< CAcceptNodeAction >().setMediumPtr( convertToInt( connectedEvent->m_node ) );
		// looks funny that  I set it in this  state, but let  it  be
		CSeedNodesManager::getInstance()->addNode( new CSeedNodeMedium( connectedEvent->m_node ) );
		context< CAcceptNodeAction >().setRequest( new common::CIdentifyRequest<SeedResponses>( new CSpecificMediumFilter( convertToInt( connectedEvent->m_node ) ), context< CAcceptNodeAction >().getPayload(), context< CAcceptNodeAction >().getActionKey() ) );

	}

	boost::statechart::result react( const common::CContinueEvent & _continueEvent )
	{
		context< CAcceptNodeAction >().setRequest( new common::CContinueReqest<SeedResponses>( _continueEvent.m_keyId, new CSpecificMediumFilter( context< CAcceptNodeAction >().getMediumPtr() ) ) );
	}

	typedef boost::mpl::list<
	boost::statechart::transition< common::CIntroduceEvent, CPairIdentifiedConnecting >,
	boost::statechart::custom_reaction< common::CContinueEvent >
	> reactions;
};

struct CBothUnidentifiedConnected : boost::statechart::state< CBothUnidentifiedConnected, CAcceptNodeAction >
{
	CBothUnidentifiedConnected( my_context ctx ) : my_base( ctx )
	{
		createIdentifyResponse( context< CAcceptNodeAction >() );

	}

	boost::statechart::result react( const common::CContinueEvent & _continueEvent )
	{
		context< CAcceptNodeAction >().setRequest( new common::CContinueReqest<SeedResponses>( _continueEvent.m_keyId, new CSpecificMediumFilter( context< CAcceptNodeAction >().getMediumPtr() ) ) );
	}

	typedef boost::mpl::list<
	boost::statechart::transition< common::CIntroduceEvent, CPairIdentifiedConnected >,
	boost::statechart::custom_reaction< common::CContinueEvent >
	> reactions;
};

struct CCantReachNode : boost::statechart::state< CCantReachNode, CAcceptNodeAction >
{
	CCantReachNode( my_context ctx ) : my_base( ctx )
	{
		context< CAcceptNodeAction >().setValid( false );
		context< CAcceptNodeAction >().setRequest( 0 );
	}
};

struct CUnconnected : boost::statechart::state< CUnconnected, CAcceptNodeAction >
{
	CUnconnected( my_context ctx ) : my_base( ctx )
	{
		context< CAcceptNodeAction >().setRequest(
				  new common::CConnectToNodeRequest< SeedResponses >( std::string(""), context< CAcceptNodeAction >().getAddress(), new CInternalMediumFilter() ) );

	}

	typedef boost::mpl::list<
	boost::statechart::transition< common::CNodeConnectedEvent, CBothUnidentifiedConnecting >,
	boost::statechart::transition< common::CCantReachNode, CCantReachNode >
	> reactions;

};

struct ConnectedToTracker : boost::statechart::state< ConnectedToTracker, CAcceptNodeAction >
{
	// system is not suitable for sending many requests one after another
	// play  ugly here to overcome this
	// maybe instead of  this mess use ack event to  confirm
	ConnectedToTracker( my_context ctx ) : my_base( ctx ), m_request( 0 )
	{
		context< CAcceptNodeAction >().setValid( true );

		if ( !context< CAcceptNodeAction >().getRequest() )// allow execution if something is there
		{
			context< CAcceptNodeAction >().setRequest(
						new common::CKnownNetworkInfoRequest< SeedResponses >( context< CAcceptNodeAction >().getActionKey(), std::vector< common::CValidNodeInfo >(), new CSpecificMediumFilter( context< CAcceptNodeAction >().getMediumPtr() ) ) );// vicious usage of CKnownNetworkInfoRequest
		}
		else
		{
			m_request = new common::CKnownNetworkInfoRequest< SeedResponses >( context< CAcceptNodeAction >().getActionKey(), std::vector< common::CValidNodeInfo >(), new CSpecificMediumFilter( context< CAcceptNodeAction >().getMediumPtr() ) );
		}
	}

	boost::statechart::result react( common::CNetworkInfoEvent const & _networkInfo )
	{
		context< CAcceptNodeAction >().setRequest( 0 );

		BOOST_FOREACH( common::CValidNodeInfo validNodeInfo, _networkInfo.m_networkInfo )
		{
			if ( validNodeInfo.m_role == common::CRole::Tracker || validNodeInfo.m_role == common::CRole::Monitor )
			{
				db.Add( validNodeInfo.m_address );
			}
		}
	}

	boost::statechart::result react( const common::CContinueEvent & _continueEvent )
	{
		if ( m_request )
		{
			context< CAcceptNodeAction >().setRequest( m_request );
			m_request = 0;
		}
		else
			context< CAcceptNodeAction >().setRequest( new common::CContinueReqest< SeedResponses >( _continueEvent.m_keyId, new CSpecificMediumFilter( context< CAcceptNodeAction >().getMediumPtr() ) ) );
	}

	typedef boost::mpl::list<
	boost::statechart::custom_reaction< common::CNetworkInfoEvent >,
	boost::statechart::custom_reaction< common::CContinueEvent >
	> reactions;

	common::CRequest< SeedResponses >* m_request;
};

struct ConnectedToSeed : boost::statechart::state< ConnectedToSeed, CAcceptNodeAction >
{
	ConnectedToSeed( my_context ctx ) : my_base( ctx )
	{
		context< CAcceptNodeAction >().setRequest( 0 );
	}
};

struct ConnectedToMonitor : boost::statechart::state< ConnectedToMonitor, CAcceptNodeAction >
{
	ConnectedToMonitor( my_context ctx ) : my_base( ctx )
	{
		context< CAcceptNodeAction >().setRequest( 0 );
	}
};

struct CSynchronizing : boost::statechart::simple_state< CSynchronizing, CAcceptNodeAction >
{

};

CAcceptNodeAction::CAcceptNodeAction( uint256 const & _actionKey, std::vector< unsigned char > const & _payload, uintptr_t _mediumPtr )
: common::CCommunicationAction( _actionKey )
, m_payload( _payload )
, m_request( 0 )
, m_passive( true )
, m_mediumPtr( _mediumPtr )
, m_valid( false )
{
	initiate();
	process_event( common::CSwitchToConnectedEvent() );
}

CAcceptNodeAction::CAcceptNodeAction( CAddress const & _nodeAddress )
	: common::CAction< SeedResponses >( false )
	, m_nodeAddress( _nodeAddress )
	, m_request( 0 )
	, m_passive( false )
	, m_valid( false )
{
	for ( unsigned int i = 0; i < ms_randomPayloadLenght; i++ )
	{
		m_payload.push_back( insecure_rand() % 256 );
	}
	initiate();
	process_event( common::CSwitchToConnectingEvent() );
}

common::CRequest< SeedResponses >*
CAcceptNodeAction::execute()
{
	common::CRequest< SeedResponses >* request = m_request;
	m_request = 0;
	return request;
}

void
CAcceptNodeAction::accept( common::CSetResponseVisitor< SeedResponses > & _visitor )
{
	_visitor.visit( *this );
}

void
CAcceptNodeAction::setRequest( common::CRequest< SeedResponses >* _request )
{
	m_request = _request;
}

common::CRequest< SeedResponses > const *
CAcceptNodeAction::getRequest() const
{
	return m_request;
}

CAddress
CAcceptNodeAction::getAddress() const
{
	return m_nodeAddress;
}

std::vector< unsigned char > const &
CAcceptNodeAction::getPayload() const
{
	return m_payload;
}

uintptr_t
CAcceptNodeAction::getMediumPtr() const
{
	return m_mediumPtr;
}

void
CAcceptNodeAction::setMediumPtr( uintptr_t _mediumPtr )
{
	m_mediumPtr = _mediumPtr;
}

}
<|endoftext|>


<commit_before>#ifndef ITER_RANGE_H_
#define ITER_RANGE_H_

// range() for range-based loops with start, stop, and step.
//
// Acceptable forms are:
// for (auto i : range(stop)) { ... } // start = 0, step = 1
// for (auto i : range(start, stop)) { ... } // step = 1
// for (auto i : range(start, stop, step)) { ... }
//
// The start may be greater than the stop if the range is negative
// The range will effectively be empty if:
//   1) step is positive and start > stop
//   2) step is negative and start < stop
//
// If a step of 0 is provided, a RangeException will be thrown

#include <exception>
#include <type_traits>
#include <iterator>

namespace iter {

    // Thrown when step 0 occurs
    class RangeException : public std::exception {
        const char *what() const noexcept override {
            return "range step must be non-zero";
        }
    };

    template <typename T, bool IsFloat =false>
    class Range;

    template <typename T, bool IsFloat =std::is_floating_point<T>::value>
    Range<T, IsFloat> range(T);
    template <typename T, bool IsFloat =std::is_floating_point<T>::value>
    Range<T, IsFloat> range(T, T);
    template <typename T, bool IsFloat =std::is_floating_point<T>::value>
    Range<T, IsFloat> range(T, T, T);

    // General version for everything not a float
    template <typename T, bool>
    class Range {
        friend Range range<T, false>(T);
        friend Range range<T, false>(T, T);
        friend Range range<T, false>(T, T, T);
        private:
            const T start;
            const T stop;
            const T step;

            Range(T in_stop)
                : start{0},
                stop{in_stop},
                step{1}
            { }

            Range(T in_start, T in_stop, T in_step =1)
                : start{in_start},
                stop{in_stop},
                step{in_step}
            { }

        public:
            class Iterator
                : public std::iterator<std::forward_iterator_tag, T>
            {
                private:
                    T value;
                    T step;

                    // compare unsigned values
                    bool not_equal_to(
                            const Iterator& other, std::true_type ) const {
                        return this->value < other.value;
                    }

                    // compare signed values
                    bool not_equal_to(
                            const Iterator& other, std::false_type) const {
                        return !(this->step > 0 && this->value >= other.value)
                            && !(this->step < 0 && this->value <= other.value);
                    }
                public:
                    Iterator() =default;

                    Iterator(T val, T in_step)
                        : value{val},
                        step{in_step}
                    { }

                    T operator*() const {
                        return this->value;
                    }

                    Iterator& operator++() {
                        this->value += this->step;
                        return *this;
                    }

                    Iterator operator++(int) {
                        auto ret = *this;
                        ++*this;
                        return ret;
                    }

                    // This operator would more accurately read as "in bounds"
                    // or "incomplete" because exact comparison with the end
                    // isn't good enough for the purposes of this Iterator.
                    // There are two odd cases that need to be handled
                    //
                    // 1) The Range is infinite, such as
                    // Range (-1, 0, -1) which would go forever down toward
                    // infinitely (theoretically).  If this occurs, the Range
                    // will instead effectively be empty
                    //
                    // 2) (stop - start) % step != 0.  For
                    // example Range(1, 10, 2).  The iterator will never be
                    // exactly equal to the stop value.
                    //
                    // Another way to think about it is that the "end"
                    // iterator represents the range of values that are invalid
                    // So, if an iterator is not equal to that, it is valid
                    bool operator!=(const Iterator& other) const {
                        return not_equal_to(
                                other, typename std::is_unsigned<T>::type());
                    }

                    bool operator==(const Iterator& other) const {
                        return !(*this != other);
                    }
            };

            Iterator begin() const {
                return {start, step};
            }

            Iterator end() const {
                return {stop, step};
            }
    };

    // This specialization is used for floating point types.  Instead of
    // adding one "step" each time ++ is called on the iterator, the value
    // is recalculated as start + (steps_taken + step_size) to avoid
    // accumulating floating point inaccuracies
    template <typename T>
    class Range<T, true> {
        friend Range range<T, true>(T);
        friend Range range<T, true>(T, T);
        friend Range range<T, true>(T, T, T);
        private:
            const T start;
            const T stop;
            const T step;

            Range(T in_stop)
                : start{0},
                stop{in_stop},
                step{1}
            { }

            Range(T in_start, T in_stop, T in_step =1)
                : start{in_start},
                stop{in_stop},
                step{in_step}
            { }
        public:
            class Iterator
                : public std::iterator<std::forward_iterator_tag, T>
            {
                private:
                    T start;
                    T value;
                    T step;
                    unsigned long steps_taken =0;

                public:
                    Iterator() =default;

                    Iterator(T in_start, T in_step)
                        : start{in_start},
                        value{in_start},
                        step{in_step}
                    { }

                    bool operator!=(const Iterator& other) const {
                        return !(this->step > 0 && this->value >= other.value)
                            && !(this->step < 0 && this->value <= other.value);
                    }

                    bool operator==(const Iterator& other) const {
                        return !(*this != other);
                    }

                    T operator*() const {
                        return this->value;
                    }

                    Iterator& operator++() {
                        ++this->steps_taken;
                        this->value = this->start +
                            (this->step * this->steps_taken);
                        return *this;
                    }

                    Iterator operator++(int) {
                        auto ret = *this;
                        ++*this;
                        return ret;
                    }
            };

            Iterator begin() const {
                return {start, step};
            }

            Iterator end() const {
                return {stop, step};
            }
    };

    template <typename T, bool IsFloat>
    Range<T, IsFloat> range(T stop) {
        return {stop};
    }

    template <typename T, bool IsFloat>
    Range<T, IsFloat> range(T start, T stop) {
        return {start, stop};
    }

    template <typename T, bool IsFloat>
    Range<T, IsFloat> range(T start, T stop, T step) {
        if (step == 0) {
            throw RangeException{};
        }
        return {start, stop, step};
    }
}

#endif // #ifndef ITER_RANGE_H_
<commit_msg>range can compare arbitrary iterators<commit_after>#ifndef ITER_RANGE_H_
#define ITER_RANGE_H_

// range() for range-based loops with start, stop, and step.
//
// Acceptable forms are:
// for (auto i : range(stop)) { ... } // start = 0, step = 1
// for (auto i : range(start, stop)) { ... } // step = 1
// for (auto i : range(start, stop, step)) { ... }
//
// The start may be greater than the stop if the range is negative
// The range will effectively be empty if:
//   1) step is positive and start > stop
//   2) step is negative and start < stop
//
// If a step of 0 is provided, a RangeException will be thrown

#include <exception>
#include <type_traits>
#include <iterator>
#include <cassert>

namespace iter {

    // Thrown when step 0 occurs
    class RangeException : public std::exception {
        const char *what() const noexcept override {
            return "range step must be non-zero";
        }
    };

    template <typename T, bool IsFloat =false>
    class Range;

    template <typename T, bool IsFloat =std::is_floating_point<T>::value>
    Range<T, IsFloat> range(T);
    template <typename T, bool IsFloat =std::is_floating_point<T>::value>
    Range<T, IsFloat> range(T, T);
    template <typename T, bool IsFloat =std::is_floating_point<T>::value>
    Range<T, IsFloat> range(T, T, T);

    // General version for everything not a float
    template <typename T, bool>
    class Range {
        friend Range range<T, false>(T);
        friend Range range<T, false>(T, T);
        friend Range range<T, false>(T, T, T);
        private:
            const T start;
            const T stop;
            const T step;

            Range(T in_stop)
                : start{0},
                stop{in_stop},
                step{1}
            { }

            Range(T in_start, T in_stop, T in_step =1)
                : start{in_start},
                stop{in_stop},
                step{in_step}
            { }

        public:
            class Iterator
                : public std::iterator<std::forward_iterator_tag, T>
            {
                private:
                    T value;
                    T step;
                    bool is_end;

                    // compare unsigned values
                    static bool not_equal_to_impl(
                            const Iterator& iter, const Iterator& end_iter,
                            std::true_type ) {
                        assert(!iter.is_end);
                        assert(end_iter.is_end);
                        return iter.value < end_iter.value;
                    }

                    // compare signed values
                    static bool not_equal_to_impl(
                            const Iterator& iter, const Iterator& end_iter,
                            std::false_type) {
                        assert(!iter.is_end);
                        assert(end_iter.is_end);
                        return !(iter.step > 0 && iter.value >= end_iter.value)
                            && !(iter.step < 0 && iter.value <= end_iter.value);
                    }

                    static bool not_equal_to_end(
                            const Iterator& lhs, const Iterator& rhs) {
                        if (rhs.is_end) {
                            return not_equal_to_impl(
                                    lhs, rhs, std::is_unsigned<T>{});
                        } else {
                            return not_equal_to_impl(
                                    rhs, lhs, std::is_unsigned<T>{});
                        }
                    }

                public:
                    Iterator() =default;

                    Iterator(T val, T in_step, bool in_is_end)
                        : value{val},
                        step{in_step},
                        is_end{in_is_end}
                    { }

                    T operator*() const {
                        return this->value;
                    }

                    Iterator& operator++() {
                        this->value += this->step;
                        return *this;
                    }

                    Iterator operator++(int) {
                        auto ret = *this;
                        ++*this;
                        return ret;
                    }

                    // This operator would more accurately read as "in bounds"
                    // or "incomplete" because exact comparison with the end
                    // isn't good enough for the purposes of this Iterator.
                    // There are two odd cases that need to be handled
                    //
                    // 1) The Range is infinite, such as
                    // Range (-1, 0, -1) which would go forever down toward
                    // infinitely (theoretically).  If this occurs, the Range
                    // will instead effectively be empty
                    //
                    // 2) (stop - start) % step != 0.  For
                    // example Range(1, 10, 2).  The iterator will never be
                    // exactly equal to the stop value.
                    //
                    // Another way to think about it is that the "end"
                    // iterator represents the range of values that are invalid
                    // So, if an iterator is not equal to that, it is valid
                    bool operator!=(const Iterator& other) const {
                        if (this->is_end && other.is_end) {
                            return false;
                        }

                        if (!this->is_end && !other.is_end) {
                            return this->value != other.value;
                        }
                        return not_equal_to_end(*this, other);
                    }

                    bool operator==(const Iterator& other) const {
                        return !(*this != other);
                    }
            };

            Iterator begin() const {
                return {start, step, false};
            }

            Iterator end() const {
                return {stop, step, true};
            }
    };

    // This specialization is used for floating point types.  Instead of
    // adding one "step" each time ++ is called on the iterator, the value
    // is recalculated as start + (steps_taken + step_size) to avoid
    // accumulating floating point inaccuracies
    template <typename T>
    class Range<T, true> {
        friend Range range<T, true>(T);
        friend Range range<T, true>(T, T);
        friend Range range<T, true>(T, T, T);
        private:
            const T start;
            const T stop;
            const T step;

            Range(T in_stop)
                : start{0},
                stop{in_stop},
                step{1}
            { }

            Range(T in_start, T in_stop, T in_step =1)
                : start{in_start},
                stop{in_stop},
                step{in_step}
            { }
        public:
            class Iterator
                : public std::iterator<std::forward_iterator_tag, T>
            {
                private:
                    T start;
                    T value;
                    T step;
                    unsigned long steps_taken =0;

                public:
                    Iterator() =default;

                    Iterator(T in_start, T in_step)
                        : start{in_start},
                        value{in_start},
                        step{in_step}
                    { }

                    bool operator!=(const Iterator& other) const {
                        return !(this->step > 0 && this->value >= other.value)
                            && !(this->step < 0 && this->value <= other.value);
                    }

                    bool operator==(const Iterator& other) const {
                        return !(*this != other);
                    }

                    T operator*() const {
                        return this->value;
                    }

                    Iterator& operator++() {
                        ++this->steps_taken;
                        this->value = this->start +
                            (this->step * this->steps_taken);
                        return *this;
                    }

                    Iterator operator++(int) {
                        auto ret = *this;
                        ++*this;
                        return ret;
                    }
            };

            Iterator begin() const {
                return {start, step};
            }

            Iterator end() const {
                return {stop, step};
            }
    };

    template <typename T, bool IsFloat>
    Range<T, IsFloat> range(T stop) {
        return {stop};
    }

    template <typename T, bool IsFloat>
    Range<T, IsFloat> range(T start, T stop) {
        return {start, stop};
    }

    template <typename T, bool IsFloat>
    Range<T, IsFloat> range(T start, T stop, T step) {
        if (step == 0) {
            throw RangeException{};
        }
        return {start, stop, step};
    }
}

#endif // #ifndef ITER_RANGE_H_
<|endoftext|>


<commit_before>/*************************************************************************
 * Copyright (c) 2014 eProsima. All rights reserved.
 *
 * This copy of eProsima RTPS is licensed to you under the terms described in the
 * EPROSIMARTPS_LIBRARY_LICENSE file included in this distribution.
 *
 *************************************************************************/

/*
 * ResourceSend.cpp
 *
 */

#include "eprosimartps/resources/ResourceSend.h"
#include "eprosimartps/common/types/CDRMessage_t.h"
#include "eprosimartps/utils/RTPSLog.h"

#include "eprosimartps/Participant.h"

using boost::asio::ip::udp;

namespace eprosima {
namespace rtps {

ResourceSend::ResourceSend(ParticipantImpl* par) :
	m_send_socket(m_send_service),
	m_bytes_sent(0),
	m_send_next(true),
	mp_participant(par)
{

}

bool ResourceSend::initSend(const Locator_t& loc)
{
//	boost::asio::ip::address addr;
	m_sendLocator = loc;
//	try {
//		boost::asio::io_service netService;
//		udp::resolver   resolver(netService);
//		udp::resolver::query query(udp::v4(), "google.com", "");
//		udp::resolver::iterator endpoints = resolver.resolve(query);
//		udp::endpoint ep = *endpoints;
//		udp::socket socket(netService);
//		socket.connect(ep);
//		addr = socket.local_endpoint().address();
//
//		pInfo("My IP according to google is: " << addr.to_string() << endl);
//
//		m_sendLocator.address[12] = addr.to_v4().to_bytes()[0];
//		m_sendLocator.address[13] = addr.to_v4().to_bytes()[1];
//		m_sendLocator.address[14] = addr.to_v4().to_bytes()[2];
//		m_sendLocator.address[15] = addr.to_v4().to_bytes()[3];
//	}
//	catch (std::exception& e)
//	{
//		std::cerr << "Could not deal with socket. Exception: " << e.what() << std::endl;
//		m_sendLocator = loc;
//		m_sendLocator.address[12] = 127;
//		m_sendLocator.address[13] = 0;
//		m_sendLocator.address[14] = 0;
//		m_sendLocator.address[15] = 1;
//	}

	m_send_socket.open(boost::asio::ip::udp::v4());
	m_send_socket.set_option(boost::asio::socket_base::send_buffer_size(this->mp_participant->getSendSocketBufferSize()));
	//m_send_socket.set_option( boost::asio::ip::enable_loopback( true ) );
	bool not_bind = true;
	while(not_bind)
	{
		//udp::endpoint send_endpoint = udp::endpoint(boost::asio::ip::address_v4(),sendLocator.port);
		udp::endpoint send_endpoint = udp::endpoint(boost::asio::ip::udp::v4(),m_sendLocator.port);
		//boost::asio::ip::udp::socket s(sendService,send_endpoint);
		try{
			m_send_socket.bind(send_endpoint);
			not_bind = false;
		}
		catch (boost::system::system_error const& e)
		{
			pWarning("ResourceSend: "<<e.what()<< " with socket: " << send_endpoint << endl);
			m_sendLocator.port++;
		}
	}
	boost::asio::socket_base::send_buffer_size option;
	m_send_socket.get_option(option);
	pInfo (RTPS_YELLOW<<"ResourceSend: initSend: " << m_send_socket.local_endpoint()<<"|| State: " << m_send_socket.is_open() <<
			" || buffer size: " <<option.value()<< RTPS_DEF<<endl);

	//boost::asio::io_service::work work(sendService);
	return true;
}

ResourceSend::~ResourceSend()
{
	pDebugInfo("ResourceSend: destructor"<<endl;);
	m_send_socket.close();
	m_send_service.stop();
}

void ResourceSend::sendSync(CDRMessage_t* msg, const Locator_t& loc)
{
	boost::lock_guard<ResourceSend> guard(*this);
	if(loc.port == 0)
		return;
	if(loc.kind == LOCATOR_KIND_UDPv4)
	{
		boost::asio::ip::address_v4::bytes_type addr;
		for(uint8_t i=0;i<4;i++)
			addr[i] = loc.address[12+i];
		m_send_endpoint = udp::endpoint(boost::asio::ip::address_v4(addr),loc.port);
	}
	else if(loc.kind == LOCATOR_KIND_UDPv6)
	{
		boost::asio::ip::address_v6::bytes_type addr;
		for(uint8_t i=0;i<16;i++)
			addr[i] = loc.address[i];
		m_send_endpoint = udp::endpoint(boost::asio::ip::address_v6(addr),loc.port);
	}
	pInfo(RTPS_YELLOW<< "ResourceSend: sendSync: " << msg->length << " bytes TO endpoint: " << m_send_endpoint << " FROM " << m_send_socket.local_endpoint()  << endl);
	if(m_send_endpoint.port()>0)
	{
		m_bytes_sent = 0;
		if(m_send_next)
		{
			try {
				m_bytes_sent = m_send_socket.send_to(boost::asio::buffer((void*)msg->buffer,msg->length),m_send_endpoint);
			} catch (const std::exception& error) {
				// Should print the actual error message
				std::cerr << error.what() << std::endl;
			}

		}
		else
		{
			m_send_next = true;
		}
		pInfo (RTPS_YELLOW <<  "SENT " << m_bytes_sent << RTPS_DEF << endl);
	}
	else if(m_send_endpoint.port()<=0)
	{
		pWarning("ResourceSend: sendSync: port invalid"<<endl);
	}
	else
		pError("ResourceSend: sendSync: port error"<<endl);
}

} /* namespace rtps */
} /* namespace eprosima */
<commit_msg>Send catch error now with pWarning<commit_after>/*************************************************************************
 * Copyright (c) 2014 eProsima. All rights reserved.
 *
 * This copy of eProsima RTPS is licensed to you under the terms described in the
 * EPROSIMARTPS_LIBRARY_LICENSE file included in this distribution.
 *
 *************************************************************************/

/*
 * ResourceSend.cpp
 *
 */

#include "eprosimartps/resources/ResourceSend.h"
#include "eprosimartps/common/types/CDRMessage_t.h"
#include "eprosimartps/utils/RTPSLog.h"

#include "eprosimartps/Participant.h"

using boost::asio::ip::udp;

namespace eprosima {
namespace rtps {

ResourceSend::ResourceSend(ParticipantImpl* par) :
	m_send_socket(m_send_service),
	m_bytes_sent(0),
	m_send_next(true),
	mp_participant(par)
{

}

bool ResourceSend::initSend(const Locator_t& loc)
{
//	boost::asio::ip::address addr;
	m_sendLocator = loc;
//	try {
//		boost::asio::io_service netService;
//		udp::resolver   resolver(netService);
//		udp::resolver::query query(udp::v4(), "google.com", "");
//		udp::resolver::iterator endpoints = resolver.resolve(query);
//		udp::endpoint ep = *endpoints;
//		udp::socket socket(netService);
//		socket.connect(ep);
//		addr = socket.local_endpoint().address();
//
//		pInfo("My IP according to google is: " << addr.to_string() << endl);
//
//		m_sendLocator.address[12] = addr.to_v4().to_bytes()[0];
//		m_sendLocator.address[13] = addr.to_v4().to_bytes()[1];
//		m_sendLocator.address[14] = addr.to_v4().to_bytes()[2];
//		m_sendLocator.address[15] = addr.to_v4().to_bytes()[3];
//	}
//	catch (std::exception& e)
//	{
//		std::cerr << "Could not deal with socket. Exception: " << e.what() << std::endl;
//		m_sendLocator = loc;
//		m_sendLocator.address[12] = 127;
//		m_sendLocator.address[13] = 0;
//		m_sendLocator.address[14] = 0;
//		m_sendLocator.address[15] = 1;
//	}

	m_send_socket.open(boost::asio::ip::udp::v4());
	m_send_socket.set_option(boost::asio::socket_base::send_buffer_size(this->mp_participant->getSendSocketBufferSize()));
	//m_send_socket.set_option( boost::asio::ip::enable_loopback( true ) );
	bool not_bind = true;
	while(not_bind)
	{
		//udp::endpoint send_endpoint = udp::endpoint(boost::asio::ip::address_v4(),sendLocator.port);
		udp::endpoint send_endpoint = udp::endpoint(boost::asio::ip::udp::v4(),m_sendLocator.port);
		//boost::asio::ip::udp::socket s(sendService,send_endpoint);
		try{
			m_send_socket.bind(send_endpoint);
			not_bind = false;
		}
		catch (boost::system::system_error const& e)
		{
			pWarning("ResourceSend: "<<e.what()<< " with socket: " << send_endpoint << endl);
			m_sendLocator.port++;
		}
	}
	boost::asio::socket_base::send_buffer_size option;
	m_send_socket.get_option(option);
	pInfo (RTPS_YELLOW<<"ResourceSend: initSend: " << m_send_socket.local_endpoint()<<"|| State: " << m_send_socket.is_open() <<
			" || buffer size: " <<option.value()<< RTPS_DEF<<endl);

	//boost::asio::io_service::work work(sendService);
	return true;
}

ResourceSend::~ResourceSend()
{
	pDebugInfo("ResourceSend: destructor"<<endl;);
	m_send_socket.close();
	m_send_service.stop();
}

void ResourceSend::sendSync(CDRMessage_t* msg, const Locator_t& loc)
{
	boost::lock_guard<ResourceSend> guard(*this);
	if(loc.port == 0)
		return;
	if(loc.kind == LOCATOR_KIND_UDPv4)
	{
		boost::asio::ip::address_v4::bytes_type addr;
		for(uint8_t i=0;i<4;i++)
			addr[i] = loc.address[12+i];
		m_send_endpoint = udp::endpoint(boost::asio::ip::address_v4(addr),loc.port);
	}
	else if(loc.kind == LOCATOR_KIND_UDPv6)
	{
		boost::asio::ip::address_v6::bytes_type addr;
		for(uint8_t i=0;i<16;i++)
			addr[i] = loc.address[i];
		m_send_endpoint = udp::endpoint(boost::asio::ip::address_v6(addr),loc.port);
	}
	pInfo(RTPS_YELLOW<< "ResourceSend: sendSync: " << msg->length << " bytes TO endpoint: " << m_send_endpoint << " FROM " << m_send_socket.local_endpoint()  << endl);
	if(m_send_endpoint.port()>0)
	{
		m_bytes_sent = 0;
		if(m_send_next)
		{
			try {
				m_bytes_sent = m_send_socket.send_to(boost::asio::buffer((void*)msg->buffer,msg->length),m_send_endpoint);
			} catch (const std::exception& error) {
				// Should print the actual error message
				pWarning(error.what() << std::endl);
			}

		}
		else
		{
			m_send_next = true;
		}
		pInfo (RTPS_YELLOW <<  "SENT " << m_bytes_sent << RTPS_DEF << endl);
	}
	else if(m_send_endpoint.port()<=0)
	{
		pWarning("ResourceSend: sendSync: port invalid"<<endl);
	}
	else
		pError("ResourceSend: sendSync: port error"<<endl);
}

} /* namespace rtps */
} /* namespace eprosima */
<|endoftext|>


<commit_before>// Copyright (c) 2010, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Helper program for the linux_dumper class, which creates a bunch of
// threads. The first word of each thread's stack is set to the thread
// id.

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/syscall.h>
#include <unistd.h>

#if defined(__ARM_EABI__)
#define TID_PTR_REGISTER "r3"
#elif defined(__i386)
#define TID_PTR_REGISTER "ecx"
#elif defined(__x86_64)
#define TID_PTR_REGISTER "rcx"
#else
#error This test has not been ported to this platform.
#endif

void *thread_function(void *data) {
  pid_t thread_id = syscall(SYS_gettid);
  register pid_t *thread_id_ptr asm(TID_PTR_REGISTER) = &thread_id;
  while (true)
    asm("" : : "r" (thread_id_ptr));
  return NULL;
}

int main(int argc, char *argv[]) {
  int num_threads = atoi(argv[1]);
  if (num_threads < 1) {
    fprintf(stderr, "ERROR: number of threads is 0");
    return 1;
  }
  pthread_t threads[num_threads];
  pthread_attr_t thread_attributes;
  pthread_attr_init(&thread_attributes);
  pthread_attr_setdetachstate(&thread_attributes, PTHREAD_CREATE_DETACHED);
  for (int i = 1; i < num_threads; i++) {
    pthread_create(&threads[i], &thread_attributes, &thread_function, NULL);
  }
  thread_function(NULL);
  return 0;
}
<commit_msg>[ Mistakenly committed older version of patch.  This is the right one. ]<commit_after>// Copyright (c) 2010, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Helper program for the linux_dumper class, which creates a bunch of
// threads. The first word of each thread's stack is set to the thread
// id.

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/syscall.h>
#include <unistd.h>

#if defined(__ARM_EABI__)
#define TID_PTR_REGISTER "r3"
#elif defined(__i386)
#define TID_PTR_REGISTER "ecx"
#elif defined(__x86_64)
#define TID_PTR_REGISTER "rcx"
#else
#error This test has not been ported to this platform.
#endif

void *thread_function(void *data) {
  volatile pid_t thread_id = syscall(SYS_gettid);
  register volatile pid_t *thread_id_ptr asm(TID_PTR_REGISTER) = &thread_id;
  while (true)
    asm volatile ("" : : "r" (thread_id_ptr));
  return NULL;
}

int main(int argc, char *argv[]) {
  int num_threads = atoi(argv[1]);
  if (num_threads < 1) {
    fprintf(stderr, "ERROR: number of threads is 0");
    return 1;
  }
  pthread_t threads[num_threads];
  pthread_attr_t thread_attributes;
  pthread_attr_init(&thread_attributes);
  pthread_attr_setdetachstate(&thread_attributes, PTHREAD_CREATE_DETACHED);
  for (int i = 1; i < num_threads; i++) {
    pthread_create(&threads[i], &thread_attributes, &thread_function, NULL);
  }
  thread_function(NULL);
  return 0;
}
<|endoftext|>


<commit_before>#include "throttle.hpp"
#include <stdexcept>
#include <sys/stat.h>
#include <unistd.h>

/*
 * Parsing function: for strings we can do better
 */
template<> void Conf::parse<std::string>(const std::string &str, std::string *ret)
{
	*ret = str;
}

/*
 * Configuration reader.
 * This function is guaranteed to read in all syntactically correct files, but might also accept others.
 */
Conf::Conf(const char *config_fn) {
	// open the file
	std::ifstream conf_file(config_fn);

	// read every line and put it in the map
	char line[LINE_LENGTH];
	std::string name;
	while (conf_file) {
		// parse: first comes the name of the command
		conf_file >> name;

		// if line starts with '#', ignore it
		if (name[0] == '#') {
			conf_file.ignore(LINE_LENGTH, '\n');
			continue;
		}

		conf_file.ignore(LINE_LENGTH, '=');
		conf_file.ignore(LINE_LENGTH, ' ');
		conf_file.getline(line, LINE_LENGTH);

#ifdef DEBUG
		std::cout << "[Conf] " << name << " = " << line << std::endl;
#endif

		// write into map
		attributes[name] = std::string(line);
	}
}

/*
 * Construct a command queue. We want to now the parent, where we can write changes to,
 * and which pipe to listen on.
 */
CommQueue::CommQueue(Throttle *parent, const char *pipe_fn) : Throt(parent), comm_pipe(pipe_fn)
{
	// create the pipe
	if (mkfifo(pipe_fn, 0666))
		throw std::runtime_error(std::string("Could not create pipe \"") + std::string(pipe_fn) + std::string("\"."));
	comm_pipe = pipe_fn;

	// start the thread
	if (pthread_create(&thread, NULL, watchPipe, this))
		throw std::runtime_error("Could not create thread.");
}

/*
 * Thread main function: `void *obj` should point to the generating object.
 * We watch the pipe for input.
 */
void *CommQueue::watchPipe(void *obj)
{
	CommQueue *that = (CommQueue *)obj;

	// open the pipe
	std::ifstream pipe(that->comm_pipe, std::ifstream::in);

	// watch for input
	char buf[LINE_LENGTH];
	do {
		pipe.getline(buf, LINE_LENGTH);
		that->processCommand(std::string(buf));
	} while (buf[0] != '*');

	that->Throt->term = true;

	return 0;
}

/*
 * Process a command coming through the pipe.
 */
void CommQueue::processCommand(const std::string comm)
{
#ifdef DEBUG
	std::cout << "[CommQueue] " << comm << std::endl;
#endif

	// parse command
	// change appropriate variables
}
<commit_msg>We shouldn't read the last line twice<commit_after>#include "throttle.hpp"
#include <stdexcept>
#include <sys/stat.h>
#include <unistd.h>

/*
 * Parsing function: for strings we can do better
 */
template<> void Conf::parse<std::string>(const std::string &str, std::string *ret)
{
	*ret = str;
}

/*
 * Configuration reader.
 * This function is guaranteed to read in all syntactically correct files, but might also accept others.
 */
Conf::Conf(const char *config_fn) {
	// open the file
	std::ifstream conf_file(config_fn);

	// read every line and put it in the map
	char line[LINE_LENGTH];
	std::string name;

	// parse: first comes the name of the command
	while (conf_file >> name) {
		// if line starts with '#', ignore it
		if (name[0] == '#') {
			conf_file.ignore(LINE_LENGTH, '\n');
			continue;
		}

		conf_file.ignore(LINE_LENGTH, '=');
		conf_file.ignore(LINE_LENGTH, ' ');
		conf_file.getline(line, LINE_LENGTH);

#ifdef DEBUG
		std::cout << "[Conf] " << name << " = " << line << std::endl;
#endif

		// write into map
		attributes[name] = std::string(line);
	}
}

/*
 * Construct a command queue. We want to now the parent, where we can write changes to,
 * and which pipe to listen on.
 */
CommQueue::CommQueue(Throttle *parent, const char *pipe_fn) : Throt(parent), comm_pipe(pipe_fn)
{
	// create the pipe
	if (mkfifo(pipe_fn, 0666))
		throw std::runtime_error(std::string("Could not create pipe \"") + std::string(pipe_fn) + std::string("\"."));
	comm_pipe = pipe_fn;

	// start the thread
	if (pthread_create(&thread, NULL, watchPipe, this))
		throw std::runtime_error("Could not create thread.");
}

/*
 * Thread main function: `void *obj` should point to the generating object.
 * We watch the pipe for input.
 */
void *CommQueue::watchPipe(void *obj)
{
	CommQueue *that = (CommQueue *)obj;

	// open the pipe
	std::ifstream pipe(that->comm_pipe, std::ifstream::in);

	// watch for input
	char buf[LINE_LENGTH];
	do {
		pipe.getline(buf, LINE_LENGTH);
		that->processCommand(std::string(buf));
	} while (buf[0] != '*');

	that->Throt->term = true;

	return 0;
}

/*
 * Process a command coming through the pipe.
 */
void CommQueue::processCommand(const std::string comm)
{
#ifdef DEBUG
	std::cout << "[CommQueue] " << comm << std::endl;
#endif

	// parse command
	// change appropriate variables
}
<|endoftext|>


<commit_before>/************************************************************************************
**
* @copyright (c) 2013-2100, ChengDu Duyer Technology Co., LTD. All Right Reserved.
*
*************************************************************************************/
/**
* @file		g_server_factory.cpp
* @version
* @brief
* @author	duye
* @date		2014-10-10
* @note
*
*  1. 2014-10-10 duye Created this file
*
*/
#pragma once
<commit_msg>Update g_server_factory.cpp<commit_after>/************************************************************************************
**
* @copyright (c) 2013-2100, ChengDu Duyer Technology Co., LTD. All Right Reserved.
*
*************************************************************************************/
/**
* @file		g_server_factory.cpp
* @version
* @brief
* @author	duye
* @date		2014-10-10
* @note
*
*  1. 2014-10-10 duye Created this file
*
*/
#include <g_server_factory.h>

<|endoftext|>


<commit_before>// STL
#include <sstream>
#include <fstream>
#include <string>
// CPPUNIT
#include <extracppunit/CppUnitCore.hpp>
// StdAir
#include <stdair/basic/BasLogParams.hpp>
#include <stdair/basic/BasDBParams.hpp>
// Dsim
#include <dsim/DSIM_Types.hpp>
#include <dsim/DSIM_Service.hpp>
// Dsim Test Suite
#include <test/dsim/SimulationTestSuite.hpp>

// //////////////////////////////////////////////////////////////////////
// Test is based on ...
// //////////////////////////////////////////////////////////////////////

// //////////////////////////////////////////////////////////////////////
void SimulationTestSuite::simpleSimulationHelper() {

  try {

    // Schedule input file name
    const std::string lScheduleInputFilename ("../samples/schedule01.csv");

    // O&D input file name
    const std::string lODInputFilename ("../samples/ond01.csv");

    // Demand input file name
    const stdair::Filename_T lDemandInputFilename ("../samples/demand01.csv");

    // Fare input file name
    const stdair::Filename_T lFareInputFilename ("../samples/fare01.csv");

    // Output log File
    const std::string lLogFilename ("SimulationTestSuite.log");

    // Set the log parameters
    std::ofstream logOutputFile;
    // Open and clean the log outputfile
    logOutputFile.open (lLogFilename.c_str());
    logOutputFile.clear();

    // Initialise the simulation context
    const stdair::BasLogParams lLogParams (stdair::LOG::DEBUG, logOutputFile);
    const stdair::BasDBParams lDBParams ("dsim", "dsim",
                                         "localhost", "3306",
                                         "sim_dsim");
    DSIM::DSIM_Service dsimService (lLogParams, lDBParams,
                                    lScheduleInputFilename, lODInputFilename,
                                    lDemandInputFilename, lFareInputFilename);

    // Perform a simulation
    dsimService.simulate();

  } catch (const DSIM::RootException& otexp) {
    std::cerr << "Standard exception: " << otexp.what() << std::endl;
    return;

  } catch (const std::exception& stde) {
    std::cerr << "Standard exception: " << stde.what() << std::endl;
    return;

  } catch (...) {
    return;
  }

}

// //////////////////////////////////////////////////////////////////////
void SimulationTestSuite::simpleSimulation () {
  // TODO: Check that the simulation goes as expected
  CPPUNIT_ASSERT_NO_THROW ( simpleSimulationHelper(););
}

// //////////////////////////////////////////////////////////////////////
// void SimulationTestSuite::errorCase () {
//  CPPUNIT_ASSERT (false);
// }

// //////////////////////////////////////////////////////////////////////
SimulationTestSuite::SimulationTestSuite () {
  _describeKey << "Running test on simulation";
}

// /////////////// M A I N /////////////////
CPPUNIT_MAIN()

<commit_msg>[Test] Fixed the DB issue (however, a local MySQL instance must run, and the sim_dsim database must have been created).<commit_after>// STL
#include <sstream>
#include <fstream>
#include <string>
// CPPUNIT
#include <extracppunit/CppUnitCore.hpp>
// StdAir
#include <stdair/basic/BasLogParams.hpp>
#include <stdair/basic/BasDBParams.hpp>
// Dsim
#include <dsim/DSIM_Types.hpp>
#include <dsim/DSIM_Service.hpp>
// Dsim Test Suite
#include <test/dsim/SimulationTestSuite.hpp>

// //////////////////////////////////////////////////////////////////////
// Test is based on ...
// //////////////////////////////////////////////////////////////////////

// //////////////////////////////////////////////////////////////////////
void SimulationTestSuite::simpleSimulationHelper() {

  try {

    // Schedule input file name
    const std::string lScheduleInputFilename ("../samples/schedule01.csv");

    // O&D input file name
    const std::string lODInputFilename ("../samples/ond01.csv");

    // Demand input file name
    const stdair::Filename_T lDemandInputFilename ("../samples/demand01.csv");

    // Fare input file name
    const stdair::Filename_T lFareInputFilename ("../samples/fare01.csv");

    // Output log File
    const std::string lLogFilename ("SimulationTestSuite.log");

    // Set the log parameters
    std::ofstream logOutputFile;
    // Open and clean the log outputfile
    logOutputFile.open (lLogFilename.c_str());
    logOutputFile.clear();

    // Initialise the simulation context
    const stdair::BasLogParams lLogParams (stdair::LOG::DEBUG, logOutputFile);
    const stdair::BasDBParams lDBParams ("dsim", "dsim", "localhost", "3306",
                                         "sim_dsim");
    DSIM::DSIM_Service dsimService (lLogParams, lDBParams,
                                    lScheduleInputFilename, lODInputFilename,
                                    lFareInputFilename, lDemandInputFilename);

    // Perform a simulation
    dsimService.simulate();

  } catch (const DSIM::RootException& otexp) {
    std::cerr << "DSim exception: " << otexp.what() << std::endl;

  } catch (const std::exception& stde) {
    std::cerr << "Standard exception: " << stde.what() << std::endl;
  }
}

// //////////////////////////////////////////////////////////////////////
void SimulationTestSuite::simpleSimulation () {
  // TODO: Check that the simulation goes as expected
  CPPUNIT_ASSERT_NO_THROW ( simpleSimulationHelper(););
}

// //////////////////////////////////////////////////////////////////////
// void SimulationTestSuite::errorCase () {
//  CPPUNIT_ASSERT (false);
// }

// //////////////////////////////////////////////////////////////////////
SimulationTestSuite::SimulationTestSuite () {
  _describeKey << "Running test on simulation";
}

// /////////////// M A I N /////////////////
CPPUNIT_MAIN()

<|endoftext|>


<commit_before>// Copyright 2011 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: morlovich@google.com (Maksim Orlovich)

#include "net/instaweb/util/public/shared_mem_test_base.h"

#include <cstddef>
#include "base/scoped_ptr.h"
#include "net/instaweb/util/public/abstract_mutex.h"
#include "net/instaweb/util/public/abstract_shared_mem.h"
#include "net/instaweb/util/public/mock_message_handler.h"
#include "net/instaweb/util/public/gtest.h"

namespace net_instaweb {

namespace {
  const char kTestSegment[] = "segment1";
  const char kOtherSegment[] = "segment2";
}  // namespace

SharedMemTestEnv::~SharedMemTestEnv() {
}

SharedMemTestEnv::Callback::~Callback() {
}

SharedMemTestBase::SharedMemTestBase(SharedMemTestEnv* test_env)
    : test_env_(test_env),
      shmem_runtime_(test_env->CreateSharedMemRuntime()) {
}

bool SharedMemTestBase::CreateChild(TestMethod method) {
  MethodCallback* callback = new MethodCallback(this, method);
  return test_env_->CreateChild(callback);
}

void SharedMemTestBase::TestReadWrite(bool reattach) {
  scoped_ptr<AbstractSharedMemSegment> seg(CreateDefault());
  ASSERT_TRUE(seg.get() != NULL);
  ASSERT_TRUE(CreateChild(&SharedMemTestBase::TestReadWriteChild));

  if (reattach) {
    seg.reset(AttachDefault());
  }

  // Wait for kid to write out stuff
  while (*seg->Base() != '1') {
    test_env_->ShortSleep();
  }

  // Write out stuff.
  *seg->Base() = '2';

  // Wait for termination.
  test_env_->WaitForChildren();
  seg.reset(NULL);
  DestroyDefault();
  EXPECT_EQ(0, handler_.SeriousMessages());
}

void SharedMemTestBase::TestReadWriteChild() {
  scoped_ptr<AbstractSharedMemSegment> seg(AttachDefault());

  // Write out '1', which the parent will wait for.
  *seg->Base() = '1';

  // Wait for '2' from parent
  while (*seg->Base() != '2') {
    test_env_->ShortSleep();
  }
}

void SharedMemTestBase::TestLarge() {
  scoped_ptr<AbstractSharedMemSegment> seg(
    shmem_runtime_->CreateSegment(kTestSegment, kLarge, &handler_));

  // Make sure everything is zeroed
  for (int c = 0; c < kLarge; ++c) {
    EXPECT_EQ(0, seg->Base()[c]);
  }
  seg.reset(NULL);

  ASSERT_TRUE(CreateChild(&SharedMemTestBase::TestLargeChild));
  test_env_->WaitForChildren();

  seg.reset(shmem_runtime_->AttachToSegment(kTestSegment, kLarge, &handler_));
  for (int i = 0; i < kLarge; i+=4) {
    EXPECT_EQ(i, *IntPtr(seg.get(), i));
  }
}

void SharedMemTestBase::TestLargeChild() {
  scoped_ptr<AbstractSharedMemSegment> seg(
    shmem_runtime_->AttachToSegment(kTestSegment, kLarge, &handler_));
  for (int i = 0; i < kLarge; i+=4) {
    *IntPtr(seg.get(), i) = i;
  }
}

// Make sure that 2 segments don't interfere.
void SharedMemTestBase::TestDistinct() {
  scoped_ptr<AbstractSharedMemSegment> seg(CreateDefault());
  scoped_ptr<AbstractSharedMemSegment> seg2(
      shmem_runtime_->CreateSegment(kOtherSegment, 4, &handler_));

  ASSERT_TRUE(CreateChild(&SharedMemTestBase::WriteSeg1Child));
  ASSERT_TRUE(CreateChild(&SharedMemTestBase::WriteSeg2Child));
  test_env_->WaitForChildren();

  EXPECT_EQ('1', *seg->Base());
  EXPECT_EQ('2', *seg2->Base());

  seg.reset(NULL);
  seg2.reset(NULL);
  DestroyDefault();
  shmem_runtime_->DestroySegment(kOtherSegment, &handler_);
  EXPECT_EQ(0, handler_.SeriousMessages());
}

// Make sure destruction destroys things properly...
void SharedMemTestBase::TestDestroy() {
  scoped_ptr<AbstractSharedMemSegment> seg(CreateDefault());

  ASSERT_TRUE(CreateChild(&SharedMemTestBase::WriteSeg1Child));
  test_env_->WaitForChildren();
  EXPECT_EQ('1', *seg->Base());

  seg.reset(NULL);
  DestroyDefault();

  // Attach should fail now
  seg.reset(AttachDefault());
  EXPECT_EQ(NULL, seg.get());

  // Newly created one should have zeroed memory
  seg.reset(CreateDefault());
  EXPECT_EQ('\0', *seg->Base());

  DestroyDefault();
}

// Make sure that re-creating a segment without a Destroy is safe and
// produces a distinct segment
void SharedMemTestBase::TestCreateTwice() {
  scoped_ptr<AbstractSharedMemSegment> seg(CreateDefault());
  ASSERT_TRUE(CreateChild(&SharedMemTestBase::WriteSeg1Child));
  test_env_->WaitForChildren();
  EXPECT_EQ('1', *seg->Base());

  seg.reset(CreateDefault());
  EXPECT_EQ('\0', *seg->Base());
}

// Make sure between two kids see the SHM as well.
void SharedMemTestBase::TestTwoKids() {
  scoped_ptr<AbstractSharedMemSegment> seg(CreateDefault());
  seg.reset(NULL);

  ASSERT_TRUE(CreateChild(&SharedMemTestBase::TwoKidsChild1));
  ASSERT_TRUE(CreateChild(&SharedMemTestBase::TwoKidsChild2));
  test_env_->WaitForChildren();
  seg.reset(AttachDefault());
  EXPECT_EQ('2', *seg->Base());

  DestroyDefault();
  EXPECT_EQ(0, handler_.SeriousMessages());
}

void SharedMemTestBase::TwoKidsChild1() {
  scoped_ptr<AbstractSharedMemSegment> seg(AttachDefault());
  // Write out '1', which the other kid will wait for.
  *seg->Base() = '1';
}

void SharedMemTestBase::TwoKidsChild2() {
  scoped_ptr<AbstractSharedMemSegment> seg(AttachDefault());
  // Wait for '1'
  while (*seg->Base() != '1') {
    test_env_->ShortSleep();
  }

  *seg->Base() = '2';
}

// Test for mutex operation. This attempts to detect lack of mutual exclusion
// by hammering on a shared location (protected by a lock) with non-atomic
// increments. This test does not guarantee that it will detect a failure
// (the schedule might just end up such that things work out), but it's
// been found to be effective in practice.
void SharedMemTestBase::TestMutex() {
  size_t mutex_size = shmem_runtime_->SharedMutexSize();
  scoped_ptr<AbstractSharedMemSegment> seg(
      shmem_runtime_->CreateSegment(kTestSegment, mutex_size + 4, &handler_));
  ASSERT_EQ(mutex_size, seg->SharedMutexSize());

  ASSERT_TRUE(seg->InitializeSharedMutex(0, &handler_));
  seg.reset(
      shmem_runtime_->AttachToSegment(kTestSegment, mutex_size + 4, &handler_));

  scoped_ptr<AbstractMutex> mutex(seg->AttachToSharedMutex(0));
  mutex->Lock();
  ASSERT_TRUE(CreateChild(&SharedMemTestBase::MutexChild));

  // Unblock the kid. Before that, it shouldn't have written
  EXPECT_EQ(0, *IntPtr(seg.get(), mutex_size));
  mutex->Unlock();

  mutex->Lock();
  EXPECT_TRUE(IncrementStorm(seg.get(), mutex_size));
  mutex->Unlock();

  test_env_->WaitForChildren();
  DestroyDefault();
}

void SharedMemTestBase::MutexChild() {
  size_t mutex_size = shmem_runtime_->SharedMutexSize();
  scoped_ptr<AbstractSharedMemSegment> seg(
      shmem_runtime_->AttachToSegment(kTestSegment, mutex_size + 4, &handler_));

  scoped_ptr<AbstractMutex> mutex(seg->AttachToSharedMutex(0));
  mutex->Lock();
  if (!IncrementStorm(seg.get(), mutex_size)) {
    mutex->Unlock();
    test_env_->ChildFailed();
    return;
  }
  mutex->Unlock();
}

// Returns if successful
bool SharedMemTestBase::IncrementStorm(AbstractSharedMemSegment* seg,
                                       size_t mutex_size) {
  // We are either the first or second to do the increments.
  int init = *IntPtr(seg, mutex_size);
  if ((init != 0) && (init != kNumIncrements)) {
    return false;
  }

  for (int i = 0; i < kNumIncrements; ++i) {
    ++*IntPtr(seg, mutex_size);
    if (*IntPtr(seg, mutex_size) != (i + init + 1)) {
      return false;
    }
    ++*IntPtr(seg, mutex_size);
    if (*IntPtr(seg, mutex_size) != (i + init + 2)) {
      return false;
    }
    --*IntPtr(seg, mutex_size);
    if (*IntPtr(seg, mutex_size) != (i + init + 1)) {
      return false;
    }
  }

  return true;
}

void SharedMemTestBase::WriteSeg1Child() {
  scoped_ptr<AbstractSharedMemSegment> seg(AttachDefault());
  *seg->Base() = '1';
}

void SharedMemTestBase::WriteSeg2Child() {
  scoped_ptr<AbstractSharedMemSegment> seg(
    shmem_runtime_->AttachToSegment(kOtherSegment, 4, &handler_));
  *seg->Base() = '2';
}

AbstractSharedMemSegment* SharedMemTestBase::CreateDefault() {
  return shmem_runtime_->CreateSegment(kTestSegment, 4, &handler_);
}

AbstractSharedMemSegment* SharedMemTestBase::AttachDefault() {
  return shmem_runtime_->AttachToSegment(kTestSegment, 4, &handler_);
}

void SharedMemTestBase::DestroyDefault() {
  shmem_runtime_->DestroySegment(kTestSegment, &handler_);
}

}  // namespace net_instaweb
<commit_msg>Make shared memory test helper methods more robust in the face of failure.<commit_after>// Copyright 2011 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: morlovich@google.com (Maksim Orlovich)

#include "net/instaweb/util/public/shared_mem_test_base.h"

#include <cstddef>
#include "base/scoped_ptr.h"
#include "net/instaweb/util/public/abstract_mutex.h"
#include "net/instaweb/util/public/abstract_shared_mem.h"
#include "net/instaweb/util/public/mock_message_handler.h"
#include "net/instaweb/util/public/gtest.h"

namespace net_instaweb {

namespace {
  const char kTestSegment[] = "segment1";
  const char kOtherSegment[] = "segment2";
}  // namespace

SharedMemTestEnv::~SharedMemTestEnv() {
}

SharedMemTestEnv::Callback::~Callback() {
}

SharedMemTestBase::SharedMemTestBase(SharedMemTestEnv* test_env)
    : test_env_(test_env),
      shmem_runtime_(test_env->CreateSharedMemRuntime()) {
}

bool SharedMemTestBase::CreateChild(TestMethod method) {
  MethodCallback* callback = new MethodCallback(this, method);
  return test_env_->CreateChild(callback);
}

void SharedMemTestBase::TestReadWrite(bool reattach) {
  scoped_ptr<AbstractSharedMemSegment> seg(CreateDefault());
  ASSERT_TRUE(seg.get() != NULL);
  ASSERT_TRUE(CreateChild(&SharedMemTestBase::TestReadWriteChild));

  if (reattach) {
    seg.reset(AttachDefault());
  }

  // Wait for kid to write out stuff
  while (*seg->Base() != '1') {
    test_env_->ShortSleep();
  }

  // Write out stuff.
  *seg->Base() = '2';

  // Wait for termination.
  test_env_->WaitForChildren();
  seg.reset(NULL);
  DestroyDefault();
  EXPECT_EQ(0, handler_.SeriousMessages());
}

void SharedMemTestBase::TestReadWriteChild() {
  scoped_ptr<AbstractSharedMemSegment> seg(AttachDefault());

  // Write out '1', which the parent will wait for.
  *seg->Base() = '1';

  // Wait for '2' from parent
  while (*seg->Base() != '2') {
    test_env_->ShortSleep();
  }
}

void SharedMemTestBase::TestLarge() {
  scoped_ptr<AbstractSharedMemSegment> seg(
    shmem_runtime_->CreateSegment(kTestSegment, kLarge, &handler_));
  ASSERT_TRUE(seg.get() != NULL);

  // Make sure everything is zeroed
  for (int c = 0; c < kLarge; ++c) {
    EXPECT_EQ(0, seg->Base()[c]);
  }
  seg.reset(NULL);

  ASSERT_TRUE(CreateChild(&SharedMemTestBase::TestLargeChild));
  test_env_->WaitForChildren();

  seg.reset(shmem_runtime_->AttachToSegment(kTestSegment, kLarge, &handler_));
  for (int i = 0; i < kLarge; i+=4) {
    EXPECT_EQ(i, *IntPtr(seg.get(), i));
  }
}

void SharedMemTestBase::TestLargeChild() {
  scoped_ptr<AbstractSharedMemSegment> seg(
    shmem_runtime_->AttachToSegment(kTestSegment, kLarge, &handler_));
  for (int i = 0; i < kLarge; i+=4) {
    *IntPtr(seg.get(), i) = i;
  }
}

// Make sure that 2 segments don't interfere.
void SharedMemTestBase::TestDistinct() {
  scoped_ptr<AbstractSharedMemSegment> seg(CreateDefault());
  ASSERT_TRUE(seg.get() != NULL);
  scoped_ptr<AbstractSharedMemSegment> seg2(
      shmem_runtime_->CreateSegment(kOtherSegment, 4, &handler_));
  ASSERT_TRUE(seg2.get() != NULL);

  ASSERT_TRUE(CreateChild(&SharedMemTestBase::WriteSeg1Child));
  ASSERT_TRUE(CreateChild(&SharedMemTestBase::WriteSeg2Child));
  test_env_->WaitForChildren();

  EXPECT_EQ('1', *seg->Base());
  EXPECT_EQ('2', *seg2->Base());

  seg.reset(NULL);
  seg2.reset(NULL);
  DestroyDefault();
  shmem_runtime_->DestroySegment(kOtherSegment, &handler_);
  EXPECT_EQ(0, handler_.SeriousMessages());
}

// Make sure destruction destroys things properly...
void SharedMemTestBase::TestDestroy() {
  scoped_ptr<AbstractSharedMemSegment> seg(CreateDefault());
  ASSERT_TRUE(seg.get() != NULL);

  ASSERT_TRUE(CreateChild(&SharedMemTestBase::WriteSeg1Child));
  test_env_->WaitForChildren();
  EXPECT_EQ('1', *seg->Base());

  seg.reset(NULL);
  DestroyDefault();

  // Attach should fail now
  seg.reset(AttachDefault());
  EXPECT_EQ(NULL, seg.get());

  // Newly created one should have zeroed memory
  seg.reset(CreateDefault());
  EXPECT_EQ('\0', *seg->Base());

  DestroyDefault();
}

// Make sure that re-creating a segment without a Destroy is safe and
// produces a distinct segment
void SharedMemTestBase::TestCreateTwice() {
  scoped_ptr<AbstractSharedMemSegment> seg(CreateDefault());
  ASSERT_TRUE(seg.get() != NULL);
  ASSERT_TRUE(CreateChild(&SharedMemTestBase::WriteSeg1Child));
  test_env_->WaitForChildren();
  EXPECT_EQ('1', *seg->Base());

  seg.reset(CreateDefault());
  EXPECT_EQ('\0', *seg->Base());
}

// Make sure between two kids see the SHM as well.
void SharedMemTestBase::TestTwoKids() {
  scoped_ptr<AbstractSharedMemSegment> seg(CreateDefault());
  ASSERT_TRUE(seg.get() != NULL);
  seg.reset(NULL);

  ASSERT_TRUE(CreateChild(&SharedMemTestBase::TwoKidsChild1));
  ASSERT_TRUE(CreateChild(&SharedMemTestBase::TwoKidsChild2));
  test_env_->WaitForChildren();
  seg.reset(AttachDefault());
  EXPECT_EQ('2', *seg->Base());

  DestroyDefault();
  EXPECT_EQ(0, handler_.SeriousMessages());
}

void SharedMemTestBase::TwoKidsChild1() {
  scoped_ptr<AbstractSharedMemSegment> seg(AttachDefault());
  ASSERT_TRUE(seg.get() != NULL);
  // Write out '1', which the other kid will wait for.
  *seg->Base() = '1';
}

void SharedMemTestBase::TwoKidsChild2() {
  scoped_ptr<AbstractSharedMemSegment> seg(AttachDefault());
  ASSERT_TRUE(seg.get() != NULL);
  // Wait for '1'
  while (*seg->Base() != '1') {
    test_env_->ShortSleep();
  }

  *seg->Base() = '2';
}

// Test for mutex operation. This attempts to detect lack of mutual exclusion
// by hammering on a shared location (protected by a lock) with non-atomic
// increments. This test does not guarantee that it will detect a failure
// (the schedule might just end up such that things work out), but it's
// been found to be effective in practice.
void SharedMemTestBase::TestMutex() {
  size_t mutex_size = shmem_runtime_->SharedMutexSize();
  scoped_ptr<AbstractSharedMemSegment> seg(
      shmem_runtime_->CreateSegment(kTestSegment, mutex_size + 4, &handler_));
  ASSERT_TRUE(seg.get() != NULL);
  ASSERT_EQ(mutex_size, seg->SharedMutexSize());

  ASSERT_TRUE(seg->InitializeSharedMutex(0, &handler_));
  seg.reset(
      shmem_runtime_->AttachToSegment(kTestSegment, mutex_size + 4, &handler_));

  scoped_ptr<AbstractMutex> mutex(seg->AttachToSharedMutex(0));
  mutex->Lock();
  ASSERT_TRUE(CreateChild(&SharedMemTestBase::MutexChild));

  // Unblock the kid. Before that, it shouldn't have written
  EXPECT_EQ(0, *IntPtr(seg.get(), mutex_size));
  mutex->Unlock();

  mutex->Lock();
  EXPECT_TRUE(IncrementStorm(seg.get(), mutex_size));
  mutex->Unlock();

  test_env_->WaitForChildren();
  DestroyDefault();
}

void SharedMemTestBase::MutexChild() {
  size_t mutex_size = shmem_runtime_->SharedMutexSize();
  scoped_ptr<AbstractSharedMemSegment> seg(
      shmem_runtime_->AttachToSegment(kTestSegment, mutex_size + 4, &handler_));
  ASSERT_TRUE(seg.get() != NULL);

  scoped_ptr<AbstractMutex> mutex(seg->AttachToSharedMutex(0));
  mutex->Lock();
  if (!IncrementStorm(seg.get(), mutex_size)) {
    mutex->Unlock();
    test_env_->ChildFailed();
    return;
  }
  mutex->Unlock();
}

// Returns if successful
bool SharedMemTestBase::IncrementStorm(AbstractSharedMemSegment* seg,
                                       size_t mutex_size) {
  // We are either the first or second to do the increments.
  int init = *IntPtr(seg, mutex_size);
  if ((init != 0) && (init != kNumIncrements)) {
    return false;
  }

  for (int i = 0; i < kNumIncrements; ++i) {
    ++*IntPtr(seg, mutex_size);
    if (*IntPtr(seg, mutex_size) != (i + init + 1)) {
      return false;
    }
    ++*IntPtr(seg, mutex_size);
    if (*IntPtr(seg, mutex_size) != (i + init + 2)) {
      return false;
    }
    --*IntPtr(seg, mutex_size);
    if (*IntPtr(seg, mutex_size) != (i + init + 1)) {
      return false;
    }
  }

  return true;
}

void SharedMemTestBase::WriteSeg1Child() {
  scoped_ptr<AbstractSharedMemSegment> seg(AttachDefault());
  ASSERT_TRUE(seg.get() != NULL);
  *seg->Base() = '1';
}

void SharedMemTestBase::WriteSeg2Child() {
  scoped_ptr<AbstractSharedMemSegment> seg(
    shmem_runtime_->AttachToSegment(kOtherSegment, 4, &handler_));
  ASSERT_TRUE(seg.get() != NULL);
  *seg->Base() = '2';
}

AbstractSharedMemSegment* SharedMemTestBase::CreateDefault() {
  return shmem_runtime_->CreateSegment(kTestSegment, 4, &handler_);
}

AbstractSharedMemSegment* SharedMemTestBase::AttachDefault() {
  return shmem_runtime_->AttachToSegment(kTestSegment, 4, &handler_);
}

void SharedMemTestBase::DestroyDefault() {
  shmem_runtime_->DestroySegment(kTestSegment, &handler_);
}

}  // namespace net_instaweb
<|endoftext|>


<commit_before><commit_msg>Vulkan: fix dummy type for disabled attribs.<commit_after><|endoftext|>