<commit_before>#pragma once
//=====================================================================//
/*!	@file
	@brief	RX700 グループ・SSIE 定義
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2019 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include "common/io_utils.hpp"
#include "common/device.hpp"

namespace device {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief	シリアルサウンドインタフェース（SSIE）
		@param[in]	base	ベースアドレス
		@param[in]	per		ペリフェラル型
		@param[in]	txi		送信データエンプティ割り込みベクタ
		@param[in]	rxi		受信データフル割り込みベクタ
		@param[in]	ssie	ステータス割り込みベクタ
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <uint32_t base, peripheral per,
		ICU::VECTOR txi, ICU::VECTOR rxi, ICU::VECTOR_BL1 ssie>
	struct ssie_t {

		static const auto PERIPHERAL = per;	///< ペリフェラル型
		static const auto TX_VEC = txi;		///< 送信データエンプティ割り込みベクタ
		static const auto RX_VEC = rxi;		///< 受信データフル割り込みベクタ
		static const auto SS_VEC = ssie;	///< ステータス割り込みベクタ

		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief  制御レジスタ（ SSICR ）
			@param[in]	ofs	オフセット
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		template <uint32_t ofs>
		struct ssicr_t : public rw32_t<ofs> {
			typedef rw32_t<ofs> io_;
			using io_::operator =;
			using io_::operator ();
			using io_::operator |=;
			using io_::operator &=;

			bit_rw_t< io_, bitpos::B0>     REN;
			bit_rw_t< io_, bitpos::B1>     TEN;

			bit_rw_t< io_, bitpos::B3>     MUEN;
			bits_rw_t<io_, bitpos::B4, 4>  CKDV;
			bit_rw_t< io_, bitpos::B8>     DEL;
			bit_rw_t< io_, bitpos::B9>     PDTA;
			bit_rw_t< io_, bitpos::B10>    SDTA;
			bit_rw_t< io_, bitpos::B11>    SPDP;
			bit_rw_t< io_, bitpos::B12>    LRCKP;
			bit_rw_t< io_, bitpos::B13>    BCKP;
			bit_rw_t< io_, bitpos::B14>    MST;

			bits_rw_t<io_, bitpos::B16, 3> SWL;
			bits_rw_t<io_, bitpos::B19, 3> DWL;
			bits_rw_t<io_, bitpos::B22, 2> FRM;

			bit_rw_t< io_, bitpos::B25>    IIEN;
			bit_rw_t< io_, bitpos::B26>    ROIEN;
			bit_rw_t< io_, bitpos::B27>    RUIEN;
			bit_rw_t< io_, bitpos::B28>    TOIEN;
			bit_rw_t< io_, bitpos::B29>    TUIEN;
		};
		typedef ssicr_t<base + 0x00> SSICR_;
		static SSICR_ SSICR;

		//-----------------------------------------------------------------//
		/*!
			@brief  ステータスレジスタ（ SSISR ）
			@param[in]	ofs	オフセット
		*/
		//-----------------------------------------------------------------//
		template <uint32_t ofs>
		struct ssisr_t : public rw32_t<ofs> {
			typedef rw32_t<ofs> rw_;
			typedef ro32_t<ofs> ro_;
			using rw_::operator =;
			using rw_::operator ();
			using rw_::operator |=;
			using rw_::operator &=;

			bit_ro_t< ro_, bitpos::B25>    IIRQ;
			bit_rw_t< rw_, bitpos::B26>    ROIRQ;
			bit_rw_t< rw_, bitpos::B27>    RUIRQ;
			bit_rw_t< rw_, bitpos::B28>    TOIRQ;
			bit_rw_t< rw_, bitpos::B29>    TUIRQ;
		};
		typedef ssisr_t<base + 0x04> SSISR_;
		static SSISR_ SSISR;

		//-----------------------------------------------------------------//
		/*!
			@brief  FIFO 制御レジスタ（ SSIFCR ）
			@param[in]	ofs	オフセット
		*/
		//-----------------------------------------------------------------//
		template <uint32_t ofs>
		struct ssifcr_t : public rw32_t<ofs> {
			typedef rw32_t<ofs> io_;
			using io_::operator =;
			using io_::operator ();
			using io_::operator |=;
			using io_::operator &=;

			bit_rw_t< io_, bitpos::B0>     RFRST;
			bit_rw_t< io_, bitpos::B1>     TFRST;
			bit_rw_t< io_, bitpos::B2>     RIE;
			bit_rw_t< io_, bitpos::B3>     TIE;

			bit_rw_t< io_, bitpos::B11>    BSW;

			bit_rw_t< io_, bitpos::B16>    SSIRST;

			bit_rw_t< io_, bitpos::B31>    AUCKE;
		};
		typedef ssifcr_t<base + 0x10> SSIFCR_;
		static SSIFCR_ SSIFCR;

		//-----------------------------------------------------------------//
		/*!
			@brief  FIFO ステータスレジスタ（ SSIFSR ）
			@param[in]	ofs	オフセット
		*/
		//-----------------------------------------------------------------//
		template <uint32_t ofs>
		struct ssifsr_t : public rw32_t<ofs> {
			typedef rw32_t<ofs> io_;
			using io_::operator =;
			using io_::operator ();
			using io_::operator |=;
			using io_::operator &=;

			bit_rw_t< io_, bitpos::B0>     RDF;

			bits_rw_t<io_, bitpos::B8, 6>  RDC;

			bit_rw_t< io_, bitpos::B16>    TDE;

			bits_rw_t<io_, bitpos::B24, 6> TDC;
		};
		typedef ssifsr_t<base + 0x14> SSIFSR_;
		static SSIFSR_ SSIFSR;

		//-----------------------------------------------------------------//
		/*!
			@brief  送信 FIFO データレジスタ（ SSIFTDR ）
		*/
		//-----------------------------------------------------------------//
		typedef wo32_t<base + 0x18> SSIFTDR32_;
		static SSIFTDR32_ SSIFTDR32;
		typedef wo16_t<base + 0x18> SSIFTDR16_;
		static SSIFTDR16_ SSIFTDR16;
		typedef wo8_t<base + 0x18> SSIFTDR8_;
		static SSIFTDR8_ SSIFTDR8;

		//-----------------------------------------------------------------//
		/*!
			@brief  受信 FIFO データレジスタ（ SSIFRDR ）
		*/
		//-----------------------------------------------------------------//
		typedef ro32_t<base + 0x1C> SSIFRDR32_;
		static SSIFRDR32_ SSIFRDR32;
		typedef ro16_t<base + 0x1C> SSIFRDR16_;
		static SSIFRDR16_ SSIFRDR16;
		typedef ro8_t<base + 0x1C> SSIFRDR8_;
		static SSIFRDR8_ SSIFRDR8;

		//-----------------------------------------------------------------//
		/*!
			@brief  オーディオフォーマットレジスタ (SSIOFR)
			@param[in]	ofs	オフセット
		*/
		//-----------------------------------------------------------------//
		template <uint32_t ofs>
		struct ssiofr_t : public rw32_t<ofs> {
			typedef rw32_t<ofs> io_;
			using io_::operator =;
			using io_::operator ();
			using io_::operator |=;
			using io_::operator &=;

			bits_rw_t<io_, bitpos::B0, 2>   OMOD;

			bit_rw_t <io_, bitpos::B8>      LRCONT;
			bit_rw_t <io_, bitpos::B9>      BCKASTP;
		};
		typedef ssiofr_t<base + 0x20> SSIOFR_;
		static SSIOFR_ SSIOFR;

		//-----------------------------------------------------------------//
		/*!
			@brief  FIFO ステータスコントロールレジスタ (SSISCR)
			@param[in]	ofs	オフセット
		*/
		//-----------------------------------------------------------------//
		template <uint32_t ofs>
		struct ssiscr_t : public rw32_t<ofs> {
			typedef rw32_t<ofs> io_;
			using io_::operator =;
			using io_::operator ();
			using io_::operator |=;
			using io_::operator &=;

			bits_rw_t<io_, bitpos::B0, 5>   RDFS;

			bits_rw_t<io_, bitpos::B8, 5>   TDES;
		};
		typedef ssiscr_t<base + 0x24> SSISCR_;
		static SSISCR_ SSISCR;
	};

	template <uint32_t base, peripheral per,
		ICU::VECTOR txi, ICU::VECTOR rxi, ICU::VECTOR_BL1 ssie>
		typename ssie_t<base, per, txi, rxi, ssie>::SSICR_ ssie_t<base, per, txi, rxi, ssie>::SSICR;
	template <uint32_t base, peripheral per,
		ICU::VECTOR txi, ICU::VECTOR rxi, ICU::VECTOR_BL1 ssie>
		typename ssie_t<base, per, txi, rxi, ssie>::SSISR_ ssie_t<base, per, txi, rxi, ssie>::SSISR;
	template <uint32_t base, peripheral per,
		ICU::VECTOR txi, ICU::VECTOR rxi, ICU::VECTOR_BL1 ssie>
		typename ssie_t<base, per, txi, rxi, ssie>::SSIFCR_ ssie_t<base, per, txi, rxi, ssie>::SSIFCR;
	template <uint32_t base, peripheral per,
		ICU::VECTOR txi, ICU::VECTOR rxi, ICU::VECTOR_BL1 ssie>
		typename ssie_t<base, per, txi, rxi, ssie>::SSIFSR_ ssie_t<base, per, txi, rxi, ssie>::SSIFSR;
	template <uint32_t base, peripheral per,
		ICU::VECTOR txi, ICU::VECTOR rxi, ICU::VECTOR_BL1 ssie>
		typename ssie_t<base, per, txi, rxi, ssie>::SSIFTDR32_ ssie_t<base, per, txi, rxi, ssie>::SSIFTDR32;
	template <uint32_t base, peripheral per,
		ICU::VECTOR txi, ICU::VECTOR rxi, ICU::VECTOR_BL1 ssie>
		typename ssie_t<base, per, txi, rxi, ssie>::SSIFTDR16_ ssie_t<base, per, txi, rxi, ssie>::SSIFTDR16;
	template <uint32_t base, peripheral per,
		ICU::VECTOR txi, ICU::VECTOR rxi, ICU::VECTOR_BL1 ssie>
		typename ssie_t<base, per, txi, rxi, ssie>::SSIFTDR8_ ssie_t<base, per, txi, rxi, ssie>::SSIFTDR8;
	template <uint32_t base, peripheral per,
		ICU::VECTOR txi, ICU::VECTOR rxi, ICU::VECTOR_BL1 ssie>
		typename ssie_t<base, per, txi, rxi, ssie>::SSIFRDR32_ ssie_t<base, per, txi, rxi, ssie>::SSIFRDR32;
	template <uint32_t base, peripheral per,
		ICU::VECTOR txi, ICU::VECTOR rxi, ICU::VECTOR_BL1 ssie>
		typename ssie_t<base, per, txi, rxi, ssie>::SSIFRDR16_ ssie_t<base, per, txi, rxi, ssie>::SSIFRDR16;
	template <uint32_t base, peripheral per,
		ICU::VECTOR txi, ICU::VECTOR rxi, ICU::VECTOR_BL1 ssie>
		typename ssie_t<base, per, txi, rxi, ssie>::SSIFRDR8_ ssie_t<base, per, txi, rxi, ssie>::SSIFRDR8;
	template <uint32_t base, peripheral per,
		ICU::VECTOR txi, ICU::VECTOR rxi, ICU::VECTOR_BL1 ssie>
		typename ssie_t<base, per, txi, rxi, ssie>::SSIOFR_ ssie_t<base, per, txi, rxi, ssie>::SSIOFR;
	template <uint32_t base, peripheral per,
		ICU::VECTOR txi, ICU::VECTOR rxi, ICU::VECTOR_BL1 ssie>
		typename ssie_t<base, per, txi, rxi, ssie>::SSISCR_ ssie_t<base, per, txi, rxi, ssie>::SSISCR;

