<commit_before>#pragma once
//=====================================================================//
/*!	@file
	@brief	ethernet_client class
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2017 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include "ethernet.hpp"

#include "common/delay.hpp"

namespace net {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  ethernet_client class
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	class ethernet_client {

		ethernet&	ethernet_;

		uint32_t	cepid_;
		uint16_t	port_;

		uint16_t	close_count_;

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクター
			@param[in]	e	インサーネットへの参照
			@param[in]	port	ポート番号
		*/
		//-----------------------------------------------------------------//
		ethernet_client(ethernet& e, uint16_t port) : ethernet_(e), cepid_(0), port_(port),
			close_count_(0) { }

		//-----------------------------------------------------------------//
		/*!
			@brief  デストラクター
		*/
		//-----------------------------------------------------------------//
		~ethernet_client() {
			stop();
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  ethernet を参照
			@return ethernet
		*/
		//-----------------------------------------------------------------//
		ethernet& at_ethernet() { return ethernet_; }

		//-----------------------------------------------------------------//
		/*!
			@brief  ethernet を参照
			@return ethernet
		*/
		//-----------------------------------------------------------------//
		const ethernet& get_ethernet() const { return ethernet_; }

		//-----------------------------------------------------------------//
		/*!
			@brief  ポート番号を取得
			@return ポート番号
		*/
		//-----------------------------------------------------------------//
		uint16_t get_port() const { return port_; }

		//-----------------------------------------------------------------//
		/*!
			@brief  CEP ID を取得
			@return CEP ID
		*/
		//-----------------------------------------------------------------//
		uint32_t get_cepid() const { return cepid_; }

		//-----------------------------------------------------------------//
		/*!
			@brief  接続先を取得
			@return 接続先
		*/
		//-----------------------------------------------------------------//
		const ip_address& get_from_ip() const {
			const ethernet::CEP& cep = ethernet_.get_cep(cepid_);
			uint32_t ipw = cep.src_addr.ipaddr;
			static ip_address ip((ipw >> 24) & 255, (ipw >> 16) & 255, (ipw >> 8) & 255, ipw & 255);
			return ip;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  コネクション
			@param[in]	ip		接続先の IP アドレス
			@param[in]	port	接続ポート
			@param[in]	timeout	タイムアウト、単位１０ミリ秒（標準で１０秒）
			@return 接続できた場合「true」
		*/
		//-----------------------------------------------------------------//
		bool connect(const ip_address& ip, uint16_t port, int32_t timeout = 1000)
		{
			if(cepid_ == 0) {
				cepid_ = ethernet_.create(port_);
				if(cepid_ == 0) return false;
				close_count_ = tcp_get_close_count(cepid_);
			}

			auto& cep = ethernet_.at_cep(cepid_);
			cep.server = false;

			if(connected()) {
				return true;
			}

			debug_format("TCP Client Request Connect: %d\n") % cepid_;

			static T_IPV4EP adr;
			adr.ipaddr =  (static_cast<uint32_t>(ip[0]) << 24)
						| (static_cast<uint32_t>(ip[1]) << 16)
						| (static_cast<uint32_t>(ip[2]) << 8)
						| (static_cast<uint32_t>(ip[3]));
			adr.portno = port;
			int ercd = tcp_con_cep(cepid_, NADR, &adr, timeout);
			bool ret = true;
			if(ercd == E_OK) {
				debug_format("TCP Client connect OK: %d\n") % cepid_;
			} else if(ercd == E_QOVR) {
				debug_format("TCP Client E_QOVR: %d\n") % cepid_;
				ret = false;
			} else {
				debug_format("TCP Client connect state(%d): %d\n") % ercd % cepid_;
			}
			tcp_clear_rst(cepid_);
			return ret;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  再接続要求
			@return 正常なら「true」
		*/
		//-----------------------------------------------------------------//
		bool re_connect(const ip_address& ip, uint16_t port)
		{
			if(cepid_ == 0) {  // ディスクリプタが無効
				return false;
			}

			static T_IPV4EP adr;
			adr.ipaddr =  (static_cast<uint32_t>(ip[0]) << 24)
						| (static_cast<uint32_t>(ip[1]) << 16)
						| (static_cast<uint32_t>(ip[2]) << 8)
						| (static_cast<uint32_t>(ip[3]));
			adr.portno = port;

			if(tcp_re_con_cep(cepid_, &adr) < 0) {
				return false;
			} else {
				return true;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  接続確認
			@return 接続中なら「true」
		*/
		//-----------------------------------------------------------------//
		bool connected()
		{
			return ethernet_.connected(cepid_);
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  読み込み
			@param[out]	buff	読み込み先
			@param[in]	size	読み込みサイズ
			@return 読み込みサイズ（負の場合エラー）
		*/
		//-----------------------------------------------------------------//
		int read(void* buff, size_t size)
		{
			return ethernet_.read(cepid_, buff, size);
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  書き込み
			@param[in]	buff	書き込み元
			@param[in]	size	サイズ
			@return 書き込みサイズ（負の場合エラー）
		*/
		//-----------------------------------------------------------------//
		int32_t write(const void* buffer, uint32_t size)
		{
			return ethernet_.write(cepid_, buffer, size);
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  有効なデータがあるか
			@return 有効なデータ数
		*/
		//-----------------------------------------------------------------//
		int available()
		{
			return ethernet_.available(cepid_);
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  停止
		*/
		//-----------------------------------------------------------------//
        void stop()
		{
			if(!connected()) {
				tcp_sht_cep(cepid_, TMO_FEVR);
			}
			tcp_cls_cep(cepid_, TMO_FEVR);
			ethernet::CEP& cep = ethernet_.at_cep(cepid_);
			end();
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  終了
		*/
		//-----------------------------------------------------------------//
		void end()
		{
			ethernet_.end_connection(cepid_);
			cepid_ = 0;
		}
	};
}

<commit_msg>fix client stop blockking<commit_after>#pragma once
//=====================================================================//
/*!	@file
	@brief	ethernet_client class
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2017 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include "ethernet.hpp"

#include "common/delay.hpp"

namespace net {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  ethernet_client class
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	class ethernet_client {

		ethernet&	ethernet_;

		uint32_t	cepid_;
		uint16_t	port_;

		uint16_t	close_count_;

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクター
			@param[in]	e	インサーネットへの参照
			@param[in]	port	ポート番号
		*/
		//-----------------------------------------------------------------//
		ethernet_client(ethernet& e, uint16_t port) : ethernet_(e), cepid_(0), port_(port),
			close_count_(0) { }

		//-----------------------------------------------------------------//
		/*!
			@brief  デストラクター
		*/
		//-----------------------------------------------------------------//
		~ethernet_client() {
			stop();
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  ethernet を参照
			@return ethernet
		*/
		//-----------------------------------------------------------------//
		ethernet& at_ethernet() { return ethernet_; }

		//-----------------------------------------------------------------//
		/*!
			@brief  ethernet を参照
			@return ethernet
		*/
		//-----------------------------------------------------------------//
		const ethernet& get_ethernet() const { return ethernet_; }

		//-----------------------------------------------------------------//
		/*!
			@brief  ポート番号を取得
			@return ポート番号
		*/
		//-----------------------------------------------------------------//
		uint16_t get_port() const { return port_; }

		//-----------------------------------------------------------------//
		/*!
			@brief  CEP ID を取得
			@return CEP ID
		*/
		//-----------------------------------------------------------------//
		uint32_t get_cepid() const { return cepid_; }

		//-----------------------------------------------------------------//
		/*!
			@brief  接続先を取得
			@return 接続先
		*/
		//-----------------------------------------------------------------//
		const ip_address& get_from_ip() const {
			const ethernet::CEP& cep = ethernet_.get_cep(cepid_);
			uint32_t ipw = cep.src_addr.ipaddr;
			static ip_address ip((ipw >> 24) & 255, (ipw >> 16) & 255, (ipw >> 8) & 255, ipw & 255);
			return ip;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  コネクション
			@param[in]	ip		接続先の IP アドレス
			@param[in]	port	接続ポート
			@param[in]	timeout	タイムアウト、単位１０ミリ秒（標準で１０秒）
			@return 接続できた場合「true」
		*/
		//-----------------------------------------------------------------//
		bool connect(const ip_address& ip, uint16_t port, int32_t timeout = 1000)
		{
			if(cepid_ == 0) {
				cepid_ = ethernet_.create(port_);
				if(cepid_ == 0) return false;
				close_count_ = tcp_get_close_count(cepid_);
			}

			auto& cep = ethernet_.at_cep(cepid_);
			cep.server = false;

			if(connected()) {
				return true;
			}

			debug_format("TCP Client Request Connect: %d\n") % cepid_;

			static T_IPV4EP adr;
			adr.ipaddr =  (static_cast<uint32_t>(ip[0]) << 24)
						| (static_cast<uint32_t>(ip[1]) << 16)
						| (static_cast<uint32_t>(ip[2]) << 8)
						| (static_cast<uint32_t>(ip[3]));
			adr.portno = port;
			int ercd = tcp_con_cep(cepid_, NADR, &adr, timeout);
			bool ret = true;
			if(ercd == E_OK) {
				debug_format("TCP Client connect OK: %d\n") % cepid_;
			} else if(ercd == E_QOVR) {
				debug_format("TCP Client E_QOVR: %d\n") % cepid_;
				ret = false;
			} else {
				debug_format("TCP Client connect state(%d): %d\n") % ercd % cepid_;
			}
			tcp_clear_rst(cepid_);
			return ret;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  再接続要求
			@return 正常なら「true」
		*/
		//-----------------------------------------------------------------//
		bool re_connect(const ip_address& ip, uint16_t port)
		{
			if(cepid_ == 0) {  // ディスクリプタが無効
				return false;
			}

			static T_IPV4EP adr;
			adr.ipaddr =  (static_cast<uint32_t>(ip[0]) << 24)
						| (static_cast<uint32_t>(ip[1]) << 16)
						| (static_cast<uint32_t>(ip[2]) << 8)
						| (static_cast<uint32_t>(ip[3]));
			adr.portno = port;

			if(tcp_re_con_cep(cepid_, &adr) < 0) {
				return false;
			} else {
				return true;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  接続確認
			@return 接続中なら「true」
		*/
		//-----------------------------------------------------------------//
		bool connected()
		{
			return ethernet_.connected(cepid_);
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  読み込み
			@param[out]	buff	読み込み先
			@param[in]	size	読み込みサイズ
			@return 読み込みサイズ（負の場合エラー）
		*/
		//-----------------------------------------------------------------//
		int read(void* buff, size_t size)
		{
			return ethernet_.read(cepid_, buff, size);
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  書き込み
			@param[in]	buff	書き込み元
			@param[in]	size	サイズ
			@return 書き込みサイズ（負の場合エラー）
		*/
		//-----------------------------------------------------------------//
		int32_t write(const void* buffer, uint32_t size)
		{
			return ethernet_.write(cepid_, buffer, size);
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  有効なデータがあるか
			@return 有効なデータ数
		*/
		//-----------------------------------------------------------------//
		int available()
		{
			return ethernet_.available(cepid_);
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  停止
		*/
		//-----------------------------------------------------------------//
        void stop()
		{
			if(!connected()) {
///				tcp_sht_cep(cepid_, TMO_FEVR);
				tcp_sht_cep(cepid_, TMO_NBLK);
			}
///			tcp_cls_cep(cepid_, TMO_FEVR);
			tcp_cls_cep(cepid_, TMO_NBLK);
			ethernet::CEP& cep = ethernet_.at_cep(cepid_);
			end();
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  終了
		*/
		//-----------------------------------------------------------------//
		void end()
		{
			ethernet_.end_connection(cepid_);
			cepid_ = 0;
		}
	};
}

<|endoftext|>


<commit_before>#include <iostream>
#include "BenchTimer.h"
#include <Eigen/Dense>
#include <map>
#include <string>
using namespace Eigen;

std::map<std::string,Array<float,1,4> > results;

template<typename Scalar,int Size>
void bench(int id, int size = Size)
{
  typedef Matrix<Scalar,Size,Size> Mat;
  Mat A(size,size);
  A.setRandom();
  A = A*A.adjoint();
  BenchTimer t_llt, t_ldlt, t_lu, t_fplu, t_qr, t_cpqr, t_fpqr, t_jsvd;

  int tries = 3;
  int rep = 1000/size;
  if(rep==0) rep = 1;
  rep = rep*rep;

  LLT<Mat> llt(A);
  LDLT<Mat> ldlt(A);
  PartialPivLU<Mat> lu(A);
  FullPivLU<Mat> fplu(A);
  HouseholderQR<Mat> qr(A);
  ColPivHouseholderQR<Mat> cpqr(A);
  FullPivHouseholderQR<Mat> fpqr(A);
  JacobiSVD<Mat> jsvd(A.rows(),A.cols());

  BENCH(t_llt, tries, rep, llt.compute(A));
  BENCH(t_ldlt, tries, rep, ldlt.compute(A));
  BENCH(t_lu, tries, rep, lu.compute(A));
  BENCH(t_fplu, tries, rep, fplu.compute(A));
  BENCH(t_qr, tries, rep, qr.compute(A));
  BENCH(t_cpqr, tries, rep, cpqr.compute(A));
  BENCH(t_fpqr, tries, rep, fpqr.compute(A));
  if(size<500) // JacobiSVD is really too slow for too large matrices
    BENCH(t_jsvd, tries, rep, jsvd.compute(A,ComputeFullU|ComputeFullV));

  results["LLT"][id] = t_llt.best();
  results["LDLT"][id] = t_ldlt.best();
  results["PartialPivLU"][id] = t_lu.best();
  results["FullPivLU"][id] = t_fplu.best();
  results["HouseholderQR"][id] = t_qr.best();
  results["ColPivHouseholderQR"][id] = t_cpqr.best();
  results["FullPivHouseholderQR"][id] = t_fpqr.best();
  results["JacobiSVD"][id] = size<500 ? t_jsvd.best() : 0;
}

int main()
{
  const int small = 8;
  const int medium = 100;
  const int large = 1000;
  const int xl = 4000;

  bench<float,small>(0);
  bench<float,Dynamic>(1,medium);
  bench<float,Dynamic>(2,large);
  bench<float,Dynamic>(3,xl);

  IOFormat fmt(3, 0, " \t", "\n", "", "");

  std::cout << "solver/size               " << small << "\t" << medium << "\t" << large << "\t" << xl << "\n";
  std::cout << "LLT                 (ms)  " << (results["LLT"]/1000.).format(fmt) << "\n";
  std::cout << "LDLT                 (%)  " << (results["LDLT"]/results["LLT"]).format(fmt) << "\n";
  std::cout << "PartialPivLU         (%)  " << (results["PartialPivLU"]/results["LLT"]).format(fmt) << "\n";
  std::cout << "FullPivLU            (%)  " << (results["FullPivLU"]/results["LLT"]).format(fmt) << "\n";
  std::cout << "HouseholderQR        (%)  " << (results["HouseholderQR"]/results["LLT"]).format(fmt) << "\n";
  std::cout << "ColPivHouseholderQR  (%)  " << (results["ColPivHouseholderQR"]/results["LLT"]).format(fmt) << "\n";
  std::cout << "FullPivHouseholderQR (%)  " << (results["FullPivHouseholderQR"]/results["LLT"]).format(fmt) << "\n";
  std::cout << "JacobiSVD            (%)  " << (results["JacobiSVD"]/results["LLT"]).format(fmt) << "\n";
}
<commit_msg>Add COD and BDCSVD in list of benched solvers.<commit_after>#include <iostream>
#include "BenchTimer.h"
#include <Eigen/Dense>
#include <map>
#include <string>
using namespace Eigen;

std::map<std::string,Array<float,1,4> > results;

template<typename Scalar,int Size>
void bench(int id, int size = Size)
{
  typedef Matrix<Scalar,Size,Size> Mat;
  Mat A(size,size);
  A.setRandom();
  A = A*A.adjoint();
  BenchTimer t_llt, t_ldlt, t_lu, t_fplu, t_qr, t_cpqr, t_cod, t_fpqr, t_jsvd, t_bdcsvd;

  int tries = 3;
  int rep = 1000/size;
  if(rep==0) rep = 1;
//   rep = rep*rep;

  LLT<Mat> llt(A);
  LDLT<Mat> ldlt(A);
  PartialPivLU<Mat> lu(A);
  FullPivLU<Mat> fplu(A);
  HouseholderQR<Mat> qr(A);
  ColPivHouseholderQR<Mat> cpqr(A);
  CompleteOrthogonalDecomposition<Mat> cod(A);
  FullPivHouseholderQR<Mat> fpqr(A);
  JacobiSVD<Mat> jsvd(A.rows(),A.cols());
  BDCSVD<Mat> bdcsvd(A.rows(),A.cols());

  BENCH(t_llt, tries, rep, llt.compute(A));
  BENCH(t_ldlt, tries, rep, ldlt.compute(A));
  BENCH(t_lu, tries, rep, lu.compute(A));
  BENCH(t_fplu, tries, rep, fplu.compute(A));
  BENCH(t_qr, tries, rep, qr.compute(A));
  BENCH(t_cpqr, tries, rep, cpqr.compute(A));
  BENCH(t_cod, tries, rep, cod.compute(A));
  BENCH(t_fpqr, tries, rep, fpqr.compute(A));
  if(size<500) // JacobiSVD is really too slow for too large matrices
    BENCH(t_jsvd, tries, rep, jsvd.compute(A,ComputeFullU|ComputeFullV));
  BENCH(t_bdcsvd, tries, rep, bdcsvd.compute(A,ComputeFullU|ComputeFullV));

  results["LLT"][id] = t_llt.best();
  results["LDLT"][id] = t_ldlt.best();
  results["PartialPivLU"][id] = t_lu.best();
  results["FullPivLU"][id] = t_fplu.best();
  results["HouseholderQR"][id] = t_qr.best();
  results["ColPivHouseholderQR"][id] = t_cpqr.best();
  results["CompleteOrthogonalDecomposition"][id] = t_cod.best();
  results["FullPivHouseholderQR"][id] = t_fpqr.best();
  results["JacobiSVD"][id] = size<500 ? t_jsvd.best() : 0;
  results["BDCSVD"][id] = t_bdcsvd.best();
}

int main()
{
  const int small = 8;
  const int medium = 100;
  const int large = 1000;
  const int xl = 4000;

  bench<float,small>(0);
  bench<float,Dynamic>(1,medium);
  bench<float,Dynamic>(2,large);
  bench<float,Dynamic>(3,xl);

  IOFormat fmt(3, 0, " \t", "\n", "", "");

  std::cout << "solver/size                           " << small << "\t" << medium << "\t" << large << "\t" << xl << "\n";
  std::cout << "LLT                             (ms)  " << (results["LLT"]/1000.).format(fmt) << "\n";
  std::cout << "LDLT                             (%)  " << (results["LDLT"]/results["LLT"]).format(fmt) << "\n";
  std::cout << "PartialPivLU                     (%)  " << (results["PartialPivLU"]/results["LLT"]).format(fmt) << "\n";
  std::cout << "FullPivLU                        (%)  " << (results["FullPivLU"]/results["LLT"]).format(fmt) << "\n";
  std::cout << "HouseholderQR                    (%)  " << (results["HouseholderQR"]/results["LLT"]).format(fmt) << "\n";
  std::cout << "ColPivHouseholderQR              (%)  " << (results["ColPivHouseholderQR"]/results["LLT"]).format(fmt) << "\n";
  std::cout << "CompleteOrthogonalDecomposition  (%)  " << (results["CompleteOrthogonalDecomposition"]/results["LLT"]).format(fmt) << "\n";
  std::cout << "FullPivHouseholderQR             (%)  " << (results["FullPivHouseholderQR"]/results["LLT"]).format(fmt) << "\n";
  std::cout << "JacobiSVD                        (%)  " << (results["JacobiSVD"]/results["LLT"]).format(fmt) << "\n";
  std::cout << "BDCSVD                           (%)  " << (results["BDCSVD"]/results["LLT"]).format(fmt) << "\n";
}
<|endoftext|>


<commit_before>#include <string.h>
#include <linux/input-event-codes.h>

extern "C"
{
#include <wlr/backend/session.h>
#include <wlr/backend/multi.h>
}

#include "keyboard.hpp"
#include "core.hpp"
#include "input-manager.hpp"

void handle_keyboard_destroy_cb(wl_listener *listener, void*)
{
    wf_keyboard::listeners *lss = wl_container_of(listener, lss, destroy);
    core->input->handle_input_destroyed(lss->keyboard->device);
}

static void handle_keyboard_key_cb(wl_listener* listener, void *data)
{
    auto ev = static_cast<wlr_event_keyboard_key*> (data);
    wf_keyboard::listeners *lss = wl_container_of(listener, lss, key);

    auto seat = core->get_current_seat();
    wlr_seat_set_keyboard(seat, lss->keyboard->device);

    if (!core->input->handle_keyboard_key(ev->keycode, ev->state))
    {
        wlr_seat_keyboard_notify_key(core->input->seat, ev->time_msec,
                                     ev->keycode, ev->state);
    }

    wlr_idle_notify_activity(core->protocols.idle, seat);
}

static void handle_keyboard_mod_cb(wl_listener* listener, void* data)
{
    auto kbd = static_cast<wlr_keyboard*> (data);
    wf_keyboard::listeners *lss = wl_container_of(listener, lss, modifier);

    auto seat = core->get_current_seat();
    wlr_seat_set_keyboard(seat, lss->keyboard->device);
    wlr_seat_keyboard_send_modifiers(core->input->seat, &kbd->modifiers);

    wlr_idle_notify_activity(core->protocols.idle, seat);
}

wf_keyboard::wf_keyboard(wlr_input_device *dev, wayfire_config *config)
    : handle(dev->keyboard), device(dev)
{
    auto section = config->get_section("input");

    model   = section->get_option("xkb_model", "");
    variant = section->get_option("xkb_variant", "");
    layout  = section->get_option("xkb_layout", "");
    options = section->get_option("xkb_option", "");
    rules   = section->get_option("xkb_rule", "");

    repeat_rate  = section->get_option("kb_repeat_rate", "40");
    repeat_delay = section->get_option("kb_repeat_delay", "400");

    keyboard_options_updated = [=] () {
        reload_input_options();
    };

    model->add_updated_handler(&keyboard_options_updated);
    rules->add_updated_handler(&keyboard_options_updated);
    layout->add_updated_handler(&keyboard_options_updated);
    variant->add_updated_handler(&keyboard_options_updated);
    options->add_updated_handler(&keyboard_options_updated);
    repeat_rate->add_updated_handler(&keyboard_options_updated);
    repeat_delay->add_updated_handler(&keyboard_options_updated);

    lss.keyboard = this;
    lss.key.notify      = handle_keyboard_key_cb;
    lss.modifier.notify = handle_keyboard_mod_cb;
    lss.destroy.notify  = handle_keyboard_destroy_cb;

    wl_signal_add(&dev->keyboard->events.key,       &lss.key);
    wl_signal_add(&dev->keyboard->events.modifiers, &lss.modifier);
    wl_signal_add(&dev->events.destroy,             &lss.destroy);

    reload_input_options();
    wlr_seat_set_keyboard(core->get_current_seat(), dev);
}

void wf_keyboard::reload_input_options()
{
    auto ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);

    auto rules = this->rules->as_string();
    auto model = this->model->as_string();
    auto layout = this->layout->as_string();
    auto variant = this->variant->as_string();
    auto options = this->options->as_string();

    xkb_rule_names names;
    names.rules   = rules.c_str();
    names.model   = model.c_str();
    names.layout  = layout.c_str();
    names.variant = variant.c_str();
    names.options = options.c_str();

    auto keymap = xkb_map_new_from_names(ctx, &names, XKB_KEYMAP_COMPILE_NO_FLAGS);

    wlr_keyboard_set_keymap(handle, keymap);

    xkb_keymap_unref(keymap);
    xkb_context_unref(ctx);

    wlr_keyboard_set_repeat_info(handle, repeat_rate->as_int(),
                                 repeat_delay->as_int());
}

wf_keyboard::~wf_keyboard()
{
    model->rem_updated_handler(&keyboard_options_updated);
    rules->rem_updated_handler(&keyboard_options_updated);
    layout->rem_updated_handler(&keyboard_options_updated);
    variant->rem_updated_handler(&keyboard_options_updated);
    options->rem_updated_handler(&keyboard_options_updated);
    repeat_rate->rem_updated_handler(&keyboard_options_updated);
    repeat_delay->rem_updated_handler(&keyboard_options_updated);
}

/* input manager things */
static bool check_vt_switch(wlr_session *session, uint32_t key, uint32_t mods)
{
    if (!session)
        return false;
    if (mods ^ (WLR_MODIFIER_ALT | WLR_MODIFIER_CTRL))
        return false;

    if (key < KEY_F1 || key > KEY_F10)
        return false;

    int target_vt = key - KEY_F1 + 1;
    wlr_session_change_vt(session, target_vt);
    return true;
}

std::vector<std::function<void()>> input_manager::match_keys(uint32_t mod_state, uint32_t key)
{
    std::vector<std::function<void()>> callbacks;

    for (auto& binding : bindings[WF_BINDING_KEY])
    {
        if (binding->value->as_cached_key().matches({mod_state, key}) &&
            binding->output == core->get_active_output())
        {
            /* make sure we don't capture a reference to binding,
             * because it might get destroyed later */
            auto callback = binding->call.key;
            callbacks.push_back([key, callback] () {
                (*callback) (key);
            });
        }
    }

    for (auto& binding : bindings[WF_BINDING_ACTIVATOR])
    {
        if (binding->value->matches_key({mod_state, key}) &&
            binding->output == core->get_active_output())
        {
            callbacks.push_back(*binding->call.activator);
        }
    }

    return callbacks;
}

static uint32_t mod_from_key(uint32_t key)
{
    if (key == KEY_LEFTALT || key == KEY_RIGHTALT)
        return WLR_MODIFIER_ALT;
    if (key == KEY_LEFTCTRL || key == KEY_RIGHTCTRL)
        return WLR_MODIFIER_CTRL;
    if (key == KEY_LEFTSHIFT || key == KEY_RIGHTSHIFT)
        return WLR_MODIFIER_SHIFT;
    if (key == KEY_LEFTMETA || key == KEY_RIGHTMETA)
        return WLR_MODIFIER_LOGO;

    return 0;
}

bool input_manager::handle_keyboard_key(uint32_t key, uint32_t state)
{
    if (active_grab && active_grab->callbacks.keyboard.key)
        active_grab->callbacks.keyboard.key(key, state);

    auto mod = mod_from_key(key);
    if (mod)
        handle_keyboard_mod(mod, state);

    std::vector<std::function<void()>> callbacks;
    auto kbd = wlr_seat_get_keyboard(seat);

    if (state == WLR_KEY_PRESSED)
    {
        if (check_vt_switch(wlr_multi_get_session(core->backend), key, get_modifiers()))
            return true;

        /* as long as we have pressed only modifiers, we should check for modifier bindings on release */
        if (mod)
        {
            bool modifiers_only = !count_other_inputs;
            for (size_t i = 0; i < kbd->num_keycodes; i++)
                if (!mod_from_key(kbd->keycodes[i]))
                    modifiers_only = false;

            if (modifiers_only)
                in_mod_binding = true;
            else
                in_mod_binding = false;
        } else
        {
            in_mod_binding = false;
        }

        callbacks = match_keys(get_modifiers(), key);
    } else
    {
        if (in_mod_binding)
            callbacks = match_keys(get_modifiers() | mod, 0);

        in_mod_binding = false;
    }

    for (auto call : callbacks)
        call();

    return active_grab || !callbacks.empty();
}

void input_manager::handle_keyboard_mod(uint32_t modifier, uint32_t state)
{
    if (active_grab && active_grab->callbacks.keyboard.mod)
        active_grab->callbacks.keyboard.mod(modifier, state);
}

<commit_msg>s/wlr_multi_get_session/wlr_backend_get_session/<commit_after>#include <string.h>
#include <linux/input-event-codes.h>

extern "C"
{
#include <wlr/backend/session.h>
#include <wlr/backend/multi.h>
}

#include "keyboard.hpp"
#include "core.hpp"
#include "input-manager.hpp"

void handle_keyboard_destroy_cb(wl_listener *listener, void*)
{
    wf_keyboard::listeners *lss = wl_container_of(listener, lss, destroy);
    core->input->handle_input_destroyed(lss->keyboard->device);
}

static void handle_keyboard_key_cb(wl_listener* listener, void *data)
{
    auto ev = static_cast<wlr_event_keyboard_key*> (data);
    wf_keyboard::listeners *lss = wl_container_of(listener, lss, key);

    auto seat = core->get_current_seat();
    wlr_seat_set_keyboard(seat, lss->keyboard->device);

    if (!core->input->handle_keyboard_key(ev->keycode, ev->state))
    {
        wlr_seat_keyboard_notify_key(core->input->seat, ev->time_msec,
                                     ev->keycode, ev->state);
    }

    wlr_idle_notify_activity(core->protocols.idle, seat);
}

static void handle_keyboard_mod_cb(wl_listener* listener, void* data)
{
    auto kbd = static_cast<wlr_keyboard*> (data);
    wf_keyboard::listeners *lss = wl_container_of(listener, lss, modifier);

    auto seat = core->get_current_seat();
    wlr_seat_set_keyboard(seat, lss->keyboard->device);
    wlr_seat_keyboard_send_modifiers(core->input->seat, &kbd->modifiers);

    wlr_idle_notify_activity(core->protocols.idle, seat);
}

wf_keyboard::wf_keyboard(wlr_input_device *dev, wayfire_config *config)
    : handle(dev->keyboard), device(dev)
{
    auto section = config->get_section("input");

    model   = section->get_option("xkb_model", "");
    variant = section->get_option("xkb_variant", "");
    layout  = section->get_option("xkb_layout", "");
    options = section->get_option("xkb_option", "");
    rules   = section->get_option("xkb_rule", "");

    repeat_rate  = section->get_option("kb_repeat_rate", "40");
    repeat_delay = section->get_option("kb_repeat_delay", "400");

    keyboard_options_updated = [=] () {
        reload_input_options();
    };

    model->add_updated_handler(&keyboard_options_updated);
    rules->add_updated_handler(&keyboard_options_updated);
    layout->add_updated_handler(&keyboard_options_updated);
    variant->add_updated_handler(&keyboard_options_updated);
    options->add_updated_handler(&keyboard_options_updated);
    repeat_rate->add_updated_handler(&keyboard_options_updated);
    repeat_delay->add_updated_handler(&keyboard_options_updated);

    lss.keyboard = this;
    lss.key.notify      = handle_keyboard_key_cb;
    lss.modifier.notify = handle_keyboard_mod_cb;
    lss.destroy.notify  = handle_keyboard_destroy_cb;

    wl_signal_add(&dev->keyboard->events.key,       &lss.key);
    wl_signal_add(&dev->keyboard->events.modifiers, &lss.modifier);
    wl_signal_add(&dev->events.destroy,             &lss.destroy);

    reload_input_options();
    wlr_seat_set_keyboard(core->get_current_seat(), dev);
}

void wf_keyboard::reload_input_options()
{
    auto ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);

    auto rules = this->rules->as_string();
    auto model = this->model->as_string();
    auto layout = this->layout->as_string();
    auto variant = this->variant->as_string();
    auto options = this->options->as_string();

    xkb_rule_names names;
    names.rules   = rules.c_str();
    names.model   = model.c_str();
    names.layout  = layout.c_str();
    names.variant = variant.c_str();
    names.options = options.c_str();

    auto keymap = xkb_map_new_from_names(ctx, &names, XKB_KEYMAP_COMPILE_NO_FLAGS);

    wlr_keyboard_set_keymap(handle, keymap);

    xkb_keymap_unref(keymap);
    xkb_context_unref(ctx);

    wlr_keyboard_set_repeat_info(handle, repeat_rate->as_int(),
                                 repeat_delay->as_int());
}

wf_keyboard::~wf_keyboard()
{
    model->rem_updated_handler(&keyboard_options_updated);
    rules->rem_updated_handler(&keyboard_options_updated);
    layout->rem_updated_handler(&keyboard_options_updated);
    variant->rem_updated_handler(&keyboard_options_updated);
    options->rem_updated_handler(&keyboard_options_updated);
    repeat_rate->rem_updated_handler(&keyboard_options_updated);
    repeat_delay->rem_updated_handler(&keyboard_options_updated);
}

/* input manager things */
static bool check_vt_switch(wlr_session *session, uint32_t key, uint32_t mods)
{
    if (!session)
        return false;
    if (mods ^ (WLR_MODIFIER_ALT | WLR_MODIFIER_CTRL))
        return false;

    if (key < KEY_F1 || key > KEY_F10)
        return false;

    int target_vt = key - KEY_F1 + 1;
    wlr_session_change_vt(session, target_vt);
    return true;
}

std::vector<std::function<void()>> input_manager::match_keys(uint32_t mod_state, uint32_t key)
{
    std::vector<std::function<void()>> callbacks;

    for (auto& binding : bindings[WF_BINDING_KEY])
    {
        if (binding->value->as_cached_key().matches({mod_state, key}) &&
            binding->output == core->get_active_output())
        {
            /* make sure we don't capture a reference to binding,
             * because it might get destroyed later */
            auto callback = binding->call.key;
            callbacks.push_back([key, callback] () {
                (*callback) (key);
            });
        }
    }

    for (auto& binding : bindings[WF_BINDING_ACTIVATOR])
    {
        if (binding->value->matches_key({mod_state, key}) &&
            binding->output == core->get_active_output())
        {
            callbacks.push_back(*binding->call.activator);
        }
    }

    return callbacks;
}

static uint32_t mod_from_key(uint32_t key)
{
    if (key == KEY_LEFTALT || key == KEY_RIGHTALT)
        return WLR_MODIFIER_ALT;
    if (key == KEY_LEFTCTRL || key == KEY_RIGHTCTRL)
        return WLR_MODIFIER_CTRL;
    if (key == KEY_LEFTSHIFT || key == KEY_RIGHTSHIFT)
        return WLR_MODIFIER_SHIFT;
    if (key == KEY_LEFTMETA || key == KEY_RIGHTMETA)
        return WLR_MODIFIER_LOGO;

    return 0;
}

bool input_manager::handle_keyboard_key(uint32_t key, uint32_t state)
{
    if (active_grab && active_grab->callbacks.keyboard.key)
        active_grab->callbacks.keyboard.key(key, state);

    auto mod = mod_from_key(key);
    if (mod)
        handle_keyboard_mod(mod, state);

    std::vector<std::function<void()>> callbacks;
    auto kbd = wlr_seat_get_keyboard(seat);

    if (state == WLR_KEY_PRESSED)
    {
        if (check_vt_switch(wlr_backend_get_session(core->backend), key, get_modifiers()))
            return true;

        /* as long as we have pressed only modifiers, we should check for modifier bindings on release */
        if (mod)
        {
            bool modifiers_only = !count_other_inputs;
            for (size_t i = 0; i < kbd->num_keycodes; i++)
                if (!mod_from_key(kbd->keycodes[i]))
                    modifiers_only = false;

            if (modifiers_only)
                in_mod_binding = true;
            else
                in_mod_binding = false;
        } else
        {
            in_mod_binding = false;
        }

        callbacks = match_keys(get_modifiers(), key);
    } else
    {
        if (in_mod_binding)
            callbacks = match_keys(get_modifiers() | mod, 0);

        in_mod_binding = false;
    }

    for (auto call : callbacks)
        call();

    return active_grab || !callbacks.empty();
}

void input_manager::handle_keyboard_mod(uint32_t modifier, uint32_t state)
{
    if (active_grab && active_grab->callbacks.keyboard.mod)
        active_grab->callbacks.keyboard.mod(modifier, state);
}

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2018, Arm Limited and affiliates.
 * SPDX-License-Identifier: Apache-2.0
 *
 * 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.
 */
#include "UBLOX_AT_CellularContext.h"
#include "UBLOX_AT_CellularStack.h"
#include "APN_db.h"

namespace mbed {

UBLOX_AT_CellularContext::UBLOX_AT_CellularContext(ATHandler &at, CellularDevice *device, const char *apn) :
    AT_CellularContext(at, device, apn)
{
    // The authentication to use
    _auth = NSAPI_SECURITY_UNKNOWN;
}

UBLOX_AT_CellularContext::~UBLOX_AT_CellularContext()
{
}

NetworkStack *UBLOX_AT_CellularContext::get_stack()
{
    if (!_stack) {
        _stack = new UBLOX_AT_CellularStack(_at, _cid, _ip_stack_type);
    }
    return _stack;
}

bool UBLOX_AT_CellularContext::stack_type_supported(nsapi_ip_stack_t stack_type)
{
    return stack_type == IPV4_STACK ? true : false;
}

void UBLOX_AT_CellularContext::do_connect()
{
    _at.lock();
    _cb_data.error = NSAPI_ERROR_NO_CONNECTION;

    // Attempt to establish a connection
#ifdef TARGET_UBLOX_C030_R410M
    _cb_data.error = NSAPI_ERROR_OK;
#else
    _cb_data.error = open_data_channel();
#endif
    if (_cb_data.error != NSAPI_ERROR_OK) {
        // If new PSD context was created and failed to activate, delete it
        if (_new_context_set) {
            disconnect_modem_stack();
        }
        _connect_status = NSAPI_STATUS_DISCONNECTED;
    } else {
        _connect_status = NSAPI_STATUS_GLOBAL_UP;
    }
    _at.unlock();

    if (_status_cb) {
        call_network_cb(_connect_status);
    }
}

nsapi_error_t UBLOX_AT_CellularContext::open_data_channel()
{
    bool success = false;
    int active = 0;
    char *config = NULL;
    nsapi_error_t err = NSAPI_ERROR_NO_CONNECTION;
    char imsi[MAX_IMSI_LENGTH + 1];

    // do check for stack to validate that we have support for stack
    _stack = get_stack();
    if (!_stack) {
        return err;
    }

    _at.cmd_start("AT+UPSND=" PROFILE ",8");
    _at.cmd_stop();
    _at.resp_start("+UPSND:");
    _at.read_int();
    _at.read_int();
    active = _at.read_int();
    _at.resp_stop();

    if (active == 0) {
        // If the caller hasn't entered an APN, try to find it
        if (_apn == NULL) {
            err = get_imsi(imsi);
            if (err == NSAPI_ERROR_OK) {
                config = (char *)apnconfig(imsi);
            }
        }

        // Attempt to connect
        do {
            get_next_credentials(&config);
            if (_uname && _pwd) {
                _auth = (*_uname && *_pwd) ? _auth : NSAPI_SECURITY_NONE;
            } else {
                _auth = NSAPI_SECURITY_NONE;
            }
            success = activate_profile(_apn, _uname, _pwd);
        } while (!success && config && *config);
    } else {
        // If the profile is already active, we're good
        success = true;
    }

    err = (_at.get_last_error() == NSAPI_ERROR_OK) ? NSAPI_ERROR_OK : NSAPI_ERROR_NO_CONNECTION;

    return err;
}

bool UBLOX_AT_CellularContext::activate_profile(const char *apn,
                                                const char *username,
                                                const char *password)
{
    bool activated = false;
    bool success = false;

    // Set up the APN
    if (apn) {
        success = false;
        _at.cmd_start("AT+UPSD=0,1,");
        _at.write_string(apn);
        _at.cmd_stop();
        _at.resp_start();
        _at.resp_stop();

        if (_at.get_last_error() == NSAPI_ERROR_OK) {
            success = true;
        }
    }
    // Set up the UserName
    if (success && username) {
        success = false;
        _at.cmd_start("AT+UPSD=" PROFILE ",2,");
        _at.write_string(username);
        _at.cmd_stop();
        _at.resp_start();
        _at.resp_stop();

        if (_at.get_last_error() == NSAPI_ERROR_OK) {
            success = true;
        }
    }
    // Set up the Password
    if (success && password) {
        success = false;
        _at.cmd_start("AT+UPSD=" PROFILE ",3,");
        _at.write_string(password);
        _at.cmd_stop();
        _at.resp_start();
        _at.resp_stop();

        if (_at.get_last_error() == NSAPI_ERROR_OK) {
            success = true;
        }
    }

    if (success) {
        _at.cmd_start("AT+UPSD=" PROFILE ",7,\"0.0.0.0\"");
        _at.cmd_stop();
        _at.resp_start();
        _at.resp_stop();

        // Set up the authentication protocol
        // 0 = none
        // 1 = PAP (Password Authentication Protocol)
        // 2 = CHAP (Challenge Handshake Authentication Protocol)
        for (int protocol = nsapi_security_to_modem_security(NSAPI_SECURITY_NONE);
                success && (protocol <= nsapi_security_to_modem_security(NSAPI_SECURITY_CHAP)); protocol++) {
            if ((_auth == NSAPI_SECURITY_UNKNOWN) || (nsapi_security_to_modem_security(_auth) == protocol)) {
                _at.cmd_start("AT+UPSD=0,6,");
                _at.write_int(protocol);
                _at.cmd_stop();
                _at.resp_start();
                _at.resp_stop();

                if (_at.get_last_error() == NSAPI_ERROR_OK) {
                    // Activate, wait upto 30 seconds for the connection to be made
                    _at.set_at_timeout(30000);
                    _at.cmd_start("AT+UPSDA=0,3");
                    _at.cmd_stop();
                    _at.resp_start();
                    _at.resp_stop();
                    _at.restore_at_timeout();

                    if (_at.get_last_error() == NSAPI_ERROR_OK) {
                        activated = true;
                    }
                }
            }
        }
    }

    return activated;
}

// Convert nsapi_security_t to the modem security numbers
int UBLOX_AT_CellularContext::nsapi_security_to_modem_security(nsapi_security_t nsapi_security)
{
    int modem_security = 3;

    switch (nsapi_security) {
        case NSAPI_SECURITY_NONE:
            modem_security = 0;
            break;
        case NSAPI_SECURITY_PAP:
            modem_security = 1;
            break;
        case NSAPI_SECURITY_CHAP:
            modem_security = 2;
            break;
        case NSAPI_SECURITY_UNKNOWN:
            modem_security = 3;
            break;
        default:
            modem_security = 3;
            break;
    }

    return modem_security;
}

// Disconnect the on board IP stack of the modem.
bool UBLOX_AT_CellularContext::disconnect_modem_stack()
{
    bool success = false;

    if (get_ip_address() != NULL) {
        _at.cmd_start("AT+UPSDA=" PROFILE ",4");
        _at.cmd_stop();
        _at.resp_start();
        _at.resp_stop();

        if (_at.get_last_error() == NSAPI_ERROR_OK) {
            success = true;
        }
    }

    return success;
}

nsapi_error_t UBLOX_AT_CellularContext::get_imsi(char *imsi)
{
    _at.lock();
    _at.cmd_start("AT+CIMI");
    _at.cmd_stop();
    _at.resp_start();
    int len = _at.read_string(imsi, MAX_IMSI_LENGTH);
    if (len > 0) {
        imsi[len] = '\0';
    }
    _at.resp_stop();

    return _at.unlock_return_error();
}

// Get the next set of credentials, based on IMSI.
void UBLOX_AT_CellularContext::get_next_credentials(char **config)
{
    if (*config) {
        _apn    = _APN_GET(*config);
        _uname  = _APN_GET(*config);
        _pwd    = _APN_GET(*config);
    }
}

const char *UBLOX_AT_CellularContext::get_gateway()
{
    return get_ip_address();
}

} /* namespace mbed */
<commit_msg>Call network status callback from UBLOX AT<commit_after>/*
 * Copyright (c) 2018, Arm Limited and affiliates.
 * SPDX-License-Identifier: Apache-2.0
 *
 * 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.
 */
#include "UBLOX_AT_CellularContext.h"
#include "UBLOX_AT_CellularStack.h"
#include "APN_db.h"

namespace mbed {

UBLOX_AT_CellularContext::UBLOX_AT_CellularContext(ATHandler &at, CellularDevice *device, const char *apn) :
    AT_CellularContext(at, device, apn)
{
    // The authentication to use
    _auth = NSAPI_SECURITY_UNKNOWN;
}

UBLOX_AT_CellularContext::~UBLOX_AT_CellularContext()
{
}

NetworkStack *UBLOX_AT_CellularContext::get_stack()
{
    if (!_stack) {
        _stack = new UBLOX_AT_CellularStack(_at, _cid, _ip_stack_type);
    }
    return _stack;
}

bool UBLOX_AT_CellularContext::stack_type_supported(nsapi_ip_stack_t stack_type)
{
    return stack_type == IPV4_STACK ? true : false;
}

void UBLOX_AT_CellularContext::do_connect()
{
    _at.lock();
    _cb_data.error = NSAPI_ERROR_NO_CONNECTION;

    // Attempt to establish a connection
#ifdef TARGET_UBLOX_C030_R410M
    _cb_data.error = NSAPI_ERROR_OK;
#else
    _cb_data.error = open_data_channel();
#endif
    if (_cb_data.error != NSAPI_ERROR_OK) {
        // If new PSD context was created and failed to activate, delete it
        if (_new_context_set) {
            disconnect_modem_stack();
        }
        _connect_status = NSAPI_STATUS_DISCONNECTED;
    } else {
        _connect_status = NSAPI_STATUS_GLOBAL_UP;
    }
    _at.unlock();

    if (_status_cb) {
        _status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, _connect_status);
    }
}

nsapi_error_t UBLOX_AT_CellularContext::open_data_channel()
{
    bool success = false;
    int active = 0;
    char *config = NULL;
    nsapi_error_t err = NSAPI_ERROR_NO_CONNECTION;
    char imsi[MAX_IMSI_LENGTH + 1];

    // do check for stack to validate that we have support for stack
    _stack = get_stack();
    if (!_stack) {
        return err;
    }

    _at.cmd_start("AT+UPSND=" PROFILE ",8");
    _at.cmd_stop();
    _at.resp_start("+UPSND:");
    _at.read_int();
    _at.read_int();
    active = _at.read_int();
    _at.resp_stop();

    if (active == 0) {
        // If the caller hasn't entered an APN, try to find it
        if (_apn == NULL) {
            err = get_imsi(imsi);
            if (err == NSAPI_ERROR_OK) {
                config = (char *)apnconfig(imsi);
            }
        }

        // Attempt to connect
        do {
            get_next_credentials(&config);
            if (_uname && _pwd) {
                _auth = (*_uname && *_pwd) ? _auth : NSAPI_SECURITY_NONE;
            } else {
                _auth = NSAPI_SECURITY_NONE;
            }
            success = activate_profile(_apn, _uname, _pwd);
        } while (!success && config && *config);
    } else {
        // If the profile is already active, we're good
        success = true;
    }

    err = (_at.get_last_error() == NSAPI_ERROR_OK) ? NSAPI_ERROR_OK : NSAPI_ERROR_NO_CONNECTION;

    return err;
}

bool UBLOX_AT_CellularContext::activate_profile(const char *apn,
                                                const char *username,
                                                const char *password)
{
    bool activated = false;
    bool success = false;

    // Set up the APN
    if (apn) {
        success = false;
        _at.cmd_start("AT+UPSD=0,1,");
        _at.write_string(apn);
        _at.cmd_stop();
        _at.resp_start();
        _at.resp_stop();

        if (_at.get_last_error() == NSAPI_ERROR_OK) {
            success = true;
        }
    }
    // Set up the UserName
    if (success && username) {
        success = false;
        _at.cmd_start("AT+UPSD=" PROFILE ",2,");
        _at.write_string(username);
        _at.cmd_stop();
        _at.resp_start();
        _at.resp_stop();

        if (_at.get_last_error() == NSAPI_ERROR_OK) {
            success = true;
        }
    }
    // Set up the Password
    if (success && password) {
        success = false;
        _at.cmd_start("AT+UPSD=" PROFILE ",3,");
        _at.write_string(password);
        _at.cmd_stop();
        _at.resp_start();
        _at.resp_stop();

        if (_at.get_last_error() == NSAPI_ERROR_OK) {
            success = true;
        }
    }

    if (success) {
        _at.cmd_start("AT+UPSD=" PROFILE ",7,\"0.0.0.0\"");
        _at.cmd_stop();
        _at.resp_start();
        _at.resp_stop();

        // Set up the authentication protocol
        // 0 = none
        // 1 = PAP (Password Authentication Protocol)
        // 2 = CHAP (Challenge Handshake Authentication Protocol)
        for (int protocol = nsapi_security_to_modem_security(NSAPI_SECURITY_NONE);
                success && (protocol <= nsapi_security_to_modem_security(NSAPI_SECURITY_CHAP)); protocol++) {
            if ((_auth == NSAPI_SECURITY_UNKNOWN) || (nsapi_security_to_modem_security(_auth) == protocol)) {
                _at.cmd_start("AT+UPSD=0,6,");
                _at.write_int(protocol);
                _at.cmd_stop();
                _at.resp_start();
                _at.resp_stop();

                if (_at.get_last_error() == NSAPI_ERROR_OK) {
                    // Activate, wait upto 30 seconds for the connection to be made
                    _at.set_at_timeout(30000);
                    _at.cmd_start("AT+UPSDA=0,3");
                    _at.cmd_stop();
                    _at.resp_start();
                    _at.resp_stop();
                    _at.restore_at_timeout();

                    if (_at.get_last_error() == NSAPI_ERROR_OK) {
                        activated = true;
                    }
                }
            }
        }
    }

    return activated;
}

// Convert nsapi_security_t to the modem security numbers
int UBLOX_AT_CellularContext::nsapi_security_to_modem_security(nsapi_security_t nsapi_security)
{
    int modem_security = 3;

    switch (nsapi_security) {
        case NSAPI_SECURITY_NONE:
            modem_security = 0;
            break;
        case NSAPI_SECURITY_PAP:
            modem_security = 1;
            break;
        case NSAPI_SECURITY_CHAP:
            modem_security = 2;
            break;
        case NSAPI_SECURITY_UNKNOWN:
            modem_security = 3;
            break;
        default:
            modem_security = 3;
            break;
    }

    return modem_security;
}

// Disconnect the on board IP stack of the modem.
bool UBLOX_AT_CellularContext::disconnect_modem_stack()
{
    bool success = false;

    if (get_ip_address() != NULL) {
        _at.cmd_start("AT+UPSDA=" PROFILE ",4");
        _at.cmd_stop();
        _at.resp_start();
        _at.resp_stop();

        if (_at.get_last_error() == NSAPI_ERROR_OK) {
            success = true;
        }
    }

    return success;
}

nsapi_error_t UBLOX_AT_CellularContext::get_imsi(char *imsi)
{
    _at.lock();
    _at.cmd_start("AT+CIMI");
    _at.cmd_stop();
    _at.resp_start();
    int len = _at.read_string(imsi, MAX_IMSI_LENGTH);
    if (len > 0) {
        imsi[len] = '\0';
    }
    _at.resp_stop();

    return _at.unlock_return_error();
}

// Get the next set of credentials, based on IMSI.
void UBLOX_AT_CellularContext::get_next_credentials(char **config)
{
    if (*config) {
        _apn    = _APN_GET(*config);
        _uname  = _APN_GET(*config);
        _pwd    = _APN_GET(*config);
    }
}

const char *UBLOX_AT_CellularContext::get_gateway()
{
    return get_ip_address();
}

} /* namespace mbed */
<|endoftext|>


<commit_before>/*
 * This helper library glues delegate_glue and http_response_handler
 * together.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "HttpRequest.hxx"
#include "Handler.hxx"
#include "Glue.hxx"
#include "static_headers.hxx"
#include "http_response.hxx"
#include "strmap.hxx"
#include "istream/istream.hxx"
#include "istream/istream_file.hxx"
#include "gerrno.h"
#include "pool.hxx"

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>

struct DelegateHttpRequest final : DelegateHandler {
    struct pool &pool;
    const char *const path;
    const char *const content_type;
    struct http_response_handler_ref handler;

    DelegateHttpRequest(struct pool &_pool,
                        const char *_path, const char *_content_type,
                        const struct http_response_handler &_handler, void *ctx)
        :pool(_pool),
         path(_path), content_type(_content_type),
         handler(_handler, ctx) {}

    /* virtual methods from class DelegateHandler */
    void OnDelegateSuccess(int fd) override;

    void OnDelegateError(GError *error) override {
        handler.InvokeAbort(error);
    }
};

void
DelegateHttpRequest::OnDelegateSuccess(int fd)
{
    struct stat st;
    if (fstat(fd, &st) < 0) {
        GError *error = new_error_errno();
        g_prefix_error(&error, "Failed to stat %s: ", path);
        handler.InvokeAbort(error);
        return;
    }

    if (!S_ISREG(st.st_mode)) {
        close(fd);
        handler.InvokeMessage(pool, HTTP_STATUS_NOT_FOUND,
                              "Not a regular file");
        return;
    }

    /* XXX handle if-modified-since, ... */

    struct strmap *headers = strmap_new(&pool);
    static_response_headers(&pool, headers, fd, &st, content_type);

    Istream *body = istream_file_fd_new(&pool, path,
                                        fd, FdType::FD_FILE,
                                        st.st_size);
    handler.InvokeResponse(HTTP_STATUS_OK, headers, body);
}

void
delegate_stock_request(StockMap *stock, struct pool *pool,
                       const char *helper,
                       const ChildOptions &options,
                       const char *path, const char *content_type,
                       const struct http_response_handler *handler, void *ctx,
                       struct async_operation_ref &async_ref)
{
    auto get = NewFromPool<DelegateHttpRequest>(*pool, *pool,
                                                path, content_type,
                                                *handler, ctx);

    delegate_stock_open(stock, pool,
                        helper, options, path,
                        *get, async_ref);
}
<commit_msg>delegate/HttpRequest: move code to method Open()<commit_after>/*
 * This helper library glues delegate_glue and http_response_handler
 * together.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "HttpRequest.hxx"
#include "Handler.hxx"
#include "Glue.hxx"
#include "static_headers.hxx"
#include "http_response.hxx"
#include "strmap.hxx"
#include "istream/istream.hxx"
#include "istream/istream_file.hxx"
#include "gerrno.h"
#include "pool.hxx"

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>

struct DelegateHttpRequest final : DelegateHandler {
    struct pool &pool;
    const char *const path;
    const char *const content_type;
    struct http_response_handler_ref handler;

    DelegateHttpRequest(struct pool &_pool,
                        const char *_path, const char *_content_type,
                        const struct http_response_handler &_handler, void *ctx)
        :pool(_pool),
         path(_path), content_type(_content_type),
         handler(_handler, ctx) {}

    void Open(StockMap &stock, const char *helper,
              const ChildOptions &options,
              struct async_operation_ref &async_ref) {
        delegate_stock_open(&stock, &pool,
                            helper, options, path,
                            *this, async_ref);
    }

    /* virtual methods from class DelegateHandler */
    void OnDelegateSuccess(int fd) override;

    void OnDelegateError(GError *error) override {
        handler.InvokeAbort(error);
    }
};

void
DelegateHttpRequest::OnDelegateSuccess(int fd)
{
    struct stat st;
    if (fstat(fd, &st) < 0) {
        GError *error = new_error_errno();
        g_prefix_error(&error, "Failed to stat %s: ", path);
        handler.InvokeAbort(error);
        return;
    }

    if (!S_ISREG(st.st_mode)) {
        close(fd);
        handler.InvokeMessage(pool, HTTP_STATUS_NOT_FOUND,
                              "Not a regular file");
        return;
    }

    /* XXX handle if-modified-since, ... */

    struct strmap *headers = strmap_new(&pool);
    static_response_headers(&pool, headers, fd, &st, content_type);

    Istream *body = istream_file_fd_new(&pool, path,
                                        fd, FdType::FD_FILE,
                                        st.st_size);
    handler.InvokeResponse(HTTP_STATUS_OK, headers, body);
}

void
delegate_stock_request(StockMap *stock, struct pool *pool,
                       const char *helper,
                       const ChildOptions &options,
                       const char *path, const char *content_type,
                       const struct http_response_handler *handler, void *ctx,
                       struct async_operation_ref &async_ref)
{
    auto get = NewFromPool<DelegateHttpRequest>(*pool, *pool,
                                                path, content_type,
                                                *handler, ctx);
    get->Open(*stock, helper, options, async_ref);
}
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/hwpf/fapi2/include/target_types.H $                */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2012,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
/**
 * @file target_types.H
 * @brief definitions for fapi2 target types
 */

#ifndef __FAPI2_TARGET_TYPES__
#define __FAPI2_TARGET_TYPES__
#include <stdint.h>
/// FAPI namespace
namespace fapi2
{
///
/// @enum fapi::TargetType
/// @brief Types, kinds, of targets
/// @note TYPE_NONE is used to represent empty/NULL targets in lists
/// or tables. TYPE_ALL is used to pass targets to methods which
/// can act generally on any type of target
///

/// Target Kind
enum TargetType
{
    TARGET_TYPE_NONE          = 0x00000000, ///< No type
    TARGET_TYPE_SYSTEM        = 0x00000001, ///< System type
    TARGET_TYPE_DIMM          = 0x00000002, ///< DIMM type
    TARGET_TYPE_PROC_CHIP     = 0x00000004, ///< Processor type
    TARGET_TYPE_MEMBUF_CHIP   = 0x00000008, ///< Membuf type
    TARGET_TYPE_EX            = 0x00000010, ///< EX - 2x Core, L2, L3 - can be deconfigured
    TARGET_TYPE_MBA           = 0x00000020, ///< MBA type
    TARGET_TYPE_MCS           = 0x00000040, ///< MCS type
    TARGET_TYPE_XBUS          = 0x00000080, ///< XBUS type
    TARGET_TYPE_ABUS          = 0x00000100, ///< ABUS type
    TARGET_TYPE_L4            = 0x00000200, ///< L4 type
    TARGET_TYPE_CORE          = 0x00000400, ///< Core - 4x threads(?) - can be deconfigured
    TARGET_TYPE_EQ            = 0x00000800, ///< EQ - 4x core, 2x L2, 2x L3 - can be deconfigured
    TARGET_TYPE_MCA           = 0x00001000, ///< MCA type
    TARGET_TYPE_MCBIST        = 0x00002000, ///< MCBIST type
    TARGET_TYPE_MI            = 0x00004000, ///< MI Memory Interface (Cumulus)
    TARGET_TYPE_CAPP          = 0x00008000, ///< CAPP target
    TARGET_TYPE_DMI           = 0x00010000, ///< DMI type
    TARGET_TYPE_OBUS          = 0x00020000, ///< OBUS type
    TARGET_TYPE_NV            = 0x00040000, ///< NV bus type
    TARGET_TYPE_SBE           = 0x00080000, ///< SBE type
    TARGET_TYPE_PPE           = 0x00100000, ///< PPE type
    TARGET_TYPE_PERV          = 0x00200000, ///< Pervasive type
    TARGET_TYPE_PEC           = 0x00400000, ///< PEC type
    TARGET_TYPE_PHB           = 0x00800000, ///< PHB type

    TARGET_TYPE_ALL           = 0xFFFFFFFF, ///< Any/All types

    // Compound target types
    TARGET_TYPE_CHIPS         = TARGET_TYPE_PROC_CHIP |
                                TARGET_TYPE_MEMBUF_CHIP,

    TARGET_TYPE_CHIPLETS      = TARGET_TYPE_EX     |
                                TARGET_TYPE_MBA    |
                                TARGET_TYPE_MCS    |
                                TARGET_TYPE_XBUS   |
                                TARGET_TYPE_ABUS   |
                                TARGET_TYPE_L4     |
                                TARGET_TYPE_CORE   |
                                TARGET_TYPE_EQ     |
                                TARGET_TYPE_MCA    |
                                TARGET_TYPE_MCBIST |
                                TARGET_TYPE_MI     |
                                TARGET_TYPE_DMI    |
                                TARGET_TYPE_OBUS   |
                                TARGET_TYPE_NV     |
                                TARGET_TYPE_SBE    |
                                TARGET_TYPE_PPE    |
                                TARGET_TYPE_PERV   |
                                TARGET_TYPE_PEC    |
                                TARGET_TYPE_PHB,

    // Mappings to target types found in the error xml files
    TARGET_TYPE_EX_CHIPLET    = TARGET_TYPE_EX,
    TARGET_TYPE_MBA_CHIPLET   = TARGET_TYPE_MBA,
    TARGET_TYPE_MCS_CHIPLET   = TARGET_TYPE_MCS,
    TARGET_TYPE_XBUS_ENDPOINT = TARGET_TYPE_XBUS,
    TARGET_TYPE_ABUS_ENDPOINT = TARGET_TYPE_ABUS,
};

///
/// @brief Enumeration of chiplet filters
///
enum TargetFilter
{
    TARGET_FILTER_TP          = 0x80000000,  // Pervasive 1
    TARGET_FILTER_NEST_NORTH  = 0x40000000,  // Pervasive 2
    TARGET_FILTER_NEST_SOUTH  = 0x20000000,  // Pervasive 3
    TARGET_FILTER_NEST_EAST   = 0x10000000,  // Pervasive 4
    TARGET_FILTER_NEST_WEST   = 0x08000000,  // Pervasive 5
    TARGET_FILTER_XBUS        = 0x04000000,  // Pervasive 6
    TARGET_FILTER_MC_WEST     = 0x02000000,  // Pervasive 7
    TARGET_FILTER_MC_EAST     = 0x01000000,  // Pervasive 8
    TARGET_FILTER_OBUS0       = 0x00800000,  // Pervasive 9
    TARGET_FILTER_OBUS1       = 0x00400000,  // Pervasive 10
    TARGET_FILTER_OBUS2       = 0x00200000,  // Pervasive 11
    TARGET_FILTER_OBUS3       = 0x00100000,  // Pervasive 12
    TARGET_FILTER_PCI0        = 0x00080000,  // Pervasive 13
    TARGET_FILTER_PCI1        = 0x00040000,  // Pervasive 14
    TARGET_FILTER_PCI2        = 0x00020000,  // Pervasive 15

    // Composite filters follow

    // Pervasive 2-5 (eg N0-N3) < req'd
    TARGET_FILTER_ALL_NEST    = (TARGET_FILTER_NEST_NORTH |
                                 TARGET_FILTER_NEST_SOUTH | TARGET_FILTER_NEST_EAST |
                                 TARGET_FILTER_NEST_WEST),

    // Pervasive 2-4 (eg N0-N2) < req'd
    TARGET_FILTER_NEST_SLAVES =
        (TARGET_FILTER_NEST_NORTH | TARGET_FILTER_NEST_SOUTH |
         TARGET_FILTER_NEST_EAST),

    // Pervasive 5 (eg N32) < req'd
    TARGET_FILTER_NEST_MASTER = TARGET_FILTER_NEST_WEST,

    // Pervasive 7-8 (eg MC0-MC1)
    TARGET_FILTER_ALL_MC      =
        (TARGET_FILTER_MC_WEST | TARGET_FILTER_MC_EAST),

    // Pervasive 9-12 (OB0-OB3)
    TARGET_FILTER_ALL_OBUS    =
        (TARGET_FILTER_OBUS0 | TARGET_FILTER_OBUS1 | TARGET_FILTER_OBUS2 |
         TARGET_FILTER_OBUS3),

    // Pervasive 13-15 (PCI0-PCI2)
    TARGET_FILTER_ALL_PCI =
        (TARGET_FILTER_PCI0 | TARGET_FILTER_PCI1 | TARGET_FILTER_PCI2),

    // Sync mode filter = All NEST + All MCS
    TARGET_FILTER_SYNC_MODE_NEST =
        (TARGET_FILTER_ALL_NEST | TARGET_FILTER_ALL_MC),

    // All IO Targets except NEST
    TARGET_FILTER_ALL_IO_EXCEPT_NEST =
        (TARGET_FILTER_XBUS | TARGET_FILTER_ALL_PCI | TARGET_FILTER_ALL_OBUS),
};

/// @cond
constexpr TargetType operator|(TargetType x, TargetType y)
{
    return static_cast<TargetType>(static_cast<int>(x) |
                                   static_cast<int>(y));
}

template<uint64_t V>
class bitCount
{
    public:
        // Don't use enums, too hard to compare
        static const uint8_t count = bitCount < (V >> 1) >::count + (V & 1);
};

template<>
class bitCount<0>
{
    public:
        static const uint8_t count = 0;
};
/// @endcond

}

#endif
<commit_msg>Updated target filter definitions<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/hwpf/fapi2/include/target_types.H $                */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2012,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
/**
 * @file target_types.H
 * @brief definitions for fapi2 target types
 */

#ifndef __FAPI2_TARGET_TYPES__
#define __FAPI2_TARGET_TYPES__
#include <stdint.h>
/// FAPI namespace
namespace fapi2
{
///
/// @enum fapi::TargetType
/// @brief Types, kinds, of targets
/// @note TYPE_NONE is used to represent empty/NULL targets in lists
/// or tables. TYPE_ALL is used to pass targets to methods which
/// can act generally on any type of target
///

/// Target Kind
enum TargetType
{
    TARGET_TYPE_NONE          = 0x00000000, ///< No type
    TARGET_TYPE_SYSTEM        = 0x00000001, ///< System type
    TARGET_TYPE_DIMM          = 0x00000002, ///< DIMM type
    TARGET_TYPE_PROC_CHIP     = 0x00000004, ///< Processor type
    TARGET_TYPE_MEMBUF_CHIP   = 0x00000008, ///< Membuf type
    TARGET_TYPE_EX            = 0x00000010, ///< EX - 2x Core, L2, L3 - can be deconfigured
    TARGET_TYPE_MBA           = 0x00000020, ///< MBA type
    TARGET_TYPE_MCS           = 0x00000040, ///< MCS type
    TARGET_TYPE_XBUS          = 0x00000080, ///< XBUS type
    TARGET_TYPE_ABUS          = 0x00000100, ///< ABUS type
    TARGET_TYPE_L4            = 0x00000200, ///< L4 type
    TARGET_TYPE_CORE          = 0x00000400, ///< Core - 4x threads(?) - can be deconfigured
    TARGET_TYPE_EQ            = 0x00000800, ///< EQ - 4x core, 2x L2, 2x L3 - can be deconfigured
    TARGET_TYPE_MCA           = 0x00001000, ///< MCA type
    TARGET_TYPE_MCBIST        = 0x00002000, ///< MCBIST type
    TARGET_TYPE_MI            = 0x00004000, ///< MI Memory Interface (Cumulus)
    TARGET_TYPE_CAPP          = 0x00008000, ///< CAPP target
    TARGET_TYPE_DMI           = 0x00010000, ///< DMI type
    TARGET_TYPE_OBUS          = 0x00020000, ///< OBUS type
    TARGET_TYPE_NV            = 0x00040000, ///< NV bus type
    TARGET_TYPE_SBE           = 0x00080000, ///< SBE type
    TARGET_TYPE_PPE           = 0x00100000, ///< PPE type
    TARGET_TYPE_PERV          = 0x00200000, ///< Pervasive type
    TARGET_TYPE_PEC           = 0x00400000, ///< PEC type
    TARGET_TYPE_PHB           = 0x00800000, ///< PHB type

    TARGET_TYPE_ALL           = 0xFFFFFFFF, ///< Any/All types

    // Compound target types
    TARGET_TYPE_CHIPS         = TARGET_TYPE_PROC_CHIP |
                                TARGET_TYPE_MEMBUF_CHIP,

    TARGET_TYPE_CHIPLETS      = TARGET_TYPE_EX     |
                                TARGET_TYPE_MBA    |
                                TARGET_TYPE_MCS    |
                                TARGET_TYPE_XBUS   |
                                TARGET_TYPE_ABUS   |
                                TARGET_TYPE_L4     |
                                TARGET_TYPE_CORE   |
                                TARGET_TYPE_EQ     |
                                TARGET_TYPE_MCA    |
                                TARGET_TYPE_MCBIST |
                                TARGET_TYPE_MI     |
                                TARGET_TYPE_DMI    |
                                TARGET_TYPE_OBUS   |
                                TARGET_TYPE_NV     |
                                TARGET_TYPE_SBE    |
                                TARGET_TYPE_PPE    |
                                TARGET_TYPE_PERV   |
                                TARGET_TYPE_PEC    |
                                TARGET_TYPE_PHB,

    // Mappings to target types found in the error xml files
    TARGET_TYPE_EX_CHIPLET    = TARGET_TYPE_EX,
    TARGET_TYPE_MBA_CHIPLET   = TARGET_TYPE_MBA,
    TARGET_TYPE_MCS_CHIPLET   = TARGET_TYPE_MCS,
    TARGET_TYPE_XBUS_ENDPOINT = TARGET_TYPE_XBUS,
    TARGET_TYPE_ABUS_ENDPOINT = TARGET_TYPE_ABUS,
};

///
/// @brief Enumeration of chiplet filters
///
enum TargetFilter
{
    TARGET_FILTER_TP          = 0x8000000000000000,  // Pervasive 1
    TARGET_FILTER_NEST_NORTH  = 0x4000000000000000,  // Pervasive 2
    TARGET_FILTER_NEST_SOUTH  = 0x2000000000000000,  // Pervasive 3
    TARGET_FILTER_NEST_EAST   = 0x1000000000000000,  // Pervasive 4
    TARGET_FILTER_NEST_WEST   = 0x0800000000000000,  // Pervasive 5
    TARGET_FILTER_XBUS        = 0x0400000000000000,  // Pervasive 6
    TARGET_FILTER_MC_WEST     = 0x0200000000000000,  // Pervasive 7
    TARGET_FILTER_MC_EAST     = 0x0100000000000000,  // Pervasive 8
    TARGET_FILTER_OBUS0       = 0x0080000000000000,  // Pervasive 9
    TARGET_FILTER_OBUS1       = 0x0040000000000000,  // Pervasive 10
    TARGET_FILTER_OBUS2       = 0x0020000000000000,  // Pervasive 11
    TARGET_FILTER_OBUS3       = 0x0010000000000000,  // Pervasive 12
    TARGET_FILTER_PCI0        = 0x0008000000000000,  // Pervasive 13
    TARGET_FILTER_PCI1        = 0x0004000000000000,  // Pervasive 14
    TARGET_FILTER_PCI2        = 0x0002000000000000,  // Pervasive 15
    TARGET_FILTER_CACHE0      = 0x0001000000000000,  // Pervasive 16
    TARGET_FILTER_CACHE1      = 0x0000800000000000,  // Pervasive 17
    TARGET_FILTER_CACHE2      = 0x0000400000000000,  // Pervasive 18
    TARGET_FILTER_CACHE3      = 0x0000200000000000,  // Pervasive 19
    TARGET_FILTER_CACHE4      = 0x0000100000000000,  // Pervasive 20
    TARGET_FILTER_CACHE5      = 0x0000080000000000,  // Pervasive 21
    TARGET_FILTER_CORE0       = 0x0000040000000000,  // Pervasive 32
    TARGET_FILTER_CORE1       = 0x0000020000000000,  // Pervasive 33
    TARGET_FILTER_CORE2       = 0x0000010000000000,  // Pervasive 34
    TARGET_FILTER_CORE3       = 0x0000008000000000,  // Pervasive 35
    TARGET_FILTER_CORE4       = 0x0000004000000000,  // Pervasive 36
    TARGET_FILTER_CORE5       = 0x0000002000000000,  // Pervasive 37
    TARGET_FILTER_CORE6       = 0x0000001000000000,  // Pervasive 38
    TARGET_FILTER_CORE7       = 0x0000000800000000,  // Pervasive 39
    TARGET_FILTER_CORE8       = 0x0000000400000000,  // Pervasive 40
    TARGET_FILTER_CORE9       = 0x0000000200000000,  // Pervasive 41
    TARGET_FILTER_CORE10      = 0x0000000100000000,  // Pervasive 42
    TARGET_FILTER_CORE11      = 0x0000000080000000,  // Pervasive 43
    TARGET_FILTER_CORE12      = 0x0000000040000000,  // Pervasive 44
    TARGET_FILTER_CORE13      = 0x0000000020000000,  // Pervasive 45
    TARGET_FILTER_CORE14      = 0x0000000010000000,  // Pervasive 46
    TARGET_FILTER_CORE15      = 0x0000000008000000,  // Pervasive 47
    TARGET_FILTER_CORE16      = 0x0000000004000000,  // Pervasive 48
    TARGET_FILTER_CORE17      = 0x0000000002000000,  // Pervasive 49
    TARGET_FILTER_CORE18      = 0x0000000001000000,  // Pervasive 50
    TARGET_FILTER_CORE19      = 0x0000000000800000,  // Pervasive 51
    TARGET_FILTER_CORE20      = 0x0000000000400000,  // Pervasive 52
    TARGET_FILTER_CORE21      = 0x0000000000200000,  // Pervasive 53
    TARGET_FILTER_CORE22      = 0x0000000000100000,  // Pervasive 54
    TARGET_FILTER_CORE23      = 0x0000000000080000,  // Pervasive 55

    // Composite filters follow

    // Pervasive 32-55 (all cores)
    TARGET_FILTER_ALL_CORES   = (TARGET_FILTER_CORE0 |
                                 TARGET_FILTER_CORE1 | TARGET_FILTER_CORE2 |
                                 TARGET_FILTER_CORE3 | TARGET_FILTER_CORE4 |
                                 TARGET_FILTER_CORE5 | TARGET_FILTER_CORE6 |
                                 TARGET_FILTER_CORE7 | TARGET_FILTER_CORE8 |
                                 TARGET_FILTER_CORE9 | TARGET_FILTER_CORE10 |
                                 TARGET_FILTER_CORE11 | TARGET_FILTER_CORE12 |
                                 TARGET_FILTER_CORE13 | TARGET_FILTER_CORE14 |
                                 TARGET_FILTER_CORE15 | TARGET_FILTER_CORE16 |
                                 TARGET_FILTER_CORE17 | TARGET_FILTER_CORE18 |
                                 TARGET_FILTER_CORE19 | TARGET_FILTER_CORE20 |
                                 TARGET_FILTER_CORE21 | TARGET_FILTER_CORE22 |
                                 TARGET_FILTER_CORE23),

    // Pervasive 16-21 (all caches)
    TARGET_FILTER_ALL_CACHES  = (TARGET_FILTER_CACHE0 |
                                 TARGET_FILTER_CACHE1 | TARGET_FILTER_CACHE2 |
                                 TARGET_FILTER_CACHE3 | TARGET_FILTER_CACHE4 |
                                 TARGET_FILTER_CACHE5),

    // Pervasive 2-5 (eg N0-N3) < req'd
    TARGET_FILTER_ALL_NEST    = (TARGET_FILTER_NEST_NORTH |
                                 TARGET_FILTER_NEST_SOUTH | TARGET_FILTER_NEST_EAST |
                                 TARGET_FILTER_NEST_WEST),

    // Pervasive 2-4 (eg N0-N2) < req'd
    TARGET_FILTER_NEST_SLAVES =
        (TARGET_FILTER_NEST_NORTH | TARGET_FILTER_NEST_SOUTH |
         TARGET_FILTER_NEST_EAST),

    // Pervasive 5 (eg N32) < req'd
    TARGET_FILTER_NEST_MASTER = TARGET_FILTER_NEST_WEST,

    // Pervasive 7-8 (eg MC0-MC1)
    TARGET_FILTER_ALL_MC      =
        (TARGET_FILTER_MC_WEST | TARGET_FILTER_MC_EAST),

    // Pervasive 9-12 (OB0-OB3)
    TARGET_FILTER_ALL_OBUS    =
        (TARGET_FILTER_OBUS0 | TARGET_FILTER_OBUS1 | TARGET_FILTER_OBUS2 |
         TARGET_FILTER_OBUS3),

    // Pervasive 13-15 (PCI0-PCI2)
    TARGET_FILTER_ALL_PCI =
        (TARGET_FILTER_PCI0 | TARGET_FILTER_PCI1 | TARGET_FILTER_PCI2),

    // Sync mode filter = All NEST + All MCS
    TARGET_FILTER_SYNC_MODE_NEST =
        (TARGET_FILTER_ALL_NEST | TARGET_FILTER_ALL_MC),

    // All IO Targets except NEST
    TARGET_FILTER_ALL_IO_EXCEPT_NEST =
        (TARGET_FILTER_XBUS | TARGET_FILTER_ALL_PCI | TARGET_FILTER_ALL_OBUS),

    // All sync mode IO except NEST
    TARGET_FILTER_SYNC_MODE_ALL_IO_EXCEPT_NEST =
        (TARGET_FILTER_ALL_MC | TARGET_FILTER_XBUS | TARGET_FILTER_ALL_PCI |
         TARGET_FILTER_ALL_OBUS),

    // All sync mode NEST slaves
    TARGET_FILTER_SYNC_MODE_NEST_SLAVES =
        (TARGET_FILTER_ALL_MC | TARGET_FILTER_NEST_SLAVES),

    // All sync mode IO
    TARGET_FILTER_SYNC_MODE_ALL_IO =
        (TARGET_FILTER_ALL_MC | TARGET_FILTER_ALL_NEST |
         TARGET_FILTER_ALL_OBUS | TARGET_FILTER_ALL_PCI |
         TARGET_FILTER_XBUS),

    // All IO
    TARGET_FILTER_ALL_IO = (TARGET_FILTER_ALL_NEST |
                            TARGET_FILTER_ALL_OBUS | TARGET_FILTER_ALL_PCI |
                            TARGET_FILTER_XBUS),

    // All sync mode except TP
    TARGET_FILTER_SYNC_MODE_ALL_EXCEPT_TP =
        (TARGET_FILTER_ALL_MC | TARGET_FILTER_ALL_NEST |
         TARGET_FILTER_ALL_OBUS | TARGET_FILTER_ALL_PCI |
         TARGET_FILTER_XBUS | TARGET_FILTER_ALL_CORES |
         TARGET_FILTER_ALL_CACHES),
};

/// @cond
constexpr TargetType operator|(TargetType x, TargetType y)
{
    return static_cast<TargetType>(static_cast<int>(x) |
                                   static_cast<int>(y));
}

template<uint64_t V>
class bitCount
{
    public:
        // Don't use enums, too hard to compare
        static const uint8_t count = bitCount < (V >> 1) >::count + (V & 1);
};

template<>
class bitCount<0>
{
    public:
        static const uint8_t count = 0;
};
/// @endcond

}

#endif
<|endoftext|>


<commit_before>#include "sdpnegotiator.h"

#include "mediacapabilities.h"

#include "common.h"

#include <QDateTime>

SDPNegotiator::SDPNegotiator()
{}

std::shared_ptr<SDPMessageInfo> SDPNegotiator::generateLocalSDP(QString localAddress)
{
  // TODO: This should ask media manager, what options it supports.

  printNormal(this, "Generating new SDP message with our address",
              "Local address", localAddress);

  QString localUsername = getLocalUsername();

  if(localAddress == ""
     || localAddress == "0.0.0.0"
     || localUsername == "")
  {
    printWarning(this, " Necessary info not set for SDP generation",
                 {"username"}, {localUsername});

    return nullptr;
  }

  // TODO: Get suitable SDP from media manager
  std::shared_ptr<SDPMessageInfo> newInfo = std::shared_ptr<SDPMessageInfo> (new SDPMessageInfo);
  newInfo->version = 0;
  generateOrigin(newInfo, localAddress);
  setConnectionAddress(newInfo, localAddress);

  newInfo->sessionName = SESSION_NAME;
  newInfo->sessionDescription = SESSION_DESCRIPTION;

  newInfo->timeDescriptions.push_back(TimeInfo{0,0, "", "", {}});

  MediaInfo audio;
  MediaInfo video;

  if(!generateAudioMedia(audio) || !generateVideoMedia(video))
  {
    return nullptr;
  }

  newInfo->media = {audio, video};

  return newInfo;
}

std::shared_ptr<SDPMessageInfo> SDPNegotiator::negotiateSDP(SDPMessageInfo& remoteSDPOffer,
                                                          QString localAddress)
{
  // At this point we should have checked if their offer is acceptable.
  // Now we just have to generate our answer.

  std::shared_ptr<SDPMessageInfo> newInfo = std::shared_ptr<SDPMessageInfo> (new SDPMessageInfo);

  // we assume our answer will be different so new origin
  generateOrigin(newInfo, localAddress);
  setConnectionAddress(newInfo, localAddress);

  newInfo->version = 0;
  newInfo->sessionName = remoteSDPOffer.sessionName;
  newInfo->sessionDescription = remoteSDPOffer.sessionDescription;
  newInfo->timeDescriptions = remoteSDPOffer.timeDescriptions;

  // Now the hard part. Select best codecs and set our corresponding media ports.
  for (auto& remoteMedia : remoteSDPOffer.media)
  {
    MediaInfo ourMedia;
    ourMedia.type = remoteMedia.type;
    ourMedia.receivePort = 0; // TODO: ICE Should set this to one of its candidates
    ourMedia.proto = remoteMedia.proto;
    ourMedia.title = remoteMedia.title;
    if (remoteMedia.flagAttributes.empty())
    {
      ourMedia.flagAttributes = {A_SENDRECV};
    }
    else if (remoteMedia.flagAttributes.back() == A_SENDONLY)
    {
      ourMedia.flagAttributes = {A_RECVONLY};
    }
    else if (remoteMedia.flagAttributes.back() == A_RECVONLY)
    {
      ourMedia.flagAttributes = {A_SENDONLY};
    }
    else {
      ourMedia.flagAttributes = remoteMedia.flagAttributes;
    }

    // set our bitrate, not implemented
    // set our encryptionKey, not implemented

    if (remoteMedia.type == "audio")
    {
      QList<uint8_t> supportedNums = PREDEFINED_AUDIO_CODECS;
      QList<RTPMap> supportedCodecs = DYNAMIC_AUDIO_CODECS;

      selectBestCodec(remoteMedia.rtpNums, remoteMedia.codecs,
                      supportedNums, supportedCodecs,
                      ourMedia.rtpNums, ourMedia.codecs);

    }
    else if (remoteMedia.type == "video")
    {
      QList<uint8_t> supportedNums = PREDEFINED_VIDEO_CODECS;
      QList<RTPMap> supportedCodecs = DYNAMIC_VIDEO_CODECS;

      selectBestCodec(remoteMedia.rtpNums, remoteMedia.codecs,
                      supportedNums, supportedCodecs,
                      ourMedia.rtpNums, ourMedia.codecs);
    }
    newInfo->media.append(ourMedia);
  }

  return newInfo;
}

bool SDPNegotiator::selectBestCodec(QList<uint8_t>& remoteNums,       QList<RTPMap> &remoteCodecs,
                                    QList<uint8_t>& supportedNums,    QList<RTPMap> &supportedCodecs,
                                    QList<uint8_t>& outMatchingNums,  QList<RTPMap> &outMatchingCodecs)
{
  for (auto& remoteCodec : remoteCodecs)
  {
    for (auto& supportedCodec : supportedCodecs)
    {
      if(remoteCodec.codec == supportedCodec.codec)
      {
        outMatchingCodecs.append(remoteCodec);
        printDebug(DEBUG_NORMAL, "SDPNegotiator",  "Found suitable codec.");

        outMatchingNums.push_back(remoteCodec.rtpNum);

        return true;
      }
    }
  }

  for (auto& rtpNumber : remoteNums)
  {
    for (auto& supportedNum : supportedNums)
    {
      if(rtpNumber == supportedNum)
      {
        outMatchingNums.append(rtpNumber);
        printDebug(DEBUG_NORMAL, "SDPNegotiator",  "Found suitable RTP number.");
        return true;
      }
    }
  }

  printDebug(DEBUG_ERROR, "SDPNegotiator",
             "Could not find suitable codec or RTP number for media.");

  return false;
}

void SDPNegotiator::generateOrigin(std::shared_ptr<SDPMessageInfo> sdp,
                                 QString localAddress)
{
  sdp->originator_username = getLocalUsername();
  sdp->sess_id = QDateTime::currentMSecsSinceEpoch();
  sdp->sess_v = QDateTime::currentMSecsSinceEpoch();
  sdp->host_nettype = "IN";
  sdp->host_address = localAddress;
  if (localAddress.front() == "[")
  {
    sdp->host_address = localAddress.mid(1, localAddress.size() - 2);
    sdp->host_addrtype = "IP6";
  }
  else {
    sdp->host_addrtype = "IP4";
  }
}

void SDPNegotiator::setConnectionAddress(std::shared_ptr<SDPMessageInfo> sdp,
                                       QString localAddress)
{
  sdp->connection_address = localAddress;
  sdp->connection_nettype = "IN";
  if (localAddress.front() == "[")
  {
    sdp->connection_address = localAddress.mid(1, localAddress.size() - 2);
    sdp->connection_addrtype = "IP6";
  }
  else
  {
    sdp->connection_addrtype = "IP4";
  }
}

bool SDPNegotiator::generateAudioMedia(MediaInfo &audio)
{
  // we ignore nettype, addrtype and address, because we use a global c=
  audio = {"audio", 0, "RTP/AVP", {},
           "", "", "", "", {},"", DYNAMIC_AUDIO_CODECS, {A_SENDRECV}, {}};

  // add all the dynamic numbers first because we want to favor dynamic type codecs.
  for(RTPMap& codec : audio.codecs)
  {
    audio.rtpNums.push_back(codec.rtpNum);
  }

  audio.rtpNums += PREDEFINED_AUDIO_CODECS;
  return true;
}

bool SDPNegotiator::generateVideoMedia(MediaInfo& video)
{
  // we ignore nettype, addrtype and address, because we use a global c=
  video = {"video", 0, "RTP/AVP", {},
           "", "", "", "", {},"", DYNAMIC_VIDEO_CODECS, {A_SENDRECV}, {}};

  for(RTPMap& codec : video.codecs)
  {
    video.rtpNums.push_back(codec.rtpNum);
  }

  // just for completeness, we will probably never support any of the pre-set video types.
  video.rtpNums += PREDEFINED_VIDEO_CODECS;
  return true;
}

bool SDPNegotiator::checkSDPOffer(SDPMessageInfo &offer) const
{
  // TODO: check everything.

  bool hasAudio = false;
  bool hasH265 = false;

  if(offer.connection_address == "0.0.0.0")
  {
    printPeerError(this, "Got bad global address from SDP", "Address",
                   offer.connection_address);
    return false;
  }

  if(offer.version != 0)
  {
    printPeerError(this, "Their offer had non-0 version", "Version",
                   QString::number(offer.version));
    return false;
  }

  QStringList debugCodecsFound = {};
  for(MediaInfo& media : offer.media)
  {
    if(!media.rtpNums.empty() && media.rtpNums.first() == 0)
    {
      debugCodecsFound << "pcm";
      hasAudio = true;
    }

    for(RTPMap& rtp : media.codecs)
    {
      if(rtp.codec == "opus")
      {
        debugCodecsFound << "opus";
        hasAudio = true;
      }
      else if(rtp.codec == "h265")
      {
        debugCodecsFound << "h265";
        hasH265 = true;
      }
    }
  }

  printDebug(DEBUG_NORMAL, "Negotiation",
             "Found following codecs in SDP", {"Codecs"}, debugCodecsFound);

  if (offer.timeDescriptions.size() >= 1)
  {
    if (offer.timeDescriptions.at(0).startTime != 0 ||
        offer.timeDescriptions.at(0).stopTime != 0)
    {
      printDebug(DEBUG_ERROR, "Negotiation",
                 "They offered us a session with limits. Unsupported.");
      return false;
    }
  }
  else {
    printDebug(DEBUG_PROGRAM_ERROR, "Negotiation",
               "they included wrong number of Time Descriptions. Should be detected earlier.");
    return false;
  }

  return hasAudio && hasH265;
}

void SDPNegotiator::setMediaPair(MediaInfo& media,
                                 std::shared_ptr<ICEInfo> mediaInfo,
                                 bool local)
{
  if (mediaInfo == nullptr)
  {
    printDebug(DEBUG_PROGRAM_ERROR, "SDPNegotiator", "Null mediainfo in setMediaPair");
    return;
  }

  // for local address, we bind to our rel-address if using non-host connection type
  if (local &&
      mediaInfo->type != "host" &&
      mediaInfo->rel_address != "" && mediaInfo->rel_port != 0)
  {
    media.connection_address = mediaInfo->rel_address;
    media.receivePort        = mediaInfo->rel_port;
  }
  else
  {
    media.connection_address = mediaInfo->address;
    media.receivePort        = mediaInfo->port;
  }
}

<commit_msg>fix(Negotiation): This check does not make sense if we use ICE<commit_after>#include "sdpnegotiator.h"

#include "mediacapabilities.h"

#include "common.h"

#include <QDateTime>

SDPNegotiator::SDPNegotiator()
{}

std::shared_ptr<SDPMessageInfo> SDPNegotiator::generateLocalSDP(QString localAddress)
{
  // TODO: This should ask media manager, what options it supports.

  printNormal(this, "Generating new SDP message with our address",
              "Local address", localAddress);

  QString localUsername = getLocalUsername();

  if(localAddress == ""
     || localAddress == "0.0.0.0"
     || localUsername == "")
  {
    printWarning(this, " Necessary info not set for SDP generation",
                 {"username"}, {localUsername});

    return nullptr;
  }

  // TODO: Get suitable SDP from media manager
  std::shared_ptr<SDPMessageInfo> newInfo = std::shared_ptr<SDPMessageInfo> (new SDPMessageInfo);
  newInfo->version = 0;
  generateOrigin(newInfo, localAddress);
  setConnectionAddress(newInfo, localAddress);

  newInfo->sessionName = SESSION_NAME;
  newInfo->sessionDescription = SESSION_DESCRIPTION;

  newInfo->timeDescriptions.push_back(TimeInfo{0,0, "", "", {}});

  MediaInfo audio;
  MediaInfo video;

  if(!generateAudioMedia(audio) || !generateVideoMedia(video))
  {
    return nullptr;
  }

  newInfo->media = {audio, video};

  return newInfo;
}

std::shared_ptr<SDPMessageInfo> SDPNegotiator::negotiateSDP(SDPMessageInfo& remoteSDPOffer,
                                                          QString localAddress)
{
  // At this point we should have checked if their offer is acceptable.
  // Now we just have to generate our answer.

  std::shared_ptr<SDPMessageInfo> newInfo = std::shared_ptr<SDPMessageInfo> (new SDPMessageInfo);

  // we assume our answer will be different so new origin
  generateOrigin(newInfo, localAddress);
  setConnectionAddress(newInfo, localAddress);

  newInfo->version = 0;
  newInfo->sessionName = remoteSDPOffer.sessionName;
  newInfo->sessionDescription = remoteSDPOffer.sessionDescription;
  newInfo->timeDescriptions = remoteSDPOffer.timeDescriptions;

  // Now the hard part. Select best codecs and set our corresponding media ports.
  for (auto& remoteMedia : remoteSDPOffer.media)
  {
    MediaInfo ourMedia;
    ourMedia.type = remoteMedia.type;
    ourMedia.receivePort = 0; // TODO: ICE Should set this to one of its candidates
    ourMedia.proto = remoteMedia.proto;
    ourMedia.title = remoteMedia.title;
    if (remoteMedia.flagAttributes.empty())
    {
      ourMedia.flagAttributes = {A_SENDRECV};
    }
    else if (remoteMedia.flagAttributes.back() == A_SENDONLY)
    {
      ourMedia.flagAttributes = {A_RECVONLY};
    }
    else if (remoteMedia.flagAttributes.back() == A_RECVONLY)
    {
      ourMedia.flagAttributes = {A_SENDONLY};
    }
    else {
      ourMedia.flagAttributes = remoteMedia.flagAttributes;
    }

    // set our bitrate, not implemented
    // set our encryptionKey, not implemented

    if (remoteMedia.type == "audio")
    {
      QList<uint8_t> supportedNums = PREDEFINED_AUDIO_CODECS;
      QList<RTPMap> supportedCodecs = DYNAMIC_AUDIO_CODECS;

      selectBestCodec(remoteMedia.rtpNums, remoteMedia.codecs,
                      supportedNums, supportedCodecs,
                      ourMedia.rtpNums, ourMedia.codecs);

    }
    else if (remoteMedia.type == "video")
    {
      QList<uint8_t> supportedNums = PREDEFINED_VIDEO_CODECS;
      QList<RTPMap> supportedCodecs = DYNAMIC_VIDEO_CODECS;

      selectBestCodec(remoteMedia.rtpNums, remoteMedia.codecs,
                      supportedNums, supportedCodecs,
                      ourMedia.rtpNums, ourMedia.codecs);
    }
    newInfo->media.append(ourMedia);
  }

  return newInfo;
}

bool SDPNegotiator::selectBestCodec(QList<uint8_t>& remoteNums,       QList<RTPMap> &remoteCodecs,
                                    QList<uint8_t>& supportedNums,    QList<RTPMap> &supportedCodecs,
                                    QList<uint8_t>& outMatchingNums,  QList<RTPMap> &outMatchingCodecs)
{
  for (auto& remoteCodec : remoteCodecs)
  {
    for (auto& supportedCodec : supportedCodecs)
    {
      if(remoteCodec.codec == supportedCodec.codec)
      {
        outMatchingCodecs.append(remoteCodec);
        printDebug(DEBUG_NORMAL, "SDPNegotiator",  "Found suitable codec.");

        outMatchingNums.push_back(remoteCodec.rtpNum);

        return true;
      }
    }
  }

  for (auto& rtpNumber : remoteNums)
  {
    for (auto& supportedNum : supportedNums)
    {
      if(rtpNumber == supportedNum)
      {
        outMatchingNums.append(rtpNumber);
        printDebug(DEBUG_NORMAL, "SDPNegotiator",  "Found suitable RTP number.");
        return true;
      }
    }
  }

  printDebug(DEBUG_ERROR, "SDPNegotiator",
             "Could not find suitable codec or RTP number for media.");

  return false;
}

void SDPNegotiator::generateOrigin(std::shared_ptr<SDPMessageInfo> sdp,
                                 QString localAddress)
{
  sdp->originator_username = getLocalUsername();
  sdp->sess_id = QDateTime::currentMSecsSinceEpoch();
  sdp->sess_v = QDateTime::currentMSecsSinceEpoch();
  sdp->host_nettype = "IN";
  sdp->host_address = localAddress;
  if (localAddress.front() == "[")
  {
    sdp->host_address = localAddress.mid(1, localAddress.size() - 2);
    sdp->host_addrtype = "IP6";
  }
  else {
    sdp->host_addrtype = "IP4";
  }
}

void SDPNegotiator::setConnectionAddress(std::shared_ptr<SDPMessageInfo> sdp,
                                       QString localAddress)
{
  sdp->connection_address = localAddress;
  sdp->connection_nettype = "IN";
  if (localAddress.front() == "[")
  {
    sdp->connection_address = localAddress.mid(1, localAddress.size() - 2);
    sdp->connection_addrtype = "IP6";
  }
  else
  {
    sdp->connection_addrtype = "IP4";
  }
}

bool SDPNegotiator::generateAudioMedia(MediaInfo &audio)
{
  // we ignore nettype, addrtype and address, because we use a global c=
  audio = {"audio", 0, "RTP/AVP", {},
           "", "", "", "", {},"", DYNAMIC_AUDIO_CODECS, {A_SENDRECV}, {}};

  // add all the dynamic numbers first because we want to favor dynamic type codecs.
  for(RTPMap& codec : audio.codecs)
  {
    audio.rtpNums.push_back(codec.rtpNum);
  }

  audio.rtpNums += PREDEFINED_AUDIO_CODECS;
  return true;
}

bool SDPNegotiator::generateVideoMedia(MediaInfo& video)
{
  // we ignore nettype, addrtype and address, because we use a global c=
  video = {"video", 0, "RTP/AVP", {},
           "", "", "", "", {},"", DYNAMIC_VIDEO_CODECS, {A_SENDRECV}, {}};

  for(RTPMap& codec : video.codecs)
  {
    video.rtpNums.push_back(codec.rtpNum);
  }

  // just for completeness, we will probably never support any of the pre-set video types.
  video.rtpNums += PREDEFINED_VIDEO_CODECS;
  return true;
}

bool SDPNegotiator::checkSDPOffer(SDPMessageInfo &offer) const
{
  // TODO: check everything.

  bool hasAudio = false;
  bool hasH265 = false;

  if(offer.version != 0)
  {
    printPeerError(this, "Their offer had non-0 version", "Version",
                   QString::number(offer.version));
    return false;
  }

  QStringList debugCodecsFound = {};
  for(MediaInfo& media : offer.media)
  {
    if(!media.rtpNums.empty() && media.rtpNums.first() == 0)
    {
      debugCodecsFound << "pcm";
      hasAudio = true;
    }

    for(RTPMap& rtp : media.codecs)
    {
      if(rtp.codec == "opus")
      {
        debugCodecsFound << "opus";
        hasAudio = true;
      }
      else if(rtp.codec == "h265")
      {
        debugCodecsFound << "h265";
        hasH265 = true;
      }
    }
  }

  printDebug(DEBUG_NORMAL, "Negotiation",
             "Found following codecs in SDP", {"Codecs"}, debugCodecsFound);

  if (offer.timeDescriptions.size() >= 1)
  {
    if (offer.timeDescriptions.at(0).startTime != 0 ||
        offer.timeDescriptions.at(0).stopTime != 0)
    {
      printDebug(DEBUG_ERROR, "Negotiation",
                 "They offered us a session with limits. Unsupported.");
      return false;
    }
  }
  else {
    printDebug(DEBUG_PROGRAM_ERROR, "Negotiation",
               "they included wrong number of Time Descriptions. Should be detected earlier.");
    return false;
  }

  return hasAudio && hasH265;
}

void SDPNegotiator::setMediaPair(MediaInfo& media,
                                 std::shared_ptr<ICEInfo> mediaInfo,
                                 bool local)
{
  if (mediaInfo == nullptr)
  {
    printDebug(DEBUG_PROGRAM_ERROR, "SDPNegotiator", "Null mediainfo in setMediaPair");
    return;
  }

  // for local address, we bind to our rel-address if using non-host connection type
  if (local &&
      mediaInfo->type != "host" &&
      mediaInfo->rel_address != "" && mediaInfo->rel_port != 0)
  {
    media.connection_address = mediaInfo->rel_address;
    media.receivePort        = mediaInfo->rel_port;
  }
  else
  {
    media.connection_address = mediaInfo->address;
    media.receivePort        = mediaInfo->port;
  }
}

<|endoftext|>