#if defined(SIG_RX72M) || defined(SIG_RX72N)
	typedef ssie_t<0x0008A500, peripheral::SSIE0,
		ICU::VECTOR::SSITXI0, ICU::VECTOR::SSIRXI0, ICU::VECTOR_BL1::SSIF0> SSIE0;
	typedef ssie_t<0x0008A540, peripheral::SSIE1,
		ICU::VECTOR::SSIRTI1, ICU::VECTOR::SSIRTI1, ICU::VECTOR_BL1::SSIF1> SSIE1;
#endif
}
<commit_msg>Update: cleanup<commit_after>#pragma once
//=====================================================================//
/*!	@file
	@brief	RX700 グループ・SSIE 定義
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2019, 2020 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include "common/io_utils.hpp"
#include "common/device.hpp"

namespace device {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief	シリアルサウンドインタフェース（SSIE）
		@param[in]	base	ベースアドレス
		@param[in]	per		ペリフェラル型
		@param[in]	txi		送信データエンプティ割り込みベクタ
		@param[in]	rxi		受信データフル割り込みベクタ
		@param[in]	ssie	ステータス割り込みベクタ
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <uint32_t base, peripheral per,
		ICU::VECTOR txi, ICU::VECTOR rxi, ICU::VECTOR_BL1 ssie>
	struct ssie_t {

		static const auto PERIPHERAL = per;	///< ペリフェラル型
		static const auto TX_VEC = txi;		///< 送信データエンプティ割り込みベクタ
		static const auto RX_VEC = rxi;		///< 受信データフル割り込みベクタ
		static const auto SS_VEC = ssie;	///< ステータス割り込みベクタ

		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief  制御レジスタ（ SSICR ）
			@param[in]	ofs	オフセット
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		template <uint32_t ofs>
		struct ssicr_t : public rw32_t<ofs> {
			typedef rw32_t<ofs> io_;
			using io_::operator =;
			using io_::operator ();
			using io_::operator |=;
			using io_::operator &=;

			bit_rw_t< io_, bitpos::B0>     REN;
			bit_rw_t< io_, bitpos::B1>     TEN;

			bit_rw_t< io_, bitpos::B3>     MUEN;
			bits_rw_t<io_, bitpos::B4, 4>  CKDV;
			bit_rw_t< io_, bitpos::B8>     DEL;
			bit_rw_t< io_, bitpos::B9>     PDTA;
			bit_rw_t< io_, bitpos::B10>    SDTA;
			bit_rw_t< io_, bitpos::B11>    SPDP;
			bit_rw_t< io_, bitpos::B12>    LRCKP;
			bit_rw_t< io_, bitpos::B13>    BCKP;
			bit_rw_t< io_, bitpos::B14>    MST;

			bits_rw_t<io_, bitpos::B16, 3> SWL;
			bits_rw_t<io_, bitpos::B19, 3> DWL;
			bits_rw_t<io_, bitpos::B22, 2> FRM;

			bit_rw_t< io_, bitpos::B25>    IIEN;
			bit_rw_t< io_, bitpos::B26>    ROIEN;
			bit_rw_t< io_, bitpos::B27>    RUIEN;
			bit_rw_t< io_, bitpos::B28>    TOIEN;
			bit_rw_t< io_, bitpos::B29>    TUIEN;
		};
		typedef ssicr_t<base + 0x00> SSICR_;
		static SSICR_ SSICR;

		//-----------------------------------------------------------------//
		/*!
			@brief  ステータスレジスタ（ SSISR ）
			@param[in]	ofs	オフセット
		*/
		//-----------------------------------------------------------------//
		template <uint32_t ofs>
		struct ssisr_t : public rw32_t<ofs> {
			typedef rw32_t<ofs> rw_;
			typedef ro32_t<ofs> ro_;
			using rw_::operator =;
			using rw_::operator ();
			using rw_::operator |=;
			using rw_::operator &=;

			bit_ro_t< ro_, bitpos::B25>    IIRQ;
			bit_rw_t< rw_, bitpos::B26>    ROIRQ;
			bit_rw_t< rw_, bitpos::B27>    RUIRQ;
			bit_rw_t< rw_, bitpos::B28>    TOIRQ;
			bit_rw_t< rw_, bitpos::B29>    TUIRQ;
		};
		typedef ssisr_t<base + 0x04> SSISR_;
		static SSISR_ SSISR;

		//-----------------------------------------------------------------//
		/*!
			@brief  FIFO 制御レジスタ（ SSIFCR ）
			@param[in]	ofs	オフセット
		*/
		//-----------------------------------------------------------------//
		template <uint32_t ofs>
		struct ssifcr_t : public rw32_t<ofs> {
			typedef rw32_t<ofs> io_;
			using io_::operator =;
			using io_::operator ();
			using io_::operator |=;
			using io_::operator &=;

			bit_rw_t< io_, bitpos::B0>     RFRST;
			bit_rw_t< io_, bitpos::B1>     TFRST;
			bit_rw_t< io_, bitpos::B2>     RIE;
			bit_rw_t< io_, bitpos::B3>     TIE;

			bit_rw_t< io_, bitpos::B11>    BSW;

			bit_rw_t< io_, bitpos::B16>    SSIRST;

			bit_rw_t< io_, bitpos::B31>    AUCKE;
		};
		typedef ssifcr_t<base + 0x10> SSIFCR_;
		static SSIFCR_ SSIFCR;

		//-----------------------------------------------------------------//
		/*!
			@brief  FIFO ステータスレジスタ（ SSIFSR ）
			@param[in]	ofs	オフセット
		*/
		//-----------------------------------------------------------------//
		template <uint32_t ofs>
		struct ssifsr_t : public rw32_t<ofs> {
			typedef rw32_t<ofs> io_;
			using io_::operator =;
			using io_::operator ();
			using io_::operator |=;
			using io_::operator &=;

			bit_rw_t< io_, bitpos::B0>     RDF;

			bits_rw_t<io_, bitpos::B8, 6>  RDC;

			bit_rw_t< io_, bitpos::B16>    TDE;

			bits_rw_t<io_, bitpos::B24, 6> TDC;
		};
		typedef ssifsr_t<base + 0x14> SSIFSR_;
		static SSIFSR_ SSIFSR;

		//-----------------------------------------------------------------//
		/*!
			@brief  送信 FIFO データレジスタ（ SSIFTDR ）
		*/
		//-----------------------------------------------------------------//
		typedef wo32_t<base + 0x18> SSIFTDR32_;
		static SSIFTDR32_ SSIFTDR32;
		typedef wo16_t<base + 0x18> SSIFTDR16_;
		static SSIFTDR16_ SSIFTDR16;
		typedef wo8_t<base + 0x18> SSIFTDR8_;
		static SSIFTDR8_ SSIFTDR8;

		//-----------------------------------------------------------------//
		/*!
			@brief  受信 FIFO データレジスタ（ SSIFRDR ）
		*/
		//-----------------------------------------------------------------//
		typedef ro32_t<base + 0x1C> SSIFRDR32_;
		static SSIFRDR32_ SSIFRDR32;
		typedef ro16_t<base + 0x1C> SSIFRDR16_;
		static SSIFRDR16_ SSIFRDR16;
		typedef ro8_t<base + 0x1C> SSIFRDR8_;
		static SSIFRDR8_ SSIFRDR8;

		//-----------------------------------------------------------------//
		/*!
			@brief  オーディオフォーマットレジスタ (SSIOFR)
			@param[in]	ofs	オフセット
		*/
		//-----------------------------------------------------------------//
		template <uint32_t ofs>
		struct ssiofr_t : public rw32_t<ofs> {
			typedef rw32_t<ofs> io_;
			using io_::operator =;
			using io_::operator ();
			using io_::operator |=;
			using io_::operator &=;

			bits_rw_t<io_, bitpos::B0, 2>   OMOD;

			bit_rw_t <io_, bitpos::B8>      LRCONT;
			bit_rw_t <io_, bitpos::B9>      BCKASTP;
		};
		typedef ssiofr_t<base + 0x20> SSIOFR_;
		static SSIOFR_ SSIOFR;

		//-----------------------------------------------------------------//
		/*!
			@brief  FIFO ステータスコントロールレジスタ (SSISCR)
			@param[in]	ofs	オフセット
		*/
		//-----------------------------------------------------------------//
		template <uint32_t ofs>
		struct ssiscr_t : public rw32_t<ofs> {
			typedef rw32_t<ofs> io_;
			using io_::operator =;
			using io_::operator ();
			using io_::operator |=;
			using io_::operator &=;

			bits_rw_t<io_, bitpos::B0, 5>   RDFS;

			bits_rw_t<io_, bitpos::B8, 5>   TDES;
		};
		typedef ssiscr_t<base + 0x24> SSISCR_;
		static SSISCR_ SSISCR;
	};

	template <uint32_t base, peripheral per,
		ICU::VECTOR txi, ICU::VECTOR rxi, ICU::VECTOR_BL1 ssie>
		typename ssie_t<base, per, txi, rxi, ssie>::SSICR_ ssie_t<base, per, txi, rxi, ssie>::SSICR;
	template <uint32_t base, peripheral per,
		ICU::VECTOR txi, ICU::VECTOR rxi, ICU::VECTOR_BL1 ssie>
		typename ssie_t<base, per, txi, rxi, ssie>::SSISR_ ssie_t<base, per, txi, rxi, ssie>::SSISR;
	template <uint32_t base, peripheral per,
		ICU::VECTOR txi, ICU::VECTOR rxi, ICU::VECTOR_BL1 ssie>
		typename ssie_t<base, per, txi, rxi, ssie>::SSIFCR_ ssie_t<base, per, txi, rxi, ssie>::SSIFCR;
	template <uint32_t base, peripheral per,
		ICU::VECTOR txi, ICU::VECTOR rxi, ICU::VECTOR_BL1 ssie>
		typename ssie_t<base, per, txi, rxi, ssie>::SSIFSR_ ssie_t<base, per, txi, rxi, ssie>::SSIFSR;
	template <uint32_t base, peripheral per,
		ICU::VECTOR txi, ICU::VECTOR rxi, ICU::VECTOR_BL1 ssie>
		typename ssie_t<base, per, txi, rxi, ssie>::SSIFTDR32_ ssie_t<base, per, txi, rxi, ssie>::SSIFTDR32;
	template <uint32_t base, peripheral per,
		ICU::VECTOR txi, ICU::VECTOR rxi, ICU::VECTOR_BL1 ssie>
		typename ssie_t<base, per, txi, rxi, ssie>::SSIFTDR16_ ssie_t<base, per, txi, rxi, ssie>::SSIFTDR16;
	template <uint32_t base, peripheral per,
		ICU::VECTOR txi, ICU::VECTOR rxi, ICU::VECTOR_BL1 ssie>
		typename ssie_t<base, per, txi, rxi, ssie>::SSIFTDR8_ ssie_t<base, per, txi, rxi, ssie>::SSIFTDR8;
	template <uint32_t base, peripheral per,
		ICU::VECTOR txi, ICU::VECTOR rxi, ICU::VECTOR_BL1 ssie>
		typename ssie_t<base, per, txi, rxi, ssie>::SSIFRDR32_ ssie_t<base, per, txi, rxi, ssie>::SSIFRDR32;
	template <uint32_t base, peripheral per,
		ICU::VECTOR txi, ICU::VECTOR rxi, ICU::VECTOR_BL1 ssie>
		typename ssie_t<base, per, txi, rxi, ssie>::SSIFRDR16_ ssie_t<base, per, txi, rxi, ssie>::SSIFRDR16;
	template <uint32_t base, peripheral per,
		ICU::VECTOR txi, ICU::VECTOR rxi, ICU::VECTOR_BL1 ssie>
		typename ssie_t<base, per, txi, rxi, ssie>::SSIFRDR8_ ssie_t<base, per, txi, rxi, ssie>::SSIFRDR8;
	template <uint32_t base, peripheral per,
		ICU::VECTOR txi, ICU::VECTOR rxi, ICU::VECTOR_BL1 ssie>
		typename ssie_t<base, per, txi, rxi, ssie>::SSIOFR_ ssie_t<base, per, txi, rxi, ssie>::SSIOFR;
	template <uint32_t base, peripheral per,
		ICU::VECTOR txi, ICU::VECTOR rxi, ICU::VECTOR_BL1 ssie>
		typename ssie_t<base, per, txi, rxi, ssie>::SSISCR_ ssie_t<base, per, txi, rxi, ssie>::SSISCR;

#if defined(SIG_RX72M) || defined(SIG_RX72N)
	typedef ssie_t<0x0008A500, peripheral::SSIE0,
		ICU::VECTOR::SSITXI0, ICU::VECTOR::SSIRXI0, ICU::VECTOR_BL1::SSIF0> SSIE0;
	typedef ssie_t<0x0008A540, peripheral::SSIE1,
		ICU::VECTOR::SSIRTI1, ICU::VECTOR::SSIRTI1, ICU::VECTOR_BL1::SSIF1> SSIE1;
#endif
}
<|endoftext|>


<commit_before>/* listener.cc
   Mathieu Stefani, 12 August 2015

*/

#include <pistache/common.h>
#include <pistache/errors.h>
#include <pistache/listener.h>
#include <pistache/os.h>
#include <pistache/peer.h>
#include <pistache/transport.h>

#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <sys/timerfd.h>
#include <sys/types.h>

#include <chrono>
#include <memory>
#include <vector>

#include <cerrno>
#include <signal.h>

#ifdef PISTACHE_USE_SSL

#include <openssl/err.h>
#include <openssl/ssl.h>

#endif /* PISTACHE_USE_SSL */

namespace Pistache {
namespace Tcp {

void setSocketOptions(Fd fd, Flags<Options> options) {
  if (options.hasFlag(Options::ReuseAddr)) {
    int one = 1;
    TRY(::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)));
  }

  if (options.hasFlag(Options::ReusePort)) {
    int one = 1;
    TRY(::setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)));
  }

  if (options.hasFlag(Options::Linger)) {
    struct linger opt;
    opt.l_onoff = 1;
    opt.l_linger = 1;
    TRY(::setsockopt(fd, SOL_SOCKET, SO_LINGER, &opt, sizeof(opt)));
  }

  if (options.hasFlag(Options::FastOpen)) {
    int hint = 5;
    TRY(::setsockopt(fd, SOL_TCP, TCP_FASTOPEN, &hint, sizeof(hint)));
  }
  if (options.hasFlag(Options::NoDelay)) {
    int one = 1;
    TRY(::setsockopt(fd, SOL_TCP, TCP_NODELAY, &one, sizeof(one)));
  }
}

Listener::Listener()
    : addr_(), listen_fd(-1), backlog_(Const::MaxBacklog), shutdownFd(),
      poller(), options_(), workers_(Const::DefaultWorkers), workersName_(),
      reactor_(), transportKey(), useSSL_(false), ssl_ctx_(nullptr) {}

Listener::Listener(const Address &address)
    : addr_(address), listen_fd(-1), backlog_(Const::MaxBacklog), shutdownFd(),
      poller(), options_(), workers_(Const::DefaultWorkers), workersName_(),
      reactor_(), transportKey(), useSSL_(false), ssl_ctx_(nullptr) {}

Listener::~Listener() {
  if (isBound())
    shutdown();
  if (acceptThread.joinable())
    acceptThread.join();

  if (listen_fd >= 0) {
    close(listen_fd);
    listen_fd = -1;
  }
#ifdef PISTACHE_USE_SSL
  if (this->useSSL_) {
    SSL_CTX_free((SSL_CTX *)this->ssl_ctx_);
    EVP_cleanup();
  }
#endif /* PISTACHE_USE_SSL */
}

void Listener::init(size_t workers, Flags<Options> options,
                    const std::string &workersName, int backlog) {
  if (workers > hardware_concurrency()) {
    // Log::warning() << "More workers than available cores"
  }

  options_ = options;
  backlog_ = backlog;
  useSSL_ = false;
  workers_ = workers;
  workersName_ = workersName;
}

void Listener::setHandler(const std::shared_ptr<Handler> &handler) {
  handler_ = handler;
}

void Listener::pinWorker(size_t worker, const CpuSet &set) {
  UNUSED(worker)
  UNUSED(set)
#if 0
    if (ioGroup.empty()) {
        throw std::domain_error("Invalid operation, did you call init() before ?");
    }
    if (worker > ioGroup.size()) {
        throw std::invalid_argument("Trying to pin invalid worker");
    }

    auto &wrk = ioGroup[worker];
    wrk->pin(set);
#endif
}

void Listener::bind() { bind(addr_); }

void Listener::bind(const Address &address) {
  if (!handler_)
    throw std::runtime_error("Call setHandler before calling bind()");
  addr_ = address;

  struct addrinfo hints;
  hints.ai_family = address.family();
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_flags = AI_PASSIVE;
  hints.ai_protocol = 0;

  const auto &host = addr_.host();
  const auto &port = addr_.port().toString();
  AddrInfo addr_info;

  TRY(addr_info.invoke(host.c_str(), port.c_str(), &hints));

  int fd = -1;

  const addrinfo *addr = nullptr;
  for (addr = addr_info.get_info_ptr(); addr; addr = addr->ai_next) {
    fd = ::socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
    if (fd < 0)
      continue;

    setSocketOptions(fd, options_);

    if (::bind(fd, addr->ai_addr, addr->ai_addrlen) < 0) {
      close(fd);
      continue;
    }

    TRY(::listen(fd, backlog_));
    break;
  }

  // At this point, it is still possible that we couldn't bind any socket. If it
  // is the case, the previous loop would have exited naturally and addr will be
  // null.
  if (addr == nullptr) {
    throw std::runtime_error(strerror(errno));
  }

  make_non_blocking(fd);
  poller.addFd(fd, Flags<Polling::NotifyOn>(Polling::NotifyOn::Read),
               Polling::Tag(fd));
  listen_fd = fd;

  auto transport = std::make_shared<Transport>(handler_);

  reactor_.init(Aio::AsyncContext(workers_, workersName_));
  transportKey = reactor_.addHandler(transport);
}

bool Listener::isBound() const { return listen_fd != -1; }

// Return actual TCP port Listener is on, or 0 on error / no port.
// Notes:
// 1) Default constructor for 'Port()' sets value to 0.
// 2) Socket is created inside 'Listener::run()', which is called from
//    'Endpoint::serve()' and 'Endpoint::serveThreaded()'.  So getting the
//    port is only useful if you attempt to do so from a _different_ thread
//    than the one running 'Listener::run()'.  So for a traditional single-
//    threaded program this method is of little value.
Port Listener::getPort() const {
  if (listen_fd == -1) {
    return Port();
  }

  struct sockaddr_in sock_addr = {0};
  socklen_t addrlen = sizeof(sock_addr);
  auto sock_addr_alias = reinterpret_cast<struct sockaddr *>(&sock_addr);

  if (-1 == getsockname(listen_fd, sock_addr_alias, &addrlen)) {
    return Port();
  }

  return Port(ntohs(sock_addr.sin_port));
}

void Listener::run() {
  shutdownFd.bind(poller);
  reactor_.run();

  for (;;) {
    std::vector<Polling::Event> events;
    int ready_fds = poller.poll(events);

    if (ready_fds == -1) {
      throw Error::system("Polling");
    }
    for (const auto &event : events) {
      if (event.tag == shutdownFd.tag())
        return;

      if (event.flags.hasFlag(Polling::NotifyOn::Read)) {
        auto fd = event.tag.value();
        if (static_cast<ssize_t>(fd) == listen_fd) {
          try {
            handleNewConnection();
          } catch (SocketError &ex) {
            std::cerr << "Server: " << ex.what() << std::endl;
          } catch (ServerError &ex) {
            std::cerr << "Server: " << ex.what() << std::endl;
            throw;
          }
        }
      }
    }
  }
}

void Listener::runThreaded() {
  acceptThread = std::thread([=]() { this->run(); });
}

void Listener::shutdown() {
  if (shutdownFd.isBound())
    shutdownFd.notify();
  reactor_.shutdown();
}

Async::Promise<Listener::Load>
Listener::requestLoad(const Listener::Load &old) {
  auto handlers = reactor_.handlers(transportKey);

  std::vector<Async::Promise<rusage>> loads;
  for (const auto &handler : handlers) {
    auto transport = std::static_pointer_cast<Transport>(handler);
    loads.push_back(transport->load());
  }

  return Async::whenAll(std::begin(loads), std::end(loads))
      .then(
          [=](const std::vector<rusage> &usages) {
            Load res;
            res.raw = usages;

            if (old.raw.empty()) {
              res.global = 0.0;
              for (size_t i = 0; i < handlers.size(); ++i)
                res.workers.push_back(0.0);
            } else {

              auto totalElapsed = [](rusage usage) {
                return (usage.ru_stime.tv_sec * 1e6 + usage.ru_stime.tv_usec) +
                       (usage.ru_utime.tv_sec * 1e6 + usage.ru_utime.tv_usec);
              };

              auto now = std::chrono::system_clock::now();
              auto diff = now - old.tick;
              auto tick =
                  std::chrono::duration_cast<std::chrono::microseconds>(diff);
              res.tick = now;

              for (size_t i = 0; i < usages.size(); ++i) {
                auto last = old.raw[i];
                const auto &usage = usages[i];

                auto nowElapsed = totalElapsed(usage);
                auto timeElapsed = nowElapsed - totalElapsed(last);

                auto loadPct = (timeElapsed * 100.0) / tick.count();
                res.workers.push_back(loadPct);
                res.global += loadPct;
              }

              res.global /= usages.size();
            }

            return res;
          },
          Async::Throw);
}

Address Listener::address() const { return addr_; }

Options Listener::options() const { return options_; }

void Listener::handleNewConnection() {
  struct sockaddr_in peer_addr;
  int client_fd = acceptConnection(peer_addr);

  void *ssl = nullptr;

#ifdef PISTACHE_USE_SSL
  if (this->useSSL_) {

    ssl = SSL_new((SSL_CTX *)this->ssl_ctx_);
    if (ssl == NULL) {
      close(client_fd);
      throw std::runtime_error("Cannot create SSL connection");
    }

    SSL_set_fd(ssl, client_fd);
    SSL_set_accept_state(ssl);

    if (SSL_accept(ssl) <= 0) {
      ERR_print_errors_fp(stderr);
      SSL_free(ssl);
      close(client_fd);
      return;
    }
  }
#endif /* PISTACHE_USE_SSL */

  make_non_blocking(client_fd);

  std::shared_ptr<Peer> peer;
  if (this->useSSL_) {
    peer = Peer::CreateSSL(client_fd, Address::fromUnix(&peer_addr), ssl);
  } else {
    peer = Peer::Create(client_fd, Address::fromUnix(&peer_addr));
  }

  dispatchPeer(peer);
}

int Listener::acceptConnection(struct sockaddr_in &peer_addr) const {
  socklen_t peer_addr_len = sizeof(peer_addr);
  int client_fd =
      ::accept(listen_fd, (struct sockaddr *)&peer_addr, &peer_addr_len);
  if (client_fd < 0) {
    if (errno == EBADF || errno == ENOTSOCK)
      throw ServerError(strerror(errno));
    else
      throw SocketError(strerror(errno));
  }
  return client_fd;
}

void Listener::dispatchPeer(const std::shared_ptr<Peer> &peer) {
  auto handlers = reactor_.handlers(transportKey);
  auto idx = peer->fd() % handlers.size();
  auto transport = std::static_pointer_cast<Transport>(handlers[idx]);

  transport->handleNewPeer(peer);
}

#ifdef PISTACHE_USE_SSL

static SSL_CTX *ssl_create_context(const std::string &cert,
                                   const std::string &key,
                                   bool use_compression) {
  const SSL_METHOD *method;
  SSL_CTX *ctx;

  method = SSLv23_server_method();

  ctx = SSL_CTX_new(method);
  if (ctx == NULL) {
    ERR_print_errors_fp(stderr);
    throw std::runtime_error("Cannot setup SSL context");
  }

  if (!use_compression) {
    /* Disable compression to prevent BREACH and CRIME vulnerabilities. */
    if (!SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION)) {
      ERR_print_errors_fp(stderr);
      throw std::runtime_error("Cannot disable compression");
    }
  }

  /* Function introduced in 1.0.2 */
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
  SSL_CTX_set_ecdh_auto(ctx, 1);
#endif /* OPENSSL_VERSION_NUMBER */

  if (SSL_CTX_use_certificate_file(ctx, cert.c_str(), SSL_FILETYPE_PEM) <= 0) {
    ERR_print_errors_fp(stderr);
    throw std::runtime_error("Cannot load SSL certificate");
  }

  if (SSL_CTX_use_PrivateKey_file(ctx, key.c_str(), SSL_FILETYPE_PEM) <= 0) {
    ERR_print_errors_fp(stderr);
    throw std::runtime_error("Cannot load SSL private key");
  }

  if (!SSL_CTX_check_private_key(ctx)) {
    ERR_print_errors_fp(stderr);
    throw std::runtime_error(
        "Private key does not match public key in the certificate");
  }

  return ctx;
}

void Listener::setupSSLAuth(const std::string &ca_file,
                            const std::string &ca_path,
                            int (*cb)(int, void *) = NULL) {
  const char *__ca_file = NULL;
  const char *__ca_path = NULL;

  if (this->ssl_ctx_ == NULL)
    throw std::runtime_error("SSL Context is not initialized");

  if (!ca_file.empty())
    __ca_file = ca_file.c_str();
  if (!ca_path.empty())
    __ca_path = ca_path.c_str();

  if (SSL_CTX_load_verify_locations((SSL_CTX *)this->ssl_ctx_, __ca_file,
                                    __ca_path) <= 0) {
    ERR_print_errors_fp(stderr);
    throw std::runtime_error("Cannot verify SSL locations");
  }

  SSL_CTX_set_verify((SSL_CTX *)this->ssl_ctx_,
                     SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT |
                         SSL_VERIFY_CLIENT_ONCE,
  /* Callback type did change in 1.0.1 */
#if OPENSSL_VERSION_NUMBER < 0x10100000L
                     (int (*)(int, X509_STORE_CTX *))cb
#else
                     (SSL_verify_cb)cb
#endif /* OPENSSL_VERSION_NUMBER */
  );
}

void Listener::setupSSL(const std::string &cert_path,
                        const std::string &key_path, bool use_compression) {
  SSL_load_error_strings();
  OpenSSL_add_ssl_algorithms();

  this->ssl_ctx_ = ssl_create_context(cert_path, key_path, use_compression);
  this->useSSL_ = true;
}

#endif /* PISTACHE_USE_SSL */

} // namespace Tcp
} // namespace Pistache
<commit_msg>One more change<commit_after>/* listener.cc
   Mathieu Stefani, 12 August 2015

*/

#include <pistache/common.h>
#include <pistache/errors.h>
#include <pistache/listener.h>
#include <pistache/os.h>
#include <pistache/peer.h>
#include <pistache/transport.h>

#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <sys/timerfd.h>
#include <sys/types.h>

#include <chrono>
#include <memory>
#include <vector>

#include <cerrno>
#include <signal.h>

#ifdef PISTACHE_USE_SSL

#include <openssl/err.h>
#include <openssl/ssl.h>

#endif /* PISTACHE_USE_SSL */

namespace Pistache {
namespace Tcp {

void setSocketOptions(Fd fd, Flags<Options> options) {
  if (options.hasFlag(Options::ReuseAddr)) {
    int one = 1;
    TRY(::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)));
  }

  if (options.hasFlag(Options::ReusePort)) {
    int one = 1;
    TRY(::setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)));
  }

  if (options.hasFlag(Options::Linger)) {
    struct linger opt;
    opt.l_onoff = 1;
    opt.l_linger = 1;
    TRY(::setsockopt(fd, SOL_SOCKET, SO_LINGER, &opt, sizeof(opt)));
  }

  if (options.hasFlag(Options::FastOpen)) {
    int hint = 5;
    TRY(::setsockopt(fd, SOL_TCP, TCP_FASTOPEN, &hint, sizeof(hint)));
  }
  if (options.hasFlag(Options::NoDelay)) {
    int one = 1;
    TRY(::setsockopt(fd, SOL_TCP, TCP_NODELAY, &one, sizeof(one)));
  }
}

Listener::Listener()
    : addr_(), listen_fd(-1), backlog_(Const::MaxBacklog), shutdownFd(),
      poller(), options_(), workers_(Const::DefaultWorkers), workersName_(),
      reactor_(), transportKey(), useSSL_(false), ssl_ctx_(nullptr) {}

Listener::Listener(const Address &address)
    : addr_(address), listen_fd(-1), backlog_(Const::MaxBacklog), shutdownFd(),
      poller(), options_(), workers_(Const::DefaultWorkers), workersName_(),
      reactor_(), transportKey(), useSSL_(false), ssl_ctx_(nullptr) {}

Listener::~Listener() {
  if (isBound())
    shutdown();
  if (acceptThread.joinable())
    acceptThread.join();

  if (listen_fd >= 0) {
    close(listen_fd);
    listen_fd = -1;
  }
#ifdef PISTACHE_USE_SSL
  if (this->useSSL_) {
    SSL_CTX_free((SSL_CTX *)this->ssl_ctx_);
    EVP_cleanup();
  }
#endif /* PISTACHE_USE_SSL */
}

void Listener::init(size_t workers, Flags<Options> options,
                    const std::string &workersName, int backlog) {
  if (workers > hardware_concurrency()) {
    // Log::warning() << "More workers than available cores"
  }

  options_ = options;
  backlog_ = backlog;
  useSSL_ = false;
  workers_ = workers;
  workersName_ = workersName;
}

void Listener::setHandler(const std::shared_ptr<Handler> &handler) {
  handler_ = handler;
}

void Listener::pinWorker(size_t worker, const CpuSet &set) {
  UNUSED(worker)
  UNUSED(set)
#if 0
    if (ioGroup.empty()) {
        throw std::domain_error("Invalid operation, did you call init() before ?");
    }
    if (worker > ioGroup.size()) {
        throw std::invalid_argument("Trying to pin invalid worker");
    }

    auto &wrk = ioGroup[worker];
    wrk->pin(set);
#endif
}

void Listener::bind() { bind(addr_); }

void Listener::bind(const Address &address) {
  if (!handler_)
    throw std::runtime_error("Call setHandler before calling bind()");
  addr_ = address;

  struct addrinfo hints;
  hints.ai_family = address.family();
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_flags = AI_PASSIVE;
  hints.ai_protocol = 0;

  const auto &host = addr_.host();
  const auto &port = addr_.port().toString();
  AddrInfo addr_info;

  TRY(addr_info.invoke(host.c_str(), port.c_str(), &hints));

  int fd = -1;

  const addrinfo *addr = nullptr;
  for (addr = addr_info.get_info_ptr(); addr; addr = addr->ai_next) {
    fd = ::socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
    if (fd < 0)
      continue;

    setSocketOptions(fd, options_);

    if (::bind(fd, addr->ai_addr, addr->ai_addrlen) < 0) {
      close(fd);
      continue;
    }

    TRY(::listen(fd, backlog_));
    break;
  }

  // At this point, it is still possible that we couldn't bind any socket. If it
  // is the case, the previous loop would have exited naturally and addr will be
  // null.
  if (addr == nullptr) {
    throw std::runtime_error(strerror(errno));
  }

  make_non_blocking(fd);
  poller.addFd(fd, Flags<Polling::NotifyOn>(Polling::NotifyOn::Read),
               Polling::Tag(fd));
  listen_fd = fd;

  auto transport = std::make_shared<Transport>(handler_);

  reactor_.init(Aio::AsyncContext(workers_, workersName_));
  transportKey = reactor_.addHandler(transport);
}

bool Listener::isBound() const { return listen_fd != -1; }

// Return actual TCP port Listener is on, or 0 on error / no port.
// Notes:
// 1) Default constructor for 'Port()' sets value to 0.
// 2) Socket is created inside 'Listener::run()', which is called from
//    'Endpoint::serve()' and 'Endpoint::serveThreaded()'.  So getting the
//    port is only useful if you attempt to do so from a _different_ thread
//    than the one running 'Listener::run()'.  So for a traditional single-
//    threaded program this method is of little value.
Port Listener::getPort() const {
  if (listen_fd == -1) {
    return Port();
  }

  struct sockaddr_in sock_addr = {0};
  socklen_t addrlen = sizeof(sock_addr);
  auto sock_addr_alias = reinterpret_cast<struct sockaddr *>(&sock_addr);

  if (-1 == getsockname(listen_fd, sock_addr_alias, &addrlen)) {
    return Port();
  }

  return Port(ntohs(sock_addr.sin_port));
}

void Listener::run() {
  shutdownFd.bind(poller);
  reactor_.run();

  for (;;) {
    std::vector<Polling::Event> events;
    int ready_fds = poller.poll(events);

    if (ready_fds == -1) {
      throw Error::system("Polling");
    }
    for (const auto &event : events) {
      if (event.tag == shutdownFd.tag())
        return;

      if (event.flags.hasFlag(Polling::NotifyOn::Read)) {
        auto fd = event.tag.value();
        if (static_cast<ssize_t>(fd) == listen_fd) {
          try {
            handleNewConnection();
          } catch (SocketError &ex) {
            std::cerr << "Server: " << ex.what() << std::endl;
          } catch (ServerError &ex) {
            std::cerr << "Server: " << ex.what() << std::endl;
            throw;
          }
        }
      }
    }
  }
}

void Listener::runThreaded() {
  acceptThread = std::thread([=]() { this->run(); });
}

void Listener::shutdown() {
  if (shutdownFd.isBound())
    shutdownFd.notify();
  reactor_.shutdown();
}

Async::Promise<Listener::Load>
Listener::requestLoad(const Listener::Load &old) {
  auto handlers = reactor_.handlers(transportKey);

  std::vector<Async::Promise<rusage>> loads;
  for (const auto &handler : handlers) {
    auto transport = std::static_pointer_cast<Transport>(handler);
    loads.push_back(transport->load());
  }

  return Async::whenAll(std::begin(loads), std::end(loads))
      .then(
          [=](const std::vector<rusage> &usages) {
            Load res;
            res.raw = usages;

            if (old.raw.empty()) {
              res.global = 0.0;
              for (size_t i = 0; i < handlers.size(); ++i)
                res.workers.push_back(0.0);
            } else {

              auto totalElapsed = [](rusage usage) {
                return (usage.ru_stime.tv_sec * 1e6 + usage.ru_stime.tv_usec) +
                       (usage.ru_utime.tv_sec * 1e6 + usage.ru_utime.tv_usec);
              };

              auto now = std::chrono::system_clock::now();
              auto diff = now - old.tick;
              auto tick =
                  std::chrono::duration_cast<std::chrono::microseconds>(diff);
              res.tick = now;

              for (size_t i = 0; i < usages.size(); ++i) {
                auto last = old.raw[i];
                const auto &usage = usages[i];

                auto nowElapsed = totalElapsed(usage);
                auto timeElapsed = nowElapsed - totalElapsed(last);

                auto loadPct = (timeElapsed * 100.0) / tick.count();
                res.workers.push_back(loadPct);
                res.global += loadPct;
              }

              res.global /= usages.size();
            }

            return res;
          },
          Async::Throw);
}

Address Listener::address() const { return addr_; }

Options Listener::options() const { return options_; }

void Listener::handleNewConnection() {
  struct sockaddr_in peer_addr;
  int client_fd = acceptConnection(peer_addr);

  void *ssl = nullptr;

#ifdef PISTACHE_USE_SSL
  if (this->useSSL_) {

    SSL* ssl_data = SSL_new((SSL_CTX *)this->ssl_ctx_);
    if (ssl == NULL) {
      close(client_fd);
      throw std::runtime_error("Cannot create SSL connection");
    }

    SSL_set_fd(ssl, client_fd);
    SSL_set_accept_state(ssl);

    if (SSL_accept(ssl) <= 0) {
      ERR_print_errors_fp(stderr);
      SSL_free(ssl);
      close(client_fd);
      return;
    }
    ssl = static_cast<void*>(ssl);
  }
#endif /* PISTACHE_USE_SSL */

  make_non_blocking(client_fd);

  std::shared_ptr<Peer> peer;
  if (this->useSSL_) {
    peer = Peer::CreateSSL(client_fd, Address::fromUnix(&peer_addr), ssl);
  } else {
    peer = Peer::Create(client_fd, Address::fromUnix(&peer_addr));
  }

  dispatchPeer(peer);
}

int Listener::acceptConnection(struct sockaddr_in &peer_addr) const {
  socklen_t peer_addr_len = sizeof(peer_addr);
  int client_fd =
      ::accept(listen_fd, (struct sockaddr *)&peer_addr, &peer_addr_len);
  if (client_fd < 0) {
    if (errno == EBADF || errno == ENOTSOCK)
      throw ServerError(strerror(errno));
    else
      throw SocketError(strerror(errno));
  }
  return client_fd;
}

void Listener::dispatchPeer(const std::shared_ptr<Peer> &peer) {
  auto handlers = reactor_.handlers(transportKey);
  auto idx = peer->fd() % handlers.size();
  auto transport = std::static_pointer_cast<Transport>(handlers[idx]);

  transport->handleNewPeer(peer);
}

#ifdef PISTACHE_USE_SSL

static SSL_CTX *ssl_create_context(const std::string &cert,
                                   const std::string &key,
                                   bool use_compression) {
  const SSL_METHOD *method;
  SSL_CTX *ctx;

  method = SSLv23_server_method();

  ctx = SSL_CTX_new(method);
  if (ctx == NULL) {
    ERR_print_errors_fp(stderr);
    throw std::runtime_error("Cannot setup SSL context");
  }

  if (!use_compression) {
    /* Disable compression to prevent BREACH and CRIME vulnerabilities. */
    if (!SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION)) {
      ERR_print_errors_fp(stderr);
      throw std::runtime_error("Cannot disable compression");
    }
  }

  /* Function introduced in 1.0.2 */
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
  SSL_CTX_set_ecdh_auto(ctx, 1);
#endif /* OPENSSL_VERSION_NUMBER */

  if (SSL_CTX_use_certificate_file(ctx, cert.c_str(), SSL_FILETYPE_PEM) <= 0) {
    ERR_print_errors_fp(stderr);
    throw std::runtime_error("Cannot load SSL certificate");
  }

  if (SSL_CTX_use_PrivateKey_file(ctx, key.c_str(), SSL_FILETYPE_PEM) <= 0) {
    ERR_print_errors_fp(stderr);
    throw std::runtime_error("Cannot load SSL private key");
  }

  if (!SSL_CTX_check_private_key(ctx)) {
    ERR_print_errors_fp(stderr);
    throw std::runtime_error(
        "Private key does not match public key in the certificate");
  }

  return ctx;
}

void Listener::setupSSLAuth(const std::string &ca_file,
                            const std::string &ca_path,
                            int (*cb)(int, void *) = NULL) {
  const char *__ca_file = NULL;
  const char *__ca_path = NULL;

  if (this->ssl_ctx_ == NULL)
    throw std::runtime_error("SSL Context is not initialized");

  if (!ca_file.empty())
    __ca_file = ca_file.c_str();
  if (!ca_path.empty())
    __ca_path = ca_path.c_str();

  if (SSL_CTX_load_verify_locations((SSL_CTX *)this->ssl_ctx_, __ca_file,
                                    __ca_path) <= 0) {
    ERR_print_errors_fp(stderr);
    throw std::runtime_error("Cannot verify SSL locations");
  }

  SSL_CTX_set_verify((SSL_CTX *)this->ssl_ctx_,
                     SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT |
                         SSL_VERIFY_CLIENT_ONCE,
  /* Callback type did change in 1.0.1 */
#if OPENSSL_VERSION_NUMBER < 0x10100000L
                     (int (*)(int, X509_STORE_CTX *))cb
#else
                     (SSL_verify_cb)cb
#endif /* OPENSSL_VERSION_NUMBER */
  );
}

void Listener::setupSSL(const std::string &cert_path,
                        const std::string &key_path, bool use_compression) {
  SSL_load_error_strings();
  OpenSSL_add_ssl_algorithms();

  this->ssl_ctx_ = ssl_create_context(cert_path, key_path, use_compression);
  this->useSSL_ = true;
}

#endif /* PISTACHE_USE_SSL */

} // namespace Tcp
} // namespace Pistache
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2001 Jani Kajala
 *
 * Permission to use, copy, modify, distribute and sell this
 * software and its documentation for any purpose is hereby
 * granted without fee, provided that the above copyright notice
 * appear in all copies and that both that copyright notice and
 * this permission notice appear in supporting documentation.
 * Jani Kajala makes no representations about the suitability
 * of this software for any purpose. It is provided "as is"
 * without express or implied warranty.
 */

#include "MapFile.h"
#include "MapFileEntry.h"
#include "TextFile.h"
#include "Array.h"
#include <algorithm>
#include <cstring>
#include <cctype>
#ifdef WIN32
#include <windows.h>
#endif

class MapFile::MapFileImpl
{
    public:
        long                loadAddr;
        char                name[256];
        Array<MapFileEntry> segments;
        Array<MapFileEntry> entries;

        MapFileImpl(const char* filename) : loadAddr(0), m_file(filename), m_err(MapFile::ERROR_NONE), m_errLine(0)
        {
            m_file.readString(name, sizeof(name));

            char buf[1024];
            while(m_file.readString(buf, sizeof(buf)))
            {
                if(!strcmp("Preferred", buf))
                    parseLoadAddress();
                else if(!strcmp("Start", buf))
                    parseSegments();
                else if(!strcmp("Address", buf))
                    parseEntries();
                else
                    m_file.skipLine();
            }

            std::sort(segments.begin(), segments.end());
            std::sort(entries.begin(), entries.end());
        }

        ~MapFileImpl()
        {
        }

        ErrorType error() const
        {
            if(m_err != MapFile::ERROR_NONE)
                return m_err;

            switch(m_file.error())
            {
                case TextFile::ERROR_OPEN:
                    return MapFile::ERROR_OPEN;
                case TextFile::ERROR_READ:
                    return MapFile::ERROR_READ;
                case TextFile::ERROR_PARSE:
                    return MapFile::ERROR_PARSE;
                default:
                    return MapFile::ERROR_NONE;
            }
        }

        int line() const
        {
            if(m_err != MapFile::ERROR_NONE)
                return m_errLine;

            return m_file.line();
        }

    private:
        TextFile            m_file;
        MapFile::ErrorType    m_err;
        int                    m_errLine;

        /**
         * Returns true if the next line is empty.
         */
        bool nextLineEmpty()
        {
            m_file.skipLine();
            char ch;
            while(m_file.peekChar(&ch) && isspace(ch) && ch != '\n')
                m_file.readChar(&ch);
            if(m_file.peekChar(&ch) && ch == '\n')
                return true;
            return false;
        }

        /**
         * Parses specified string.
         * Sets error if parsed string doesnt match.
         */
        void parse(const char* str)
        {
            char buf[256];
            m_file.readString(buf, sizeof(buf));
            if(strcmp(str, buf))
            {
                m_err = MapFile::ERROR_PARSE;
                m_errLine = m_file.line();
            }
        }

        /**
         * Parses specified character.
         * Sets error if parsed character doesnt match.
         */
        void parse(char ch)
        {
            char ch2;
            if(!m_file.readChar(&ch2) || ch2 != ch)
            {
                m_err = MapFile::ERROR_PARSE;
                m_errLine = m_file.line();
            }
        }

        /**
         * Example:
         * (Preferred) load address is 00400000
         */
        void parseLoadAddress()
        {
            parse("load");
            parse("address");
            parse("is");
            loadAddr = m_file.readHex();
        }

        /**
         * Example:
         * (Start)       Length     Name                   Class
         * 0001:00000000 00002c05H .text                   CODE
         */
        void parseSegments()
        {
            parse("Length");
            parse("Name");
            parse("Class");
            m_file.skipWhitespace();

            while(!error())
            {
                int seg = m_file.readHex();
                parse(':');
                int offs = m_file.readHex();
                int len = m_file.readHex();
                parse('H');
                char buf[256];
                m_file.readString(buf, sizeof(buf));
                segments.add(MapFileEntry(seg, offs, len, buf));

                // break at empty line
                if(nextLineEmpty())
                    break;
            }
        }

        /**
         * Example:
         * (Address)       Publics by Value           Rva+Base     Lib:Object
         * 0001:000001a0   ?stackTrace@@YAXXZ         004011a0 f   main.obj
         */
        void parseEntries()
        {
            parse("Publics");
            parse("by");
            parse("Value");
            parse("Rva+Base");
            parse("Lib:Object");
            m_file.skipWhitespace();

            while(!error())
            {
                int seg = m_file.readHex();
                parse(':');
                int offs = m_file.readHex();
                char buf[256];
                m_file.readString(buf, sizeof(buf));
                char* entryname = buf;

                // chop entry name at @@
                char* end = strstr(entryname, "@@");
                if(end)
                    *end = 0;
                // skip preceding ?01..
                while(isdigit(*entryname) || *entryname == '?' || *entryname == '$')
                    ++entryname;
                // conv @ -> .
                for(char* str = entryname ; *str ; ++str)
                    if(*str == '@')
                        *str = '.';

                entries.add(MapFileEntry(seg, offs, 0, entryname));

                // break at empty line
                if(nextLineEmpty())
                    break;
            }
        }
};

//-----------------------------------------------------------------------------

MapFile::MapFile(const char* filename)
{
    m_this = new MapFileImpl(filename);
}

MapFile::~MapFile()
{
    delete m_this;
}

long MapFile::loadAddress() const
{
    return m_this->loadAddr;
}

const MapFileEntry & MapFile::getSegment(int i) const
{
    return m_this->segments[i];
}

const MapFileEntry & MapFile::getEntry(int i) const
{
    return m_this->entries[i];
}

int MapFile::segments() const
{
    return m_this->segments.size();
}

int MapFile::entries() const
{
    return m_this->entries.size();
}

MapFile::ErrorType MapFile::error() const
{
    return m_this->error();
}

int MapFile::line() const
{
    return m_this->line();
}

int MapFile::findEntry(long addr) const
{
    for(int j = 0 ; j < segments() ; ++j)
    {
        const MapFileEntry & segment = getSegment(j);
        long section = segment.section();
        long segmentBegin = loadAddress() + (segment.section() << 12) + segment.offset();
        long segmentEnd = segmentBegin + segment.length();

        if(addr >= segmentBegin && addr < segmentEnd)
        {
            for(int i = entries() - 1 ; i >= 0  ; --i)
            {
                const MapFileEntry entry = getEntry(i);
                if(entry.section() == section)
                {
                    long entryAddr = loadAddress() + (entry.section() << 12) + entry.offset();
                    if(entryAddr <= addr)
                        return i;
                }
            }
        }
    }
    return -1;
}

void MapFile::getModuleMapFilename(char* buffer, int bufferSize)
{
    int len = 0;
    buffer[len] = 0;

#ifdef WIN32
    // get name of the exe/dll
    len = GetModuleFileName(GetModuleHandle(0), buffer, bufferSize - 1);
    buffer[len] = 0;
#endif

    // remove .exe or .dll extension
    if(len > 3 &&
            (!strcmp(buffer + len - 4, ".exe") || !strcmp(buffer + len - 4, ".EXE") ||
             !strcmp(buffer + len - 4, ".DLL") || !strcmp(buffer + len - 4, ".dll")))
    {
        buffer[len - 4] = 0;
    }

    // append .map extension
    if((int)strlen(buffer) + 4 < bufferSize)
    {
        strcat(buffer, ".map");
    }
}
<commit_msg>Resolved CID 53073 (Logically dead code). .dll and .exe extension for modules<commit_after>/*
 * Copyright (c) 2001 Jani Kajala
 *
 * Permission to use, copy, modify, distribute and sell this
 * software and its documentation for any purpose is hereby
 * granted without fee, provided that the above copyright notice
 * appear in all copies and that both that copyright notice and
 * this permission notice appear in supporting documentation.
 * Jani Kajala makes no representations about the suitability
 * of this software for any purpose. It is provided "as is"
 * without express or implied warranty.
 */

#include "MapFile.h"
#include "MapFileEntry.h"
#include "TextFile.h"
#include "Array.h"
#include <algorithm>
#include <cstring>
#include <cctype>
#ifdef WIN32
#include <windows.h>
#endif

class MapFile::MapFileImpl
{
    public:
        long                loadAddr;
        char                name[256];
        Array<MapFileEntry> segments;
        Array<MapFileEntry> entries;

        MapFileImpl(const char* filename) : loadAddr(0), m_file(filename), m_err(MapFile::ERROR_NONE), m_errLine(0)
        {
            m_file.readString(name, sizeof(name));

            char buf[1024];
            while(m_file.readString(buf, sizeof(buf)))
            {
                if(!strcmp("Preferred", buf))
                    parseLoadAddress();
                else if(!strcmp("Start", buf))
                    parseSegments();
                else if(!strcmp("Address", buf))
                    parseEntries();
                else
                    m_file.skipLine();
            }

            std::sort(segments.begin(), segments.end());
            std::sort(entries.begin(), entries.end());
        }

        ~MapFileImpl()
        {
        }

        ErrorType error() const
        {
            if(m_err != MapFile::ERROR_NONE)
                return m_err;

            switch(m_file.error())
            {
                case TextFile::ERROR_OPEN:
                    return MapFile::ERROR_OPEN;
                case TextFile::ERROR_READ:
                    return MapFile::ERROR_READ;
                case TextFile::ERROR_PARSE:
                    return MapFile::ERROR_PARSE;
                default:
                    return MapFile::ERROR_NONE;
            }
        }

        int line() const
        {
            if(m_err != MapFile::ERROR_NONE)
                return m_errLine;

            return m_file.line();
        }

    private:
        TextFile            m_file;
        MapFile::ErrorType    m_err;
        int                    m_errLine;

        /**
         * Returns true if the next line is empty.
         */
        bool nextLineEmpty()
        {
            m_file.skipLine();
            char ch;
            while(m_file.peekChar(&ch) && isspace(ch) && ch != '\n')
                m_file.readChar(&ch);
            if(m_file.peekChar(&ch) && ch == '\n')
                return true;
            return false;
        }

        /**
         * Parses specified string.
         * Sets error if parsed string doesnt match.
         */
        void parse(const char* str)
        {
            char buf[256];
            m_file.readString(buf, sizeof(buf));
            if(strcmp(str, buf))
            {
                m_err = MapFile::ERROR_PARSE;
                m_errLine = m_file.line();
            }
        }

        /**
         * Parses specified character.
         * Sets error if parsed character doesnt match.
         */
        void parse(char ch)
        {
            char ch2;
            if(!m_file.readChar(&ch2) || ch2 != ch)
            {
                m_err = MapFile::ERROR_PARSE;
                m_errLine = m_file.line();
            }
        }

        /**
         * Example:
         * (Preferred) load address is 00400000
         */
        void parseLoadAddress()
        {
            parse("load");
            parse("address");
            parse("is");
            loadAddr = m_file.readHex();
        }

        /**
         * Example:
         * (Start)       Length     Name                   Class
         * 0001:00000000 00002c05H .text                   CODE
         */
        void parseSegments()
        {
            parse("Length");
            parse("Name");
            parse("Class");
            m_file.skipWhitespace();

            while(!error())
            {
                int seg = m_file.readHex();
                parse(':');
                int offs = m_file.readHex();
                int len = m_file.readHex();
                parse('H');
                char buf[256];
                m_file.readString(buf, sizeof(buf));
                segments.add(MapFileEntry(seg, offs, len, buf));

                // break at empty line
                if(nextLineEmpty())
                    break;
            }
        }

        /**
         * Example:
         * (Address)       Publics by Value           Rva+Base     Lib:Object
         * 0001:000001a0   ?stackTrace@@YAXXZ         004011a0 f   main.obj
         */
        void parseEntries()
        {
            parse("Publics");
            parse("by");
            parse("Value");
            parse("Rva+Base");
            parse("Lib:Object");
            m_file.skipWhitespace();

            while(!error())
            {
                int seg = m_file.readHex();
                parse(':');
                int offs = m_file.readHex();
                char buf[256];
                m_file.readString(buf, sizeof(buf));
                char* entryname = buf;

                // chop entry name at @@
                char* end = strstr(entryname, "@@");
                if(end)
                    *end = 0;
                // skip preceding ?01..
                while(isdigit(*entryname) || *entryname == '?' || *entryname == '$')
                    ++entryname;
                // conv @ -> .
                for(char* str = entryname ; *str ; ++str)
                    if(*str == '@')
                        *str = '.';

                entries.add(MapFileEntry(seg, offs, 0, entryname));

                // break at empty line
                if(nextLineEmpty())
                    break;
            }
        }
};

//-----------------------------------------------------------------------------

MapFile::MapFile(const char* filename)
{
    m_this = new MapFileImpl(filename);
}

MapFile::~MapFile()
{
    delete m_this;
}

long MapFile::loadAddress() const
{
    return m_this->loadAddr;
}

const MapFileEntry & MapFile::getSegment(int i) const
{
    return m_this->segments[i];
}

const MapFileEntry & MapFile::getEntry(int i) const
{
    return m_this->entries[i];
}

int MapFile::segments() const
{
    return m_this->segments.size();
}

int MapFile::entries() const
{
    return m_this->entries.size();
}

MapFile::ErrorType MapFile::error() const
{
    return m_this->error();
}

int MapFile::line() const
{
    return m_this->line();
}

int MapFile::findEntry(long addr) const
{
    for(int j = 0 ; j < segments() ; ++j)
    {
        const MapFileEntry & segment = getSegment(j);
        long section = segment.section();
        long segmentBegin = loadAddress() + (segment.section() << 12) + segment.offset();
        long segmentEnd = segmentBegin + segment.length();

        if(addr >= segmentBegin && addr < segmentEnd)
        {
            for(int i = entries() - 1 ; i >= 0  ; --i)
            {
                const MapFileEntry entry = getEntry(i);
                if(entry.section() == section)
                {
                    long entryAddr = loadAddress() + (entry.section() << 12) + entry.offset();
                    if(entryAddr <= addr)
                        return i;
                }
            }
        }
    }
    return -1;
}

void MapFile::getModuleMapFilename(char* buffer, int bufferSize)
{
    int len = 0;
    buffer[len] = 0;

#ifdef WIN32
    // get name of the exe/dll
    len = GetModuleFileName(GetModuleHandle(0), buffer, bufferSize - 1);
    buffer[len] = 0;

    // remove .exe or .dll extension
    if (len > 3 &&
        (!strcmp(buffer + len - 4, ".exe") || !strcmp(buffer + len - 4, ".EXE") ||
        !strcmp(buffer + len - 4, ".DLL") || !strcmp(buffer + len - 4, ".dll")))
    {
        buffer[len - 4] = 0;
    }
#endif

    // append .map extension
    if((int)strlen(buffer) + 4 < bufferSize)
    {
        strcat(buffer, ".map");
    }
}
<|endoftext|>


<commit_before>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

#ifndef __STATE_PROTOBUF_HPP__
#define __STATE_PROTOBUF_HPP__

#include <string>

#include <process/future.hpp>

#include <stout/lambda.hpp>
#include <stout/option.hpp>
#include <stout/some.hpp>
#include <stout/try.hpp>
#include <stout/uuid.hpp>

#include "messages/messages.hpp"
#include "messages/state.hpp"

#include "state/state.hpp"
#include "state/storage.hpp"

namespace mesos {
namespace internal {
namespace state {
namespace protobuf {

template <typename T>
class Variable
{
public:
  T get() const
  {
    return t;
  }

  Variable mutate(const T& t) const
  {
    Variable variable(*this);
    variable.t = t;
    return variable;
  }

private:
  friend class State; // Creates and manages variables.

  Variable(const state::Variable& _variable, const T& _t)
    : variable(_variable), t(_t)
  {}

  state::Variable variable; // Not const to keep Variable assignable.
  T t;
};

class State : public state::State
{
public:
  explicit State(Storage* storage) : state::State(storage) {}
  virtual ~State() {}

  // Returns a variable from the state, creating a new one if one
  // previously did not exist (or an error if one occurs).
  template <typename T>
  process::Future<Variable<T> > fetch(const std::string& name);

  // Returns the variable specified if it was successfully stored in
  // the state, otherwise returns none if the version of the variable
  // was no longer valid, or an error if one occurs.
  template <typename T>
  process::Future<Option<Variable<T> > > store(const Variable<T>& variable);

  // Expunges the variable from the state.
  template <typename T>
  process::Future<bool> expunge(const Variable<T>& variable);

private:
  // Helpers to handle future results from fetch and swap. We make
  // these static members of State for friend access to Variable's
  // constructor.
  template <typename T>
  static process::Future<Variable<T> > _fetch(
      const state::Variable& option);

  template <typename T>
  static process::Future<Option<Variable<T> > > _store(
      const T& t,
      const Option<state::Variable>& variable);
};

template <typename T>
process::Future<Variable<T> > State::fetch(const std::string& name)
{
  return state::State::fetch(name)
    .then(lambda::bind(&State::template _fetch<T>, lambda::_1));
}

template <typename T>
process::Future<Variable<T> > State::_fetch(
    const state::Variable& variable)
{
  Try<T> t = messages::deserialize<T>(variable.value());
  if (t.isError()) {
    return process::Failure(t.error());
  }

  return Variable<T>(variable, t.get());
}

template <typename T>
process::Future<Option<Variable<T> > > State::store(
    const Variable<T>& variable)
{
  Try<std::string> value = messages::serialize(variable.t);

  if (value.isError()) {
    return process::Failure(value.error());
  }

  return state::State::store(variable.variable.mutate(value.get()))
    .then(lambda::bind(&State::template _store<T>, variable.t, lambda::_1));
}

template <typename T>
process::Future<Option<Variable<T> > > State::_store(
    const T& t,
    const Option<state::Variable>& variable)
{
  if (variable.isSome()) {
    return Some(Variable<T>(variable.get(), t));
  }

  return None();
}

template <typename T>
process::Future<bool> State::expunge(const Variable<T>& variable)
{
  return state::State::expunge(variable.variable);
}

} // namespace protobuf {
} // namespace state {
} // namespace internal {
} // namespace mesos {

#endif // __STATE_PROTOBUF_HPP__
<commit_msg>Fixed MESOS-1427: 'friend' statement in Variable resolved to a different State class on clang 3.2<commit_after>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

#ifndef __STATE_PROTOBUF_HPP__
#define __STATE_PROTOBUF_HPP__

#include <string>

#include <process/future.hpp>

#include <stout/lambda.hpp>
#include <stout/option.hpp>
#include <stout/some.hpp>
#include <stout/try.hpp>
#include <stout/uuid.hpp>

#include "messages/messages.hpp"
#include "messages/state.hpp"

#include "state/state.hpp"
#include "state/storage.hpp"

namespace mesos {
namespace internal {
namespace state {
namespace protobuf {

class State; // Forward declaration.

template <typename T>
class Variable
{
public:
  T get() const
  {
    return t;
  }

  Variable mutate(const T& t) const
  {
    Variable variable(*this);
    variable.t = t;
    return variable;
  }

private:
  friend class State; // Creates and manages variables.

  Variable(const state::Variable& _variable, const T& _t)
    : variable(_variable), t(_t)
  {}

  state::Variable variable; // Not const to keep Variable assignable.
  T t;
};

class State : public state::State
{
public:
  explicit State(Storage* storage) : state::State(storage) {}
  virtual ~State() {}

  // Returns a variable from the state, creating a new one if one
  // previously did not exist (or an error if one occurs).
  template <typename T>
  process::Future<Variable<T> > fetch(const std::string& name);

  // Returns the variable specified if it was successfully stored in
  // the state, otherwise returns none if the version of the variable
  // was no longer valid, or an error if one occurs.
  template <typename T>
  process::Future<Option<Variable<T> > > store(const Variable<T>& variable);

  // Expunges the variable from the state.
  template <typename T>
  process::Future<bool> expunge(const Variable<T>& variable);

private:
  // Helpers to handle future results from fetch and swap. We make
  // these static members of State for friend access to Variable's
  // constructor.
  template <typename T>
  static process::Future<Variable<T> > _fetch(
      const state::Variable& option);

  template <typename T>
  static process::Future<Option<Variable<T> > > _store(
      const T& t,
      const Option<state::Variable>& variable);
};

template <typename T>
process::Future<Variable<T> > State::fetch(const std::string& name)
{
  return state::State::fetch(name)
    .then(lambda::bind(&State::template _fetch<T>, lambda::_1));
}

template <typename T>
process::Future<Variable<T> > State::_fetch(
    const state::Variable& variable)
{
  Try<T> t = messages::deserialize<T>(variable.value());
  if (t.isError()) {
    return process::Failure(t.error());
  }

  return Variable<T>(variable, t.get());
}

template <typename T>
process::Future<Option<Variable<T> > > State::store(
    const Variable<T>& variable)
{
  Try<std::string> value = messages::serialize(variable.t);

  if (value.isError()) {
    return process::Failure(value.error());
  }

  return state::State::store(variable.variable.mutate(value.get()))
    .then(lambda::bind(&State::template _store<T>, variable.t, lambda::_1));
}

template <typename T>
process::Future<Option<Variable<T> > > State::_store(
    const T& t,
    const Option<state::Variable>& variable)
{
  if (variable.isSome()) {
    return Some(Variable<T>(variable.get(), t));
  }

  return None();
}

template <typename T>
process::Future<bool> State::expunge(const Variable<T>& variable)
{
  return state::State::expunge(variable.variable);
}

} // namespace protobuf {
} // namespace state {
} // namespace internal {
} // namespace mesos {

#endif // __STATE_PROTOBUF_HPP__
<|endoftext|>