<commit_before>
/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include <boost/bind.hpp>
#include "libtorrent/invariant_check.hpp"
#include "libtorrent/connection_queue.hpp"

namespace libtorrent
{

	connection_queue::connection_queue(io_service& ios): m_next_ticket(0)
		, m_num_connecting(0)
		, m_half_open_limit(0)
		, m_timer(ios)
#ifndef NDEBUG
		, m_in_timeout_function(false)
#endif
	{
#ifdef TORRENT_CONNECTION_LOGGING
		m_log.open("connection_queue.log");
#endif
	}

	int connection_queue::free_slots() const
	{
		mutex_t::scoped_lock l(m_mutex);
		return m_half_open_limit == 0 ? std::numeric_limits<int>::max()
			: m_half_open_limit - m_queue.size();
	}

	void connection_queue::enqueue(boost::function<void(int)> const& on_connect
		, boost::function<void()> const& on_timeout
		, time_duration timeout, int priority)
	{
		mutex_t::scoped_lock l(m_mutex);

		INVARIANT_CHECK;

		TORRENT_ASSERT(priority >= 0);
		TORRENT_ASSERT(priority < 2);

		entry* e = 0;

		switch (priority)
		{
			case 0:
				m_queue.push_back(entry());
				e = &m_queue.back();
				break;
			case 1:
				m_queue.push_front(entry());
				e = &m_queue.front();
				break;
		}

		e->priority = priority;
		e->on_connect = on_connect;
		e->on_timeout = on_timeout;
		e->ticket = m_next_ticket;
		e->timeout = timeout;
		++m_next_ticket;
		try_connect();
	}

	void connection_queue::done(int ticket)
	{
		mutex_t::scoped_lock l(m_mutex);

		INVARIANT_CHECK;

		std::list<entry>::iterator i = std::find_if(m_queue.begin()
			, m_queue.end(), boost::bind(&entry::ticket, _1) == ticket);
		if (i == m_queue.end())
		{
			// this might not be here in case on_timeout calls remove
			return;
		}
		if (i->connecting) --m_num_connecting;
		m_queue.erase(i);
		try_connect();
	}

	void connection_queue::close()
	{
		asio::error_code ec;
		m_timer.cancel(ec);
	}

	void connection_queue::limit(int limit)
	{
		TORRENT_ASSERT(limit >= 0);
		m_half_open_limit = limit;
	}

	int connection_queue::limit() const
	{ return m_half_open_limit; }

#ifndef NDEBUG

	void connection_queue::check_invariant() const
	{
		int num_connecting = 0;
		for (std::list<entry>::const_iterator i = m_queue.begin();
			i != m_queue.end(); ++i)
		{
			if (i->connecting) ++num_connecting;
		}
		TORRENT_ASSERT(num_connecting == m_num_connecting);
	}

#endif

	void connection_queue::try_connect()
	{
		INVARIANT_CHECK;

#ifdef TORRENT_CONNECTION_LOGGING
		m_log << log_time() << " " << free_slots() << std::endl;
#endif

		if (m_num_connecting >= m_half_open_limit
			&& m_half_open_limit > 0) return;

		if (m_queue.empty())
		{
			asio::error_code ec;
			m_timer.cancel(ec);
			return;
		}

		std::list<entry>::iterator i = std::find_if(m_queue.begin()
			, m_queue.end(), boost::bind(&entry::connecting, _1) == false);
		while (i != m_queue.end())
		{
			TORRENT_ASSERT(i->connecting == false);
			ptime expire = time_now() + i->timeout;
			if (m_num_connecting == 0)
			{
				asio::error_code ec;
				m_timer.expires_at(expire, ec);
				m_timer.async_wait(boost::bind(&connection_queue::on_timeout, this, _1));
			}
			i->connecting = true;
			++m_num_connecting;
			i->expires = expire;

			INVARIANT_CHECK;

			entry& ent = *i;
			++i;
#ifndef BOOST_NO_EXCEPTIONS
			try {
#endif
				ent.on_connect(ent.ticket);
#ifndef BOOST_NO_EXCEPTIONS
			} catch (std::exception&) {}
#endif

#ifdef TORRENT_CONNECTION_LOGGING
			m_log << log_time() << " " << free_slots() << std::endl;
#endif

			if (m_num_connecting >= m_half_open_limit
				&& m_half_open_limit > 0) break;
			i = std::find_if(i, m_queue.end(), boost::bind(&entry::connecting, _1) == false);
		}
	}

#ifndef NDEBUG
	struct function_guard
	{
		function_guard(bool& v): val(v) { TORRENT_ASSERT(!val); val = true; }
		~function_guard() { val = false; }

		bool& val;
	};
#endif

	void connection_queue::on_timeout(asio::error_code const& e)
	{
		mutex_t::scoped_lock l(m_mutex);

		INVARIANT_CHECK;
#ifndef NDEBUG
		function_guard guard_(m_in_timeout_function);
#endif

		TORRENT_ASSERT(!e || e == asio::error::operation_aborted);
		if (e) return;

		ptime next_expire = max_time();
		ptime now = time_now();
		std::list<entry> timed_out;
		for (std::list<entry>::iterator i = m_queue.begin();
			!m_queue.empty() && i != m_queue.end();)
		{
			if (i->connecting && i->expires < now)
			{
				std::list<entry>::iterator j = i;
				++i;
				timed_out.splice(timed_out.end(), m_queue, j, i);
				--m_num_connecting;
				continue;
			}
			if (i->expires < next_expire)
				next_expire = i->expires;
			++i;
		}

		// we don't want to call the timeout callback while we're locked
		// since that is a recepie for dead-locks
		l.unlock();

		for (std::list<entry>::iterator i = timed_out.begin()
			, end(timed_out.end()); i != end; ++i)
		{
			try { i->on_timeout(); } catch (std::exception&) {}
		}

		l.lock();

		if (next_expire < max_time())
		{
			asio::error_code ec;
			m_timer.expires_at(next_expire, ec);
			m_timer.async_wait(boost::bind(&connection_queue::on_timeout, this, _1));
		}
		try_connect();
	}

}

<commit_msg>msvc fix<commit_after>
/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include <boost/bind.hpp>
#include "libtorrent/invariant_check.hpp"
#include "libtorrent/connection_queue.hpp"

namespace libtorrent
{

	connection_queue::connection_queue(io_service& ios): m_next_ticket(0)
		, m_num_connecting(0)
		, m_half_open_limit(0)
		, m_timer(ios)
#ifndef NDEBUG
		, m_in_timeout_function(false)
#endif
	{
#ifdef TORRENT_CONNECTION_LOGGING
		m_log.open("connection_queue.log");
#endif
	}

	int connection_queue::free_slots() const
	{
		mutex_t::scoped_lock l(m_mutex);
		return m_half_open_limit == 0 ? (std::numeric_limits<int>::max)()
			: m_half_open_limit - m_queue.size();
	}

	void connection_queue::enqueue(boost::function<void(int)> const& on_connect
		, boost::function<void()> const& on_timeout
		, time_duration timeout, int priority)
	{
		mutex_t::scoped_lock l(m_mutex);

		INVARIANT_CHECK;

		TORRENT_ASSERT(priority >= 0);
		TORRENT_ASSERT(priority < 2);

		entry* e = 0;

		switch (priority)
		{
			case 0:
				m_queue.push_back(entry());
				e = &m_queue.back();
				break;
			case 1:
				m_queue.push_front(entry());
				e = &m_queue.front();
				break;
		}

		e->priority = priority;
		e->on_connect = on_connect;
		e->on_timeout = on_timeout;
		e->ticket = m_next_ticket;
		e->timeout = timeout;
		++m_next_ticket;
		try_connect();
	}

	void connection_queue::done(int ticket)
	{
		mutex_t::scoped_lock l(m_mutex);

		INVARIANT_CHECK;

		std::list<entry>::iterator i = std::find_if(m_queue.begin()
			, m_queue.end(), boost::bind(&entry::ticket, _1) == ticket);
		if (i == m_queue.end())
		{
			// this might not be here in case on_timeout calls remove
			return;
		}
		if (i->connecting) --m_num_connecting;
		m_queue.erase(i);
		try_connect();
	}

	void connection_queue::close()
	{
		asio::error_code ec;
		m_timer.cancel(ec);
	}

	void connection_queue::limit(int limit)
	{
		TORRENT_ASSERT(limit >= 0);
		m_half_open_limit = limit;
	}

	int connection_queue::limit() const
	{ return m_half_open_limit; }

#ifndef NDEBUG

	void connection_queue::check_invariant() const
	{
		int num_connecting = 0;
		for (std::list<entry>::const_iterator i = m_queue.begin();
			i != m_queue.end(); ++i)
		{
			if (i->connecting) ++num_connecting;
		}
		TORRENT_ASSERT(num_connecting == m_num_connecting);
	}

#endif

	void connection_queue::try_connect()
	{
		INVARIANT_CHECK;

#ifdef TORRENT_CONNECTION_LOGGING
		m_log << log_time() << " " << free_slots() << std::endl;
#endif

		if (m_num_connecting >= m_half_open_limit
			&& m_half_open_limit > 0) return;

		if (m_queue.empty())
		{
			asio::error_code ec;
			m_timer.cancel(ec);
			return;
		}

		std::list<entry>::iterator i = std::find_if(m_queue.begin()
			, m_queue.end(), boost::bind(&entry::connecting, _1) == false);
		while (i != m_queue.end())
		{
			TORRENT_ASSERT(i->connecting == false);
			ptime expire = time_now() + i->timeout;
			if (m_num_connecting == 0)
			{
				asio::error_code ec;
				m_timer.expires_at(expire, ec);
				m_timer.async_wait(boost::bind(&connection_queue::on_timeout, this, _1));
			}
			i->connecting = true;
			++m_num_connecting;
			i->expires = expire;

			INVARIANT_CHECK;

			entry& ent = *i;
			++i;
#ifndef BOOST_NO_EXCEPTIONS
			try {
#endif
				ent.on_connect(ent.ticket);
#ifndef BOOST_NO_EXCEPTIONS
			} catch (std::exception&) {}
#endif

#ifdef TORRENT_CONNECTION_LOGGING
			m_log << log_time() << " " << free_slots() << std::endl;
#endif

			if (m_num_connecting >= m_half_open_limit
				&& m_half_open_limit > 0) break;
			i = std::find_if(i, m_queue.end(), boost::bind(&entry::connecting, _1) == false);
		}
	}

#ifndef NDEBUG
	struct function_guard
	{
		function_guard(bool& v): val(v) { TORRENT_ASSERT(!val); val = true; }
		~function_guard() { val = false; }

		bool& val;
	};
#endif

	void connection_queue::on_timeout(asio::error_code const& e)
	{
		mutex_t::scoped_lock l(m_mutex);

		INVARIANT_CHECK;
#ifndef NDEBUG
		function_guard guard_(m_in_timeout_function);
#endif

		TORRENT_ASSERT(!e || e == asio::error::operation_aborted);
		if (e) return;

		ptime next_expire = max_time();
		ptime now = time_now();
		std::list<entry> timed_out;
		for (std::list<entry>::iterator i = m_queue.begin();
			!m_queue.empty() && i != m_queue.end();)
		{
			if (i->connecting && i->expires < now)
			{
				std::list<entry>::iterator j = i;
				++i;
				timed_out.splice(timed_out.end(), m_queue, j, i);
				--m_num_connecting;
				continue;
			}
			if (i->expires < next_expire)
				next_expire = i->expires;
			++i;
		}

		// we don't want to call the timeout callback while we're locked
		// since that is a recepie for dead-locks
		l.unlock();

		for (std::list<entry>::iterator i = timed_out.begin()
			, end(timed_out.end()); i != end; ++i)
		{
			try { i->on_timeout(); } catch (std::exception&) {}
		}

		l.lock();

		if (next_expire < max_time())
		{
			asio::error_code ec;
			m_timer.expires_at(next_expire, ec);
			m_timer.async_wait(boost::bind(&connection_queue::on_timeout, this, _1));
		}
		try_connect();
	}

}

<|endoftext|>


<commit_before>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include <boost/bind.hpp>
#include "libtorrent/config.hpp"
#include "libtorrent/invariant_check.hpp"
#include "libtorrent/connection_queue.hpp"
#include "libtorrent/io_service.hpp"
#include "libtorrent/error_code.hpp"
#include "libtorrent/error.hpp"

#if defined TORRENT_ASIO_DEBUGGING
#include "libtorrent/debug.hpp"
#endif

namespace libtorrent
{

	connection_queue::connection_queue(io_service& ios): m_next_ticket(0)
		, m_num_connecting(0)
		, m_half_open_limit(0)
		, m_abort(false)
		, m_num_timers(0)
		, m_timer(ios)
#ifdef TORRENT_DEBUG
		, m_in_timeout_function(false)
#endif
	{
#ifdef TORRENT_CONNECTION_LOGGING
		m_log.open("connection_queue.log");
#endif
	}

	int connection_queue::free_slots() const
	{
		mutex_t::scoped_lock l(m_mutex);
		return m_half_open_limit == 0 ? (std::numeric_limits<int>::max)()
			: m_half_open_limit - m_queue.size();
	}

	void connection_queue::enqueue(boost::function<void(int)> const& on_connect
		, boost::function<void()> const& on_timeout
		, time_duration timeout, int priority)
	{
		mutex_t::scoped_lock l(m_mutex);

		INVARIANT_CHECK;

		TORRENT_ASSERT(priority >= 0);
		TORRENT_ASSERT(priority < 3);

		entry* e = 0;

		switch (priority)
		{
			case 0:
				m_queue.push_back(entry());
				e = &m_queue.back();
				break;
			case 1:
			case 2:
				m_queue.push_front(entry());
				e = &m_queue.front();
				break;
			default: return;
		}

		e->priority = priority;
		e->on_connect = on_connect;
		e->on_timeout = on_timeout;
		e->ticket = m_next_ticket;
		e->timeout = timeout;
		++m_next_ticket;

		if (m_num_connecting < m_half_open_limit
			|| m_half_open_limit == 0)
			m_timer.get_io_service().post(boost::bind(
				&connection_queue::on_try_connect, this));
	}

	void connection_queue::done(int ticket)
	{
		mutex_t::scoped_lock l(m_mutex);

		INVARIANT_CHECK;

		std::list<entry>::iterator i = std::find_if(m_queue.begin()
			, m_queue.end(), boost::bind(&entry::ticket, _1) == ticket);
		if (i == m_queue.end())
		{
			// this might not be here in case on_timeout calls remove
			return;
		}
		if (i->connecting) --m_num_connecting;
		m_queue.erase(i);

		if (m_num_connecting < m_half_open_limit
			|| m_half_open_limit == 0)
			m_timer.get_io_service().post(boost::bind(
				&connection_queue::on_try_connect, this));
	}

	void connection_queue::close()
	{
		error_code ec;
		mutex_t::scoped_lock l(m_mutex);
		if (m_num_connecting == 0) m_timer.cancel(ec);
		m_abort = true;

		std::list<entry> tmp;
		tmp.swap(m_queue);
		m_num_connecting = 0;

		// we don't want to call the timeout callback while we're locked
		// since that is a recipie for dead-locks
		l.unlock();

		while (!tmp.empty())
		{
			entry& e = tmp.front();
			if (e.priority > 1)
			{
				mutex_t::scoped_lock ll(m_mutex);
				if (e.connecting) ++m_num_connecting;
				m_queue.push_back(e);
				tmp.pop_front();
				continue;
			}
			TORRENT_TRY {
				e.on_connect(-1);
			} TORRENT_CATCH(std::exception&) {}
			tmp.pop_front();
		}
	}

	void connection_queue::limit(int limit)
	{
		TORRENT_ASSERT(limit >= 0);
		m_half_open_limit = limit;
	}

	int connection_queue::limit() const
	{ return m_half_open_limit; }

#ifdef TORRENT_DEBUG

	void connection_queue::check_invariant() const
	{
		int num_connecting = 0;
		for (std::list<entry>::const_iterator i = m_queue.begin();
			i != m_queue.end(); ++i)
		{
			if (i->connecting) ++num_connecting;
			else TORRENT_ASSERT(i->expires == max_time());
		}
		TORRENT_ASSERT(num_connecting == m_num_connecting);
	}

#endif

	void connection_queue::try_connect(connection_queue::mutex_t::scoped_lock& l)
	{
		INVARIANT_CHECK;

#ifdef TORRENT_CONNECTION_LOGGING
		m_log << log_time() << " " << free_slots() << std::endl;
#endif
		// if this is enabled, UPnP connections will be blocked when shutting down
//		if (m_abort) return;

		if (m_num_connecting >= m_half_open_limit
			&& m_half_open_limit > 0) return;

		if (m_queue.empty())
		{
			error_code ec;
			m_timer.cancel(ec);
			return;
		}

		// all entries are connecting, no need to look for new ones
		if (m_queue.size() == m_num_connecting)
			return;

		std::list<entry>::iterator i = std::find_if(m_queue.begin()
			, m_queue.end(), boost::bind(&entry::connecting, _1) == false);

		std::list<entry> to_connect;

		while (i != m_queue.end())
		{
			TORRENT_ASSERT(i->connecting == false);
			ptime expire = time_now_hires() + i->timeout;
			if (m_num_connecting == 0)
			{
#if defined TORRENT_ASIO_DEBUGGING
				add_outstanding_async("connection_queue::on_timeout");
#endif
				error_code ec;
				m_timer.expires_at(expire, ec);
				m_timer.async_wait(boost::bind(&connection_queue::on_timeout, this, _1));
				++m_num_timers;
			}
			i->connecting = true;
			++m_num_connecting;
			i->expires = expire;

			INVARIANT_CHECK;

			to_connect.push_back(*i);

#ifdef TORRENT_CONNECTION_LOGGING
			m_log << log_time() << " " << free_slots() << std::endl;
#endif

			if (m_num_connecting >= m_half_open_limit
				&& m_half_open_limit > 0) break;
			if (m_num_connecting == m_queue.size()) break;
			i = std::find_if(i, m_queue.end(), boost::bind(&entry::connecting, _1) == false);
		}

		l.unlock();

		while (!to_connect.empty())
		{
			entry& ent = to_connect.front();
			TORRENT_TRY {
				ent.on_connect(ent.ticket);
			} TORRENT_CATCH(std::exception&) {}
			to_connect.pop_front();
		}

	}

#ifdef TORRENT_DEBUG
	struct function_guard
	{
		function_guard(bool& v): val(v) { TORRENT_ASSERT(!val); val = true; }
		~function_guard() { val = false; }

		bool& val;
	};
#endif

	void connection_queue::on_timeout(error_code const& e)
	{
#if defined TORRENT_ASIO_DEBUGGING
		complete_async("connection_queue::on_timeout");
#endif
		mutex_t::scoped_lock l(m_mutex);
		--m_num_timers;

		INVARIANT_CHECK;
#ifdef TORRENT_DEBUG
		function_guard guard_(m_in_timeout_function);
#endif

		TORRENT_ASSERT(!e || e == error::operation_aborted);
		if (e && m_num_connecting == 0 && m_num_timers > 0) return;

		ptime next_expire = max_time();
		ptime now = time_now_hires() + milliseconds(100);
		std::list<entry> timed_out;
		for (std::list<entry>::iterator i = m_queue.begin();
			!m_queue.empty() && i != m_queue.end();)
		{
			if (i->connecting && i->expires < now)
			{
				std::list<entry>::iterator j = i;
				++i;
				timed_out.splice(timed_out.end(), m_queue, j, i);
				--m_num_connecting;
				continue;
			}
			if (i->connecting && i->expires < next_expire)
				next_expire = i->expires;
			++i;
		}

		// we don't want to call the timeout callback while we're locked
		// since that is a recepie for dead-locks
		l.unlock();

		for (std::list<entry>::iterator i = timed_out.begin()
			, end(timed_out.end()); i != end; ++i)
		{
			TORRENT_ASSERT(i->connecting);
			TORRENT_ASSERT(i->ticket != -1);
			TORRENT_TRY {
				i->on_timeout();
			} TORRENT_CATCH(std::exception&) {}
		}

		l.lock();

		if (next_expire < max_time())
		{
#if defined TORRENT_ASIO_DEBUGGING
			add_outstanding_async("connection_queue::on_timeout");
#endif
			error_code ec;
			m_timer.expires_at(next_expire, ec);
			m_timer.async_wait(boost::bind(&connection_queue::on_timeout, this, _1));
			++m_num_timers;
		}
		try_connect(l);
	}

	void connection_queue::on_try_connect()
	{
		mutex_t::scoped_lock l(m_mutex);
		try_connect(l);
	}
}

<commit_msg>fix connection queue timeout logic<commit_after>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include <boost/bind.hpp>
#include "libtorrent/config.hpp"
#include "libtorrent/invariant_check.hpp"
#include "libtorrent/connection_queue.hpp"
#include "libtorrent/io_service.hpp"
#include "libtorrent/error_code.hpp"
#include "libtorrent/error.hpp"

#if defined TORRENT_ASIO_DEBUGGING
#include "libtorrent/debug.hpp"
#endif

namespace libtorrent
{

	connection_queue::connection_queue(io_service& ios): m_next_ticket(0)
		, m_num_connecting(0)
		, m_half_open_limit(0)
		, m_abort(false)
		, m_num_timers(0)
		, m_timer(ios)
#ifdef TORRENT_DEBUG
		, m_in_timeout_function(false)
#endif
	{
#ifdef TORRENT_CONNECTION_LOGGING
		m_log.open("connection_queue.log");
#endif
	}

	int connection_queue::free_slots() const
	{
		mutex_t::scoped_lock l(m_mutex);
		return m_half_open_limit == 0 ? (std::numeric_limits<int>::max)()
			: m_half_open_limit - m_queue.size();
	}

	void connection_queue::enqueue(boost::function<void(int)> const& on_connect
		, boost::function<void()> const& on_timeout
		, time_duration timeout, int priority)
	{
		mutex_t::scoped_lock l(m_mutex);

		INVARIANT_CHECK;

		TORRENT_ASSERT(priority >= 0);
		TORRENT_ASSERT(priority < 3);

		entry* e = 0;

		switch (priority)
		{
			case 0:
				m_queue.push_back(entry());
				e = &m_queue.back();
				break;
			case 1:
			case 2:
				m_queue.push_front(entry());
				e = &m_queue.front();
				break;
			default: return;
		}

		e->priority = priority;
		e->on_connect = on_connect;
		e->on_timeout = on_timeout;
		e->ticket = m_next_ticket;
		e->timeout = timeout;
		++m_next_ticket;

		if (m_num_connecting < m_half_open_limit
			|| m_half_open_limit == 0)
			m_timer.get_io_service().post(boost::bind(
				&connection_queue::on_try_connect, this));
	}

	void connection_queue::done(int ticket)
	{
		mutex_t::scoped_lock l(m_mutex);

		INVARIANT_CHECK;

		std::list<entry>::iterator i = std::find_if(m_queue.begin()
			, m_queue.end(), boost::bind(&entry::ticket, _1) == ticket);
		if (i == m_queue.end())
		{
			// this might not be here in case on_timeout calls remove
			return;
		}
		if (i->connecting) --m_num_connecting;
		m_queue.erase(i);

		if (m_num_connecting < m_half_open_limit
			|| m_half_open_limit == 0)
			m_timer.get_io_service().post(boost::bind(
				&connection_queue::on_try_connect, this));
	}

	void connection_queue::close()
	{
		error_code ec;
		mutex_t::scoped_lock l(m_mutex);
		if (m_num_connecting == 0) m_timer.cancel(ec);
		m_abort = true;

		std::list<entry> tmp;
		tmp.swap(m_queue);
		m_num_connecting = 0;

		// we don't want to call the timeout callback while we're locked
		// since that is a recipie for dead-locks
		l.unlock();

		while (!tmp.empty())
		{
			entry& e = tmp.front();
			if (e.priority > 1)
			{
				mutex_t::scoped_lock ll(m_mutex);
				if (e.connecting) ++m_num_connecting;
				m_queue.push_back(e);
				tmp.pop_front();
				continue;
			}
			TORRENT_TRY {
				e.on_connect(-1);
			} TORRENT_CATCH(std::exception&) {}
			tmp.pop_front();
		}
	}

	void connection_queue::limit(int limit)
	{
		TORRENT_ASSERT(limit >= 0);
		m_half_open_limit = limit;
	}

	int connection_queue::limit() const
	{ return m_half_open_limit; }

#ifdef TORRENT_DEBUG

	void connection_queue::check_invariant() const
	{
		int num_connecting = 0;
		for (std::list<entry>::const_iterator i = m_queue.begin();
			i != m_queue.end(); ++i)
		{
			if (i->connecting) ++num_connecting;
			else TORRENT_ASSERT(i->expires == max_time());
		}
		TORRENT_ASSERT(num_connecting == m_num_connecting);
	}

#endif

	void connection_queue::try_connect(connection_queue::mutex_t::scoped_lock& l)
	{
		INVARIANT_CHECK;

#ifdef TORRENT_CONNECTION_LOGGING
		m_log << log_time() << " " << free_slots() << std::endl;
#endif
		// if this is enabled, UPnP connections will be blocked when shutting down
//		if (m_abort) return;

		if (m_num_connecting >= m_half_open_limit
			&& m_half_open_limit > 0) return;

		if (m_queue.empty())
		{
			error_code ec;
			m_timer.cancel(ec);
			return;
		}

		// all entries are connecting, no need to look for new ones
		if (m_queue.size() == m_num_connecting)
			return;

		std::list<entry>::iterator i = std::find_if(m_queue.begin()
			, m_queue.end(), boost::bind(&entry::connecting, _1) == false);

		std::list<entry> to_connect;

		while (i != m_queue.end())
		{
			TORRENT_ASSERT(i->connecting == false);
			ptime expire = time_now_hires() + i->timeout;
			if (m_num_connecting == 0)
			{
#if defined TORRENT_ASIO_DEBUGGING
				add_outstanding_async("connection_queue::on_timeout");
#endif
				error_code ec;
				m_timer.expires_at(expire, ec);
				m_timer.async_wait(boost::bind(&connection_queue::on_timeout, this, _1));
				++m_num_timers;
			}
			i->connecting = true;
			++m_num_connecting;
			i->expires = expire;

			INVARIANT_CHECK;

			to_connect.push_back(*i);

#ifdef TORRENT_CONNECTION_LOGGING
			m_log << log_time() << " " << free_slots() << std::endl;
#endif

			if (m_num_connecting >= m_half_open_limit
				&& m_half_open_limit > 0) break;
			if (m_num_connecting == m_queue.size()) break;
			i = std::find_if(i, m_queue.end(), boost::bind(&entry::connecting, _1) == false);
		}

		l.unlock();

		while (!to_connect.empty())
		{
			entry& ent = to_connect.front();
			TORRENT_TRY {
				ent.on_connect(ent.ticket);
			} TORRENT_CATCH(std::exception&) {}
			to_connect.pop_front();
		}

	}

#ifdef TORRENT_DEBUG
	struct function_guard
	{
		function_guard(bool& v): val(v) { TORRENT_ASSERT(!val); val = true; }
		~function_guard() { val = false; }

		bool& val;
	};
#endif

	void connection_queue::on_timeout(error_code const& e)
	{
#if defined TORRENT_ASIO_DEBUGGING
		complete_async("connection_queue::on_timeout");
#endif
		mutex_t::scoped_lock l(m_mutex);
		--m_num_timers;

		INVARIANT_CHECK;
#ifdef TORRENT_DEBUG
		function_guard guard_(m_in_timeout_function);
#endif

		TORRENT_ASSERT(!e || e == error::operation_aborted);

		// if there was an error, it's most likely operation aborted,
		// we should just quit. However, in case there are still connections
		// in connecting state, and there are no other timer invocations
		// we need to stick around still.
		if (e && (m_num_connecting == 0 || m_num_timers > 0)) return;

		ptime next_expire = max_time();
		ptime now = time_now_hires() + milliseconds(100);
		std::list<entry> timed_out;
		for (std::list<entry>::iterator i = m_queue.begin();
			!m_queue.empty() && i != m_queue.end();)
		{
			if (i->connecting && i->expires < now)
			{
				std::list<entry>::iterator j = i;
				++i;
				timed_out.splice(timed_out.end(), m_queue, j, i);
				--m_num_connecting;
				continue;
			}
			if (i->connecting && i->expires < next_expire)
				next_expire = i->expires;
			++i;
		}

		// we don't want to call the timeout callback while we're locked
		// since that is a recepie for dead-locks
		l.unlock();

		for (std::list<entry>::iterator i = timed_out.begin()
			, end(timed_out.end()); i != end; ++i)
		{
			TORRENT_ASSERT(i->connecting);
			TORRENT_ASSERT(i->ticket != -1);
			TORRENT_TRY {
				i->on_timeout();
			} TORRENT_CATCH(std::exception&) {}
		}

		l.lock();

		if (next_expire < max_time())
		{
#if defined TORRENT_ASIO_DEBUGGING
			add_outstanding_async("connection_queue::on_timeout");
#endif
			error_code ec;
			m_timer.expires_at(next_expire, ec);
			m_timer.async_wait(boost::bind(&connection_queue::on_timeout, this, _1));
			++m_num_timers;
		}
		try_connect(l);
	}

	void connection_queue::on_try_connect()
	{
		mutex_t::scoped_lock l(m_mutex);
		try_connect(l);
	}
}

<|endoftext|>


<commit_before>#include "SkClipStack.h"
#include "SkPath.h"
#include <new>

struct SkClipStack::Rec {
    enum State {
        kEmpty_State,
        kRect_State,
        kPath_State
    };

    SkPath          fPath;
    SkRect          fRect;
    int             fSaveCount;
    SkRegion::Op    fOp;
    State           fState;

    Rec(int saveCount, const SkRect& rect, SkRegion::Op op) : fRect(rect) {
        fSaveCount = saveCount;
        fOp = op;
        fState = kRect_State;
    }

    Rec(int saveCount, const SkPath& path, SkRegion::Op op) : fPath(path) {
        fSaveCount = saveCount;
        fOp = op;
        fState = kPath_State;
    }

    bool operator==(const Rec& b) const {
        if (fSaveCount != b.fSaveCount || fOp != b.fOp || fState != b.fState) {
            return false;
        }
        switch (fState) {
            case kEmpty_State:
                return true;
            case kRect_State:
                return fRect == b.fRect;
            case kPath_State:
                return fPath == b.fPath;
        }
        return false;  // Silence the compiler.
    }

    bool operator!=(const Rec& b) const {
        return !(*this == b);
    }

    /**
     *  Returns true if this Rec can be intersected in place with a new clip
     */
    bool canBeIntersected(int saveCount, SkRegion::Op op) const {
        if (kEmpty_State == fState && (
                    SkRegion::kDifference_Op == op ||
                    SkRegion::kIntersect_Op == op)) {
            return true;
        }
        return  fSaveCount == saveCount &&
                SkRegion::kIntersect_Op == fOp &&
                SkRegion::kIntersect_Op == op;
    }
};

SkClipStack::SkClipStack() : fDeque(sizeof(Rec)) {
    fSaveCount = 0;
}

SkClipStack::SkClipStack(const SkClipStack& b) : fDeque(sizeof(Rec)) {
    *this = b;
}

SkClipStack& SkClipStack::operator=(const SkClipStack& b) {
    if (this == &b) {
        return *this;
    }
    reset();

    fSaveCount = b.fSaveCount;
    SkDeque::F2BIter recIter(b.fDeque);
    for (const Rec* rec = (const Rec*)recIter.next();
            rec != NULL;
            rec = (const Rec*)recIter.next()) {
        new (fDeque.push_back()) Rec(*rec);
    }

    return *this;
}

bool SkClipStack::operator==(const SkClipStack& b) const {
    if (fSaveCount != b.fSaveCount || fDeque.count() != b.fDeque.count()) {
        return false;
    }
    SkDeque::F2BIter myIter(fDeque);
    SkDeque::F2BIter bIter(b.fDeque);
    const Rec* myRec = (const Rec*)myIter.next();
    const Rec* bRec = (const Rec*)bIter.next();

    while (myRec != NULL && bRec != NULL) {
        if (*myRec != *bRec) {
            return false;
        }
        myRec = (const Rec*)myIter.next();
        bRec = (const Rec*)bIter.next();
    }
    return myRec == NULL && bRec == NULL;
}

void SkClipStack::reset() {
    // don't have a reset() on SkDeque, so fake it here
    fDeque.~SkDeque();
    new (&fDeque) SkDeque(sizeof(Rec));

    fSaveCount = 0;
}

void SkClipStack::save() {
    fSaveCount += 1;
}

void SkClipStack::restore() {
    fSaveCount -= 1;
    while (!fDeque.empty()) {
        Rec* rec = (Rec*)fDeque.back();
        if (rec->fSaveCount <= fSaveCount) {
            break;
        }
        rec->~Rec();
        fDeque.pop_back();
    }
}

void SkClipStack::clipDevRect(const SkRect& rect, SkRegion::Op op) {
    Rec* rec = (Rec*)fDeque.back();
    if (rec && rec->canBeIntersected(fSaveCount, op)) {
        switch (rec->fState) {
            case Rec::kEmpty_State:
                return;
            case Rec::kRect_State:
                if (!rec->fRect.intersect(rect)) {
                    rec->fState = Rec::kEmpty_State;
                }
                return;
            case Rec::kPath_State:
                if (!SkRect::Intersects(rec->fPath.getBounds(), rect)) {
                    rec->fState = Rec::kEmpty_State;
                    return;
                }
                break;
        }
    }
    new (fDeque.push_back()) Rec(fSaveCount, rect, op);
}

void SkClipStack::clipDevPath(const SkPath& path, SkRegion::Op op) {
    Rec* rec = (Rec*)fDeque.back();
    if (rec && rec->canBeIntersected(fSaveCount, op)) {
        const SkRect& pathBounds = path.getBounds();
        switch (rec->fState) {
            case Rec::kEmpty_State:
                return;
            case Rec::kRect_State:
                if (!SkRect::Intersects(rec->fRect, pathBounds)) {
                    rec->fState = Rec::kEmpty_State;
                    return;
                }
                break;
            case Rec::kPath_State:
                if (!SkRect::Intersects(rec->fPath.getBounds(), pathBounds)) {
                    rec->fState = Rec::kEmpty_State;
                    return;
                }
                break;
        }
    }
    new (fDeque.push_back()) Rec(fSaveCount, path, op);
}

///////////////////////////////////////////////////////////////////////////////

SkClipStack::B2FIter::B2FIter() {
}

bool operator==(const SkClipStack::B2FIter::Clip& a,
               const SkClipStack::B2FIter::Clip& b) {
    return a.fOp == b.fOp &&
           ((a.fRect == NULL && b.fRect == NULL) || *a.fRect == *b.fRect) &&
           ((a.fPath == NULL && b.fPath == NULL) || *a.fPath == *b.fPath);
}

bool operator!=(const SkClipStack::B2FIter::Clip& a,
               const SkClipStack::B2FIter::Clip& b) {
    return !(a == b);
}

SkClipStack::B2FIter::B2FIter(const SkClipStack& stack) {
    this->reset(stack);
}

const SkClipStack::B2FIter::Clip* SkClipStack::B2FIter::next() {
    const SkClipStack::Rec* rec = (const SkClipStack::Rec*)fIter.next();
    if (NULL == rec) {
        return NULL;
    }

    switch (rec->fState) {
        case SkClipStack::Rec::kEmpty_State:
            fClip.fRect = NULL;
            fClip.fPath = NULL;
            break;
        case SkClipStack::Rec::kRect_State:
            fClip.fRect = &rec->fRect;
            fClip.fPath = NULL;
            break;
        case SkClipStack::Rec::kPath_State:
            fClip.fRect = NULL;
            fClip.fPath = &rec->fPath;
            break;
    }
    fClip.fOp = rec->fOp;
    return &fClip;
}

void SkClipStack::B2FIter::reset(const SkClipStack& stack) {
    fIter.reset(stack.fDeque);
}
<commit_msg>Handle possibly NULL deref in comparison<commit_after>#include "SkClipStack.h"
#include "SkPath.h"
#include <new>

struct SkClipStack::Rec {
    enum State {
        kEmpty_State,
        kRect_State,
        kPath_State
    };

    SkPath          fPath;
    SkRect          fRect;
    int             fSaveCount;
    SkRegion::Op    fOp;
    State           fState;

    Rec(int saveCount, const SkRect& rect, SkRegion::Op op) : fRect(rect) {
        fSaveCount = saveCount;
        fOp = op;
        fState = kRect_State;
    }

    Rec(int saveCount, const SkPath& path, SkRegion::Op op) : fPath(path) {
        fSaveCount = saveCount;
        fOp = op;
        fState = kPath_State;
    }

    bool operator==(const Rec& b) const {
        if (fSaveCount != b.fSaveCount || fOp != b.fOp || fState != b.fState) {
            return false;
        }
        switch (fState) {
            case kEmpty_State:
                return true;
            case kRect_State:
                return fRect == b.fRect;
            case kPath_State:
                return fPath == b.fPath;
        }
        return false;  // Silence the compiler.
    }

    bool operator!=(const Rec& b) const {
        return !(*this == b);
    }

    /**
     *  Returns true if this Rec can be intersected in place with a new clip
     */
    bool canBeIntersected(int saveCount, SkRegion::Op op) const {
        if (kEmpty_State == fState && (
                    SkRegion::kDifference_Op == op ||
                    SkRegion::kIntersect_Op == op)) {
            return true;
        }
        return  fSaveCount == saveCount &&
                SkRegion::kIntersect_Op == fOp &&
                SkRegion::kIntersect_Op == op;
    }
};

SkClipStack::SkClipStack() : fDeque(sizeof(Rec)) {
    fSaveCount = 0;
}

SkClipStack::SkClipStack(const SkClipStack& b) : fDeque(sizeof(Rec)) {
    *this = b;
}

SkClipStack& SkClipStack::operator=(const SkClipStack& b) {
    if (this == &b) {
        return *this;
    }
    reset();

    fSaveCount = b.fSaveCount;
    SkDeque::F2BIter recIter(b.fDeque);
    for (const Rec* rec = (const Rec*)recIter.next();
            rec != NULL;
            rec = (const Rec*)recIter.next()) {
        new (fDeque.push_back()) Rec(*rec);
    }

    return *this;
}

bool SkClipStack::operator==(const SkClipStack& b) const {
    if (fSaveCount != b.fSaveCount || fDeque.count() != b.fDeque.count()) {
        return false;
    }
    SkDeque::F2BIter myIter(fDeque);
    SkDeque::F2BIter bIter(b.fDeque);
    const Rec* myRec = (const Rec*)myIter.next();
    const Rec* bRec = (const Rec*)bIter.next();

    while (myRec != NULL && bRec != NULL) {
        if (*myRec != *bRec) {
            return false;
        }
        myRec = (const Rec*)myIter.next();
        bRec = (const Rec*)bIter.next();
    }
    return myRec == NULL && bRec == NULL;
}

void SkClipStack::reset() {
    // don't have a reset() on SkDeque, so fake it here
    fDeque.~SkDeque();
    new (&fDeque) SkDeque(sizeof(Rec));

    fSaveCount = 0;
}

void SkClipStack::save() {
    fSaveCount += 1;
}

void SkClipStack::restore() {
    fSaveCount -= 1;
    while (!fDeque.empty()) {
        Rec* rec = (Rec*)fDeque.back();
        if (rec->fSaveCount <= fSaveCount) {
            break;
        }
        rec->~Rec();
        fDeque.pop_back();
    }
}

void SkClipStack::clipDevRect(const SkRect& rect, SkRegion::Op op) {
    Rec* rec = (Rec*)fDeque.back();
    if (rec && rec->canBeIntersected(fSaveCount, op)) {
        switch (rec->fState) {
            case Rec::kEmpty_State:
                return;
            case Rec::kRect_State:
                if (!rec->fRect.intersect(rect)) {
                    rec->fState = Rec::kEmpty_State;
                }
                return;
            case Rec::kPath_State:
                if (!SkRect::Intersects(rec->fPath.getBounds(), rect)) {
                    rec->fState = Rec::kEmpty_State;
                    return;
                }
                break;
        }
    }
    new (fDeque.push_back()) Rec(fSaveCount, rect, op);
}

void SkClipStack::clipDevPath(const SkPath& path, SkRegion::Op op) {
    Rec* rec = (Rec*)fDeque.back();
    if (rec && rec->canBeIntersected(fSaveCount, op)) {
        const SkRect& pathBounds = path.getBounds();
        switch (rec->fState) {
            case Rec::kEmpty_State:
                return;
            case Rec::kRect_State:
                if (!SkRect::Intersects(rec->fRect, pathBounds)) {
                    rec->fState = Rec::kEmpty_State;
                    return;
                }
                break;
            case Rec::kPath_State:
                if (!SkRect::Intersects(rec->fPath.getBounds(), pathBounds)) {
                    rec->fState = Rec::kEmpty_State;
                    return;
                }
                break;
        }
    }
    new (fDeque.push_back()) Rec(fSaveCount, path, op);
}

///////////////////////////////////////////////////////////////////////////////

SkClipStack::B2FIter::B2FIter() {
}

bool operator==(const SkClipStack::B2FIter::Clip& a,
               const SkClipStack::B2FIter::Clip& b) {
    return a.fOp == b.fOp &&
           ((a.fRect == NULL && b.fRect == NULL) ||
               (a.fRect != NULL && b.fRect != NULL && *a.fRect == *b.fRect)) &&
           ((a.fPath == NULL && b.fPath == NULL) ||
               (a.fPath != NULL && b.fPath != NULL && *a.fPath == *b.fPath));
}

bool operator!=(const SkClipStack::B2FIter::Clip& a,
               const SkClipStack::B2FIter::Clip& b) {
    return !(a == b);
}

SkClipStack::B2FIter::B2FIter(const SkClipStack& stack) {
    this->reset(stack);
}

const SkClipStack::B2FIter::Clip* SkClipStack::B2FIter::next() {
    const SkClipStack::Rec* rec = (const SkClipStack::Rec*)fIter.next();
    if (NULL == rec) {
        return NULL;
    }

    switch (rec->fState) {
        case SkClipStack::Rec::kEmpty_State:
            fClip.fRect = NULL;
            fClip.fPath = NULL;
            break;
        case SkClipStack::Rec::kRect_State:
            fClip.fRect = &rec->fRect;
            fClip.fPath = NULL;
            break;
        case SkClipStack::Rec::kPath_State:
            fClip.fRect = NULL;
            fClip.fPath = &rec->fPath;
            break;
    }
    fClip.fOp = rec->fOp;
    return &fClip;
}

void SkClipStack::B2FIter::reset(const SkClipStack& stack) {
    fIter.reset(stack.fDeque);
}
<|endoftext|>


<commit_before>/*=====================================================================

 QGroundControl Open Source Ground Control Station

 (c) 2009 - 2011 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>

 This file is part of the QGROUNDCONTROL project

 QGROUNDCONTROL is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 QGROUNDCONTROL is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.

 ======================================================================*/

/**
 * @file
 *   @brief Implementation of main window
 *
 *   @author Dominik Honegger
 *
 */

#include "QGCVideoMainWindow.h"
#include "ui_QGCVideoMainWindow.h"

#include "UDPLink.h"
#include <QDebug>

  QByteArray imageRecBuffer = QByteArray(376*240,255);
  static int part = 0;

QGCVideoMainWindow::QGCVideoMainWindow(QWidget *parent) :
    QMainWindow(parent),
    link(QHostAddress::Any, 5555),
    ui(new Ui::QGCVideoMainWindow)
{
    ui->setupUi(this);

    // Set widgets in video mode
    ui->video1Widget->enableVideo(true);
    ui->video2Widget->enableVideo(true);
    ui->video3Widget->enableVideo(true);
    ui->video4Widget->enableVideo(true);

    // Connect link to this widget, receive all bytes
    connect(&link, SIGNAL(bytesReceived(LinkInterface*,QByteArray)), this, SLOT(receiveBytes(LinkInterface*,QByteArray)));

    // Open port
    link.connect();
}

QGCVideoMainWindow::~QGCVideoMainWindow()
{
    delete ui;
}

void QGCVideoMainWindow::receiveBytes(LinkInterface* link, QByteArray data)
{
    // There is no need to differentiate between links
    // for this use case here
    Q_UNUSED(link);

    // Image data is stored in QByteArray
    // Output bytes and load Lenna!

    QString bytes;
    QString index;
    QString ascii;

    // TODO FIXME Fabian
    // RAW hardcoded to 22x22
    int imgWidth = 376;
    int imgHeight = 240;
    int imgColors = 255;

    //const int headerSize = 15;

    // Construct PGM header
    QString header("P5\n%1 %2\n%3\n");
    header = header.arg(imgWidth).arg(imgHeight).arg(imgColors);

    switch (data[0])
    {
    case (1):
        {
            for (int i=4; i<data.size()/4; i++)
            {
                imageRecBuffer[i] = data[i*4];
                part = part | 1;
            }
        }
    case (2):
        {
            for (int i=4; i<data.size()/4; i++)
            {
                imageRecBuffer[i+45124/4*2] = data[i*4];
                part = part | 2;
            }
        }
//    case (3):
//        {
//            for (int i=4; i<data.size()/4; i++)
//            {
//                imageRecBuffer[i+45124/4*2] = data[i*4];
//                part = part | 4;
//            }
//        }
    }
    if(part==3)
    {
        for (int i=45124/4*3; i<376*240; i++)
        {
            imageRecBuffer[i] = 255;
        }
        QByteArray tmpImage(header.toStdString().c_str(), header.toStdString().size());
        tmpImage.append(imageRecBuffer);

        // Load image into window
        QImage test(":images/patterns/lenna.jpg");
        QImage image;

        if (imageRecBuffer.isNull())
            {
                qDebug()<< "could not convertToPGM()";

            }

            if (!image.loadFromData(tmpImage, "PGM"))
            {
                qDebug()<< "could not create extracted image";

            }

        tmpImage.clear();
        ui->video1Widget->copyImage(test);
        ui->video2Widget->copyImage(image);
        //ui->video3Widget->copyImage(test);
        //ui->video4Widget->copyImage(test);
        part = 0;
        imageRecBuffer.clear();
    }

    unsigned char i0 = data[0];
    index.append(QString().sprintf("%02x ", i0));

    for (int j=0; j<data.size(); j++) {
        unsigned char v = data[j];
        bytes.append(QString().sprintf("%02x ", v));
        if (data.at(j) > 31 && data.at(j) < 127)
        {
            ascii.append(data.at(j));
        }
        else
        {
            ascii.append(219);
        }

    }
     qDebug() << "Received" << data.size() << "bytes";
     qDebug() << "index: " <<index;
    //qDebug() << bytes;
    //qDebug() << "ASCII:" << ascii;

}
<commit_msg>added byte decoding for current image stream<commit_after>/*=====================================================================

 QGroundControl Open Source Ground Control Station

 (c) 2009 - 2011 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>

 This file is part of the QGROUNDCONTROL project

 QGROUNDCONTROL is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 QGROUNDCONTROL is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.

 ======================================================================*/

/**
 * @file
 *   @brief Implementation of main window
 *
 *   @author Dominik Honegger
 *
 */

#include "QGCVideoMainWindow.h"
#include "ui_QGCVideoMainWindow.h"

#include "UDPLink.h"
#include <QDebug>

  QByteArray imageRecBuffer1 = QByteArray(376*240,255);
  QByteArray imageRecBuffer2 = QByteArray(376*240,255);
  static int part = 0;

QGCVideoMainWindow::QGCVideoMainWindow(QWidget *parent) :
    QMainWindow(parent),
    link(QHostAddress::Any, 5555),
    ui(new Ui::QGCVideoMainWindow)
{
    ui->setupUi(this);

    // Set widgets in video mode
    ui->video1Widget->enableVideo(true);
    ui->video2Widget->enableVideo(true);
    ui->video3Widget->enableVideo(true);
    ui->video4Widget->enableVideo(true);

    // Connect link to this widget, receive all bytes
    connect(&link, SIGNAL(bytesReceived(LinkInterface*,QByteArray)), this, SLOT(receiveBytes(LinkInterface*,QByteArray)));

    // Open port
    link.connect();
}

QGCVideoMainWindow::~QGCVideoMainWindow()
{
    delete ui;
}

void QGCVideoMainWindow::receiveBytes(LinkInterface* link, QByteArray data)
{
    // There is no need to differentiate between links
    // for this use case here
    Q_UNUSED(link);

    // Image data is stored in QByteArray
    // Output bytes and load Lenna!

    QString bytes;
    QString index;
    QString ascii;

    // TODO FIXME Fabian
    // RAW hardcoded to 22x22
    int imgWidth = 376;
    int imgHeight = 240;
    int imgColors = 255;

    //const int headerSize = 15;

    // Construct PGM header
    QString header("P5\n%1 %2\n%3\n");
    header = header.arg(imgWidth).arg(imgHeight).arg(imgColors);

    unsigned char i0 = data[0];

    switch (i0)
    {
    case 0x01:
        {
            for (int i=4; i<data.size()/4; i++)
            {
                imageRecBuffer1[i] = data[i*4];
                imageRecBuffer2[i] = data[i*4+1];
            }
            part = part | 1;
            break;
        }
    case 0x02:
        {
            for (int i=4; i<data.size()/4; i++)
            {
                imageRecBuffer1[i+45124/4] = data[i*4];
                imageRecBuffer2[i+45124/4] = data[i*4+1];
            }
            part = part | 2;
            break;
        }
    case 0x03:
        {
            for (int i=4; i<data.size()/4; i++)
            {
                imageRecBuffer1[i+45124/4*2] = data[i*4];
                imageRecBuffer2[i+45124/4*2] = data[i*4+1];
            }
            part = part | 4;
            break;
        }
    case 0x04:
        {
            for (int i=4; i<data.size()/4; i++)
            {
                imageRecBuffer1[i+45124/4*3] = data[i*4];
                imageRecBuffer2[i+45124/4*3] = data[i*4+1];
            }
            part = part | 8;
            break;
        }
    case 0x05:
        {
            for (int i=4; i<data.size()/4; i++)
            {
                imageRecBuffer1[i+45124/4*4] = data[i*4];
                imageRecBuffer2[i+45124/4*4] = data[i*4+1];
            }
            part = part | 16;
            break;
        }
    case 0x06:
        {
            for (int i=4; i<data.size()/4; i++)
            {
                imageRecBuffer1[i+45124/4*5] = data[i*4];
                imageRecBuffer2[i+45124/4*5] = data[i*4+1];
            }
            part = part | 32;
            break;
        }
    case 0x07:
        {
            for (int i=4; i<data.size()/4; i++)
            {
                imageRecBuffer1[i+45124/4*6] = data[i*4];
                imageRecBuffer2[i+45124/4*6] = data[i*4+1];
            }
            part = part | 64;
            break;
        }
    case 0x08:
        {
            for (int i=4; i<data.size()/4; i++)
            {
                imageRecBuffer1[i+45124/4*7] = data[i*4];
                imageRecBuffer2[i+45124/4*7] = data[i*4+1];
            }
            part = part | 128;
            break;
        }
    }
    if(part==255)
    {

        QByteArray tmpImage1(header.toStdString().c_str(), header.toStdString().size());
        tmpImage1.append(imageRecBuffer1);
        QByteArray tmpImage2(header.toStdString().c_str(), header.toStdString().size());
        tmpImage2.append(imageRecBuffer2);

        // Load image into window
        //QImage test(":images/patterns/lenna.jpg");
        QImage image1;
        QImage image2;

        if (imageRecBuffer1.isNull())
            {
                qDebug()<< "could not convertToPGM()";

            }

            if (!image1.loadFromData(tmpImage1, "PGM"))
            {
                qDebug()<< "could not create extracted image1";

            }
         if (imageRecBuffer2.isNull())
            {
                qDebug()<< "could not convertToPGM()";

            }

            if (!image2.loadFromData(tmpImage2, "PGM"))
            {
                 qDebug()<< "could not create extracted image2";

            }
        tmpImage1.clear();
        tmpImage2.clear();
        //ui->video1Widget->copyImage(test);
        ui->video2Widget->copyImage(image1);
        ui->video3Widget->copyImage(image2);
        //ui->video4Widget->copyImage(test);
        part = 0;
        imageRecBuffer1.clear();
        imageRecBuffer2.clear();
    }

    index.append(QString().sprintf("%02x ", i0));

    for (int j=0; j<data.size(); j++) {
        unsigned char v = data[j];
        bytes.append(QString().sprintf("%02x ", v));
        if (data.at(j) > 31 && data.at(j) < 127)
        {
            ascii.append(data.at(j));
        }
        else
        {
            ascii.append(219);
        }

    }
     qDebug() << "Received" << data.size() << "bytes";
     qDebug() << "index: " <<index;
    //qDebug() << bytes;
    //qDebug() << "ASCII:" << ascii;

}
<|endoftext|>


<commit_before>/*
 * Copyright 2010 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkImageInfo.h"
#include "SkImageInfoPriv.h"
#include "SkReadBuffer.h"
#include "SkWriteBuffer.h"

// Indicate how images and gradients should interpret colors by default.
bool gDefaultProfileIsSRGB;

SkColorProfileType SkDefaultColorProfile() {
    return gDefaultProfileIsSRGB ? kSRGB_SkColorProfileType
                                 : kLinear_SkColorProfileType;
}

static bool profile_type_is_valid(SkColorProfileType profileType) {
    return (profileType >= 0) && (profileType <= kLastEnum_SkColorProfileType);
}

static bool alpha_type_is_valid(SkAlphaType alphaType) {
    return (alphaType >= 0) && (alphaType <= kLastEnum_SkAlphaType);
}

static bool color_type_is_valid(SkColorType colorType) {
    return (colorType >= 0) && (colorType <= kLastEnum_SkColorType);
}

void SkImageInfo::unflatten(SkReadBuffer& buffer) {
    fWidth = buffer.read32();
    fHeight = buffer.read32();

    uint32_t packed = buffer.read32();
    SkASSERT(0 == (packed >> 24));
    fProfileType = (SkColorProfileType)((packed >> 16) & 0xFF);
    fAlphaType = (SkAlphaType)((packed >> 8) & 0xFF);
    fColorType = (SkColorType)((packed >> 0) & 0xFF);
    buffer.validate(profile_type_is_valid(fProfileType) &&
                    alpha_type_is_valid(fAlphaType) &&
                    color_type_is_valid(fColorType));
}

void SkImageInfo::flatten(SkWriteBuffer& buffer) const {
    buffer.write32(fWidth);
    buffer.write32(fHeight);

    SkASSERT(0 == (fProfileType & ~0xFF));
    SkASSERT(0 == (fAlphaType & ~0xFF));
    SkASSERT(0 == (fColorType & ~0xFF));
    uint32_t packed = (fProfileType << 16) | (fAlphaType << 8) | fColorType;
    buffer.write32(packed);
}

bool SkColorTypeValidateAlphaType(SkColorType colorType, SkAlphaType alphaType,
                                  SkAlphaType* canonical) {
    switch (colorType) {
        case kUnknown_SkColorType:
            alphaType = kUnknown_SkAlphaType;
            break;
        case kAlpha_8_SkColorType:
            if (kUnpremul_SkAlphaType == alphaType) {
                alphaType = kPremul_SkAlphaType;
            }
            // fall-through
        case kIndex_8_SkColorType:
        case kARGB_4444_SkColorType:
        case kRGBA_8888_SkColorType:
        case kBGRA_8888_SkColorType:
        case kRGBA_F16_SkColorType:
            if (kUnknown_SkAlphaType == alphaType) {
                return false;
            }
            break;
        case kRGB_565_SkColorType:
        case kGray_8_SkColorType:
            alphaType = kOpaque_SkAlphaType;
            break;
        default:
            return false;
    }
    if (canonical) {
        *canonical = alphaType;
    }
    return true;
}

///////////////////////////////////////////////////////////////////////////////////////////////////

#include "SkReadPixelsRec.h"

bool SkReadPixelsRec::trim(int srcWidth, int srcHeight) {
    switch (fInfo.colorType()) {
        case kUnknown_SkColorType:
        case kIndex_8_SkColorType:
            return false;
        default:
            break;
    }
    if (nullptr == fPixels || fRowBytes < fInfo.minRowBytes()) {
        return false;
    }
    if (0 == fInfo.width() || 0 == fInfo.height()) {
        return false;
    }

    int x = fX;
    int y = fY;
    SkIRect srcR = SkIRect::MakeXYWH(x, y, fInfo.width(), fInfo.height());
    if (!srcR.intersect(0, 0, srcWidth, srcHeight)) {
        return false;
    }

    // if x or y are negative, then we have to adjust pixels
    if (x > 0) {
        x = 0;
    }
    if (y > 0) {
        y = 0;
    }
    // here x,y are either 0 or negative
    fPixels = ((char*)fPixels - y * fRowBytes - x * fInfo.bytesPerPixel());
    // the intersect may have shrunk info's logical size
    fInfo = fInfo.makeWH(srcR.width(), srcR.height());
    fX = srcR.x();
    fY = srcR.y();

    return true;
}
<commit_msg>Change to sRGB default for codec generated images.<commit_after>/*
 * Copyright 2010 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkImageInfo.h"
#include "SkImageInfoPriv.h"
#include "SkReadBuffer.h"
#include "SkWriteBuffer.h"

// Indicate how images and gradients should interpret colors by default.
bool gDefaultProfileIsSRGB = true;

SkColorProfileType SkDefaultColorProfile() {
    return gDefaultProfileIsSRGB ? kSRGB_SkColorProfileType
                                 : kLinear_SkColorProfileType;
}

static bool profile_type_is_valid(SkColorProfileType profileType) {
    return (profileType >= 0) && (profileType <= kLastEnum_SkColorProfileType);
}

static bool alpha_type_is_valid(SkAlphaType alphaType) {
    return (alphaType >= 0) && (alphaType <= kLastEnum_SkAlphaType);
}

static bool color_type_is_valid(SkColorType colorType) {
    return (colorType >= 0) && (colorType <= kLastEnum_SkColorType);
}

void SkImageInfo::unflatten(SkReadBuffer& buffer) {
    fWidth = buffer.read32();
    fHeight = buffer.read32();

    uint32_t packed = buffer.read32();
    SkASSERT(0 == (packed >> 24));
    fProfileType = (SkColorProfileType)((packed >> 16) & 0xFF);
    fAlphaType = (SkAlphaType)((packed >> 8) & 0xFF);
    fColorType = (SkColorType)((packed >> 0) & 0xFF);
    buffer.validate(profile_type_is_valid(fProfileType) &&
                    alpha_type_is_valid(fAlphaType) &&
                    color_type_is_valid(fColorType));
}

void SkImageInfo::flatten(SkWriteBuffer& buffer) const {
    buffer.write32(fWidth);
    buffer.write32(fHeight);

    SkASSERT(0 == (fProfileType & ~0xFF));
    SkASSERT(0 == (fAlphaType & ~0xFF));
    SkASSERT(0 == (fColorType & ~0xFF));
    uint32_t packed = (fProfileType << 16) | (fAlphaType << 8) | fColorType;
    buffer.write32(packed);
}

bool SkColorTypeValidateAlphaType(SkColorType colorType, SkAlphaType alphaType,
                                  SkAlphaType* canonical) {
    switch (colorType) {
        case kUnknown_SkColorType:
            alphaType = kUnknown_SkAlphaType;
            break;
        case kAlpha_8_SkColorType:
            if (kUnpremul_SkAlphaType == alphaType) {
                alphaType = kPremul_SkAlphaType;
            }
            // fall-through
        case kIndex_8_SkColorType:
        case kARGB_4444_SkColorType:
        case kRGBA_8888_SkColorType:
        case kBGRA_8888_SkColorType:
        case kRGBA_F16_SkColorType:
            if (kUnknown_SkAlphaType == alphaType) {
                return false;
            }
            break;
        case kRGB_565_SkColorType:
        case kGray_8_SkColorType:
            alphaType = kOpaque_SkAlphaType;
            break;
        default:
            return false;
    }
    if (canonical) {
        *canonical = alphaType;
    }
    return true;
}

///////////////////////////////////////////////////////////////////////////////////////////////////

#include "SkReadPixelsRec.h"

bool SkReadPixelsRec::trim(int srcWidth, int srcHeight) {
    switch (fInfo.colorType()) {
        case kUnknown_SkColorType:
        case kIndex_8_SkColorType:
            return false;
        default:
            break;
    }
    if (nullptr == fPixels || fRowBytes < fInfo.minRowBytes()) {
        return false;
    }
    if (0 == fInfo.width() || 0 == fInfo.height()) {
        return false;
    }

    int x = fX;
    int y = fY;
    SkIRect srcR = SkIRect::MakeXYWH(x, y, fInfo.width(), fInfo.height());
    if (!srcR.intersect(0, 0, srcWidth, srcHeight)) {
        return false;
    }

    // if x or y are negative, then we have to adjust pixels
    if (x > 0) {
        x = 0;
    }
    if (y > 0) {
        y = 0;
    }
    // here x,y are either 0 or negative
    fPixels = ((char*)fPixels - y * fRowBytes - x * fInfo.bytesPerPixel());
    // the intersect may have shrunk info's logical size
    fInfo = fInfo.makeWH(srcR.width(), srcR.height());
    fX = srcR.x();
    fY = srcR.y();

    return true;
}
<|endoftext|>


<commit_before>extern "C" {
#include <sys/systm.h>
#include <sys/un.h>
#include <sys/kpi_socket.h>
errno_t sock_nointerrupt(socket_t so, int on);
}
#include "base.hpp"
#include "Client.hpp"
#include "Config.hpp"
#include "IOLockWrapper.hpp"

namespace org_pqrs_KeyRemap4MacBook {
  namespace {
    struct sockaddr_un sockaddr_;
    bool sockaddr_available_ = false;
    IOLock* lock_ = NULL;

    void
    releaseSocket(socket_t& socket)
    {
      sock_shutdown(socket, SHUT_RDWR);
      sock_close(socket);
    }

    bool
    makeSocket(socket_t& socket)
    {
      int error = sock_socket(PF_LOCAL, SOCK_STREAM, 0, NULL, NULL, &socket);
      if (error) {
        printf("[KeyRemap4MacBook ERROR] sock_socket failed(%d)\n", error);
        return false;
      }

      // ----------------------------------------
      struct timeval tv;
      tv.tv_sec = KeyRemap4MacBook_client::TIMEOUT_SECOND;
      tv.tv_usec = KeyRemap4MacBook_client::TIMEOUT_MICROSECOND;

      error = sock_setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval));
      if (error) {
        printf("[KeyRemap4MacBook ERROR] sock_setsockopt failed(%d)\n", error);
        goto error;
      }

      error = sock_setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(struct timeval));
      if (error) {
        printf("[KeyRemap4MacBook ERROR] sock_setsockopt failed(%d)\n", error);
        goto error;
      }

      return true;

    error:
      releaseSocket(socket);
      printf("KeyRemap4MacBook_client makeSocket failed(%d)\n", error);

      return false;
    }

    bool
    connectSocket(socket_t& socket)
    {
      if (! sockaddr_available_) return false;

      errno_t error = sock_connect(socket, reinterpret_cast<const sockaddr*>(&sockaddr_), 0);
      if (error) {
#if 0
        // the connection failure is no problem because a server does not start at login window.
        printf("[KeyRemap4MacBook ERROR] sock_connect failed(%d)\n", error);
#endif
        return false;
      }
      error = sock_nointerrupt(socket, TRUE);
      if (error) {
        printf("[KeyRemap4MacBook ERROR] sock_nointerrupt failed(%d)\n", error);
        return false;
      }

      return true;
    }
  }

  void
  KeyRemap4MacBook_client::initialize(void)
  {
    lock_ = IOLockWrapper::alloc();
    refreshSockAddr();
  }

  void
  KeyRemap4MacBook_client::terminate(void)
  {
    if (lock_) {
      IOLockWrapper::free(lock_);
    }
  }

  void
  KeyRemap4MacBook_client::refreshSockAddr(void)
  {
    if (! lock_) return;
    IOLockWrapper::ScopedLock lk(lock_);

    if (config.socket_path[0] == '\0') {
      sockaddr_available_ = false;
    } else {
      sockaddr_available_ = true;

      memset(&sockaddr_, 0, sizeof(sockaddr_));
      sockaddr_.sun_len = sizeof(sockaddr_);
      sockaddr_.sun_family = AF_UNIX;
      strlcpy(sockaddr_.sun_path, config.socket_path, sizeof(sockaddr_.sun_path) - 8);
    }
  }

  int
  KeyRemap4MacBook_client::sendmsg(KeyRemap4MacBook_bridge::RequestType type, void* request, uint32_t requestsize, void* reply, uint32_t replysize)
  {
    if (! lock_) { return EIO; }

    IOLockWrapper::ScopedLock lk(lock_);

    socket_t socket;
    if (! makeSocket(socket)) {
      return EIO;
    }

    if (! connectSocket(socket)) {
      releaseSocket(socket);
      return EIO;
    }

    // ----------------------------------------
    struct msghdr msg;
    memset(&msg, 0, sizeof(msg));

    struct iovec aiov[3];
    size_t iolen;
    aiov[0].iov_base = reinterpret_cast<caddr_t>(&type);
    aiov[0].iov_len = sizeof(type);
    if (requestsize <= 0) {
      msg.msg_iovlen = 1;
    } else {
      aiov[1].iov_base = reinterpret_cast<caddr_t>(&requestsize);
      aiov[1].iov_len = sizeof(requestsize);
      aiov[2].iov_base = reinterpret_cast<caddr_t>(request);
      aiov[2].iov_len = requestsize;
      msg.msg_iovlen = 3;
    }
    msg.msg_iov = aiov;

    int error = sock_send(socket, &msg, 0, &iolen);
    if (error) {
      printf("KeyRemap4MacBook_client::sendmsg sock_send failed(%d)\n", error);
      releaseSocket(socket);
      return error;
    }

    // ----------------------------------------
    memset(&msg, 0, sizeof(msg));

    int result = -1;
    aiov[0].iov_base = reinterpret_cast<caddr_t>(&result);
    aiov[0].iov_len = sizeof(result);
    aiov[1].iov_base = reinterpret_cast<caddr_t>(reply);
    aiov[1].iov_len = replysize;
    msg.msg_iov = aiov;
    msg.msg_iovlen = (replysize == 0 ? 1 : 2);

    error = sock_receive(socket, &msg, MSG_WAITALL, &iolen);
    if (error) {
      printf("KeyRemap4MacBook_client::sendmsg sock_receive failed(%d)\n", error);
    }

    releaseSocket(socket);
    if (error) {
      return error;
    }

    if (result) {
      printf("KeyRemap4MacBook_client::sendmsg error result (%d)\n", result);
    }
    return result;
  }
}
<commit_msg>update sendmsg @ kext<commit_after>extern "C" {
#include <sys/systm.h>
#include <sys/un.h>
#include <sys/kpi_socket.h>
errno_t sock_nointerrupt(socket_t so, int on);
}
#include "base.hpp"
#include "Client.hpp"
#include "Config.hpp"
#include "IOLockWrapper.hpp"

namespace org_pqrs_KeyRemap4MacBook {
  namespace {
    struct sockaddr_un sockaddr_;
    bool sockaddr_available_ = false;
    IOLock* lock_ = NULL;

    void
    releaseSocket(socket_t& socket)
    {
      sock_shutdown(socket, SHUT_RDWR);
      sock_close(socket);
    }

    bool
    makeSocket(socket_t& socket)
    {
      int error = sock_socket(PF_LOCAL, SOCK_STREAM, 0, NULL, NULL, &socket);
      if (error) {
        printf("[KeyRemap4MacBook ERROR] sock_socket failed(%d)\n", error);
        return false;
      }

      // ----------------------------------------
      struct timeval tv;
      tv.tv_sec = KeyRemap4MacBook_client::TIMEOUT_SECOND;
      tv.tv_usec = KeyRemap4MacBook_client::TIMEOUT_MICROSECOND;

      error = sock_setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval));
      if (error) {
        printf("[KeyRemap4MacBook ERROR] sock_setsockopt failed(%d)\n", error);
        goto error;
      }

      error = sock_setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(struct timeval));
      if (error) {
        printf("[KeyRemap4MacBook ERROR] sock_setsockopt failed(%d)\n", error);
        goto error;
      }

      return true;

    error:
      releaseSocket(socket);
      printf("KeyRemap4MacBook_client makeSocket failed(%d)\n", error);

      return false;
    }

    bool
    connectSocket(socket_t& socket)
    {
      if (! sockaddr_available_) return false;

      errno_t error = sock_connect(socket, reinterpret_cast<const sockaddr*>(&sockaddr_), 0);
      if (error) {
#if 0
        // the connection failure is no problem because a server does not start at login window.
        printf("[KeyRemap4MacBook ERROR] sock_connect failed(%d)\n", error);
#endif
        return false;
      }
      error = sock_nointerrupt(socket, TRUE);
      if (error) {
        printf("[KeyRemap4MacBook ERROR] sock_nointerrupt failed(%d)\n", error);
        return false;
      }

      return true;
    }
  }

  void
  KeyRemap4MacBook_client::initialize(void)
  {
    lock_ = IOLockWrapper::alloc();
    refreshSockAddr();
  }

  void
  KeyRemap4MacBook_client::terminate(void)
  {
    if (lock_) {
      IOLockWrapper::free(lock_);
    }
  }

  void
  KeyRemap4MacBook_client::refreshSockAddr(void)
  {
    if (! lock_) return;
    IOLockWrapper::ScopedLock lk(lock_);

    if (config.socket_path[0] == '\0') {
      sockaddr_available_ = false;
    } else {
      sockaddr_available_ = true;

      memset(&sockaddr_, 0, sizeof(sockaddr_));
      sockaddr_.sun_len = sizeof(sockaddr_);
      sockaddr_.sun_family = AF_UNIX;
      strlcpy(sockaddr_.sun_path, config.socket_path, sizeof(sockaddr_.sun_path) - 8);
    }
  }

  int
  KeyRemap4MacBook_client::sendmsg(KeyRemap4MacBook_bridge::RequestType type, void* request, uint32_t requestsize, void* reply, uint32_t replysize)
  {
    if (! lock_) { return EIO; }

    IOLockWrapper::ScopedLock lk(lock_);

    // ------------------------------------------------------------
    int result = 0;
    int error = 0;
    socket_t socket;
    bool isMakeSocket = false;

    if (! makeSocket(socket)) {
      result = EIO;
      goto finish;
    }
    isMakeSocket = true;

    if (! connectSocket(socket)) {
      result = EIO;
      goto finish;
    }

    // ----------------------------------------
    struct msghdr msg;
    memset(&msg, 0, sizeof(msg));

    struct iovec aiov[3];
    size_t iolen;
    aiov[0].iov_base = reinterpret_cast<caddr_t>(&type);
    aiov[0].iov_len = sizeof(type);
    if (requestsize <= 0) {
      msg.msg_iovlen = 1;
    } else {
      aiov[1].iov_base = reinterpret_cast<caddr_t>(&requestsize);
      aiov[1].iov_len = sizeof(requestsize);
      aiov[2].iov_base = reinterpret_cast<caddr_t>(request);
      aiov[2].iov_len = requestsize;
      msg.msg_iovlen = 3;
    }
    msg.msg_iov = aiov;

    error = sock_send(socket, &msg, 0, &iolen);
    if (error) {
      printf("KeyRemap4MacBook_client::sendmsg sock_send failed(%d)\n", error);
      result = error;
      goto finish;
    }

    // ----------------------------------------
    if (replysize > 0) {
      memset(&msg, 0, sizeof(msg));

      uint32_t status = -1;
      aiov[0].iov_base = reinterpret_cast<caddr_t>(&status);
      aiov[0].iov_len = sizeof(status);
      aiov[1].iov_base = reinterpret_cast<caddr_t>(reply);
      aiov[1].iov_len = replysize;
      msg.msg_iov = aiov;
      msg.msg_iovlen = 2;

      error = sock_receive(socket, &msg, MSG_WAITALL, &iolen);
      if (error) {
        printf("KeyRemap4MacBook_client::sendmsg sock_receive failed(%d)\n", error);
        result = error;
        goto finish;
      }
    }

  finish:
    if (isMakeSocket) {
      releaseSocket(socket);
    }
    if (result) {
      printf("KeyRemap4MacBook_client::sendmsg error result (%d)\n", result);
    }
    return result;
  }
}
<|endoftext|>


<commit_before>/*
 *
 * Copyright 2015 gRPC authors.
 *
 * 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.
 *
 */

/* Generic implementation of time calls. */

#include <grpc/support/port_platform.h>

#include <grpc/support/log.h>
#include <grpc/support/time.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>

int gpr_time_cmp(gpr_timespec a, gpr_timespec b) {
  int cmp = (a.tv_sec > b.tv_sec) - (a.tv_sec < b.tv_sec);
  GPR_ASSERT(a.clock_type == b.clock_type);
  if (cmp == 0 && a.tv_sec != INT64_MAX && a.tv_sec != INT64_MIN) {
    cmp = (a.tv_nsec > b.tv_nsec) - (a.tv_nsec < b.tv_nsec);
  }
  return cmp;
}

gpr_timespec gpr_time_min(gpr_timespec a, gpr_timespec b) {
  return gpr_time_cmp(a, b) < 0 ? a : b;
}

gpr_timespec gpr_time_max(gpr_timespec a, gpr_timespec b) {
  return gpr_time_cmp(a, b) > 0 ? a : b;
}

gpr_timespec gpr_time_0(gpr_clock_type type) {
  gpr_timespec out;
  out.tv_sec = 0;
  out.tv_nsec = 0;
  out.clock_type = type;
  return out;
}

gpr_timespec gpr_inf_future(gpr_clock_type type) {
  gpr_timespec out;
  out.tv_sec = INT64_MAX;
  out.tv_nsec = 0;
  out.clock_type = type;
  return out;
}

gpr_timespec gpr_inf_past(gpr_clock_type type) {
  gpr_timespec out;
  out.tv_sec = INT64_MIN;
  out.tv_nsec = 0;
  out.clock_type = type;
  return out;
}

static gpr_timespec to_seconds_from_sub_second_time(int64_t time_in_units,
                                                    int64_t units_per_sec,
                                                    gpr_clock_type type) {
  gpr_timespec out;
  if (time_in_units == INT64_MAX) {
    out = gpr_inf_future(type);
  } else if (time_in_units == INT64_MIN) {
    out = gpr_inf_past(type);
  } else {
    if (time_in_units >= 0) {
      out.tv_sec = time_in_units / units_per_sec;
    } else {
      out.tv_sec = (-((units_per_sec - 1) - (time_in_units + units_per_sec)) /
                    units_per_sec) -
                   1;
    }
    out.tv_nsec =
        static_cast<int32_t>((time_in_units - out.tv_sec * units_per_sec) *
                             GPR_NS_PER_SEC / units_per_sec);
    out.clock_type = type;
  }
  return out;
}

static gpr_timespec to_seconds_from_above_second_time(int64_t time_in_units,
                                                      int64_t secs_per_unit,
                                                      gpr_clock_type type) {
  gpr_timespec out;
  if (time_in_units >= INT64_MAX / secs_per_unit) {
    out = gpr_inf_future(type);
  } else if (time_in_units <= INT64_MIN / secs_per_unit) {
    out = gpr_inf_past(type);
  } else {
    out.tv_sec = time_in_units * secs_per_unit;
    out.tv_nsec = 0;
    out.clock_type = type;
  }
  return out;
}

gpr_timespec gpr_time_from_nanos(int64_t ns, gpr_clock_type type) {
  return to_seconds_from_sub_second_time(ns, GPR_NS_PER_SEC, type);
}

gpr_timespec gpr_time_from_micros(int64_t us, gpr_clock_type type) {
  return to_seconds_from_sub_second_time(us, GPR_US_PER_SEC, type);
}

gpr_timespec gpr_time_from_millis(int64_t ms, gpr_clock_type type) {
  return to_seconds_from_sub_second_time(ms, GPR_MS_PER_SEC, type);
}

gpr_timespec gpr_time_from_seconds(int64_t s, gpr_clock_type type) {
  return to_seconds_from_sub_second_time(s, 1, type);
}

gpr_timespec gpr_time_from_minutes(int64_t m, gpr_clock_type type) {
  return to_seconds_from_above_second_time(m, 60, type);
}

gpr_timespec gpr_time_from_hours(int64_t h, gpr_clock_type type) {
  return to_seconds_from_above_second_time(h, 3600, type);
}

gpr_timespec gpr_time_add(gpr_timespec a, gpr_timespec b) {
  gpr_timespec sum;
  int64_t inc = 0;
  GPR_ASSERT(b.clock_type == GPR_TIMESPAN);
  // tv_nsec in a timespan is always +ve. -ve timespan is represented as (-ve
  // tv_sec, +ve tv_nsec). For example, timespan = -2.5 seconds is represented
  // as {-3, 5e8, GPR_TIMESPAN}
  GPR_ASSERT(b.tv_nsec >= 0);
  sum.clock_type = a.clock_type;
  sum.tv_nsec = a.tv_nsec + b.tv_nsec;
  if (sum.tv_nsec >= GPR_NS_PER_SEC) {
    sum.tv_nsec -= GPR_NS_PER_SEC;
    inc++;
  }
  if (a.tv_sec == INT64_MAX || a.tv_sec == INT64_MIN) {
    sum = a;
  } else if (b.tv_sec == INT64_MAX ||
             (b.tv_sec >= 0 && a.tv_sec >= INT64_MAX - b.tv_sec)) {
    sum = gpr_inf_future(sum.clock_type);
  } else if (b.tv_sec == INT64_MIN ||
             (b.tv_sec <= 0 && a.tv_sec <= INT64_MIN - b.tv_sec)) {
    sum = gpr_inf_past(sum.clock_type);
  } else {
    sum.tv_sec = a.tv_sec + b.tv_sec;
    if (inc != 0 && sum.tv_sec == INT64_MAX - 1) {
      sum = gpr_inf_future(sum.clock_type);
    } else {
      sum.tv_sec += inc;
    }
  }
  return sum;
}

gpr_timespec gpr_time_sub(gpr_timespec a, gpr_timespec b) {
  gpr_timespec diff;
  int64_t dec = 0;
  if (b.clock_type == GPR_TIMESPAN) {
    diff.clock_type = a.clock_type;
    // tv_nsec in a timespan is always +ve. -ve timespan is represented as (-ve
    // tv_sec, +ve tv_nsec). For example, timespan = -2.5 seconds is represented
    // as {-3, 5e8, GPR_TIMESPAN}
    GPR_ASSERT(b.tv_nsec >= 0);
  } else {
    GPR_ASSERT(a.clock_type == b.clock_type);
    diff.clock_type = GPR_TIMESPAN;
  }
  diff.tv_nsec = a.tv_nsec - b.tv_nsec;
  if (diff.tv_nsec < 0) {
    diff.tv_nsec += GPR_NS_PER_SEC;
    dec++;
  }
  if (a.tv_sec == INT64_MAX || a.tv_sec == INT64_MIN) {
    diff = a;
  } else if (b.tv_sec == INT64_MIN ||
             (b.tv_sec <= 0 && a.tv_sec >= INT64_MAX + b.tv_sec)) {
    diff = gpr_inf_future(GPR_CLOCK_REALTIME);
  } else if (b.tv_sec == INT64_MAX ||
             (b.tv_sec >= 0 && a.tv_sec <= INT64_MIN + b.tv_sec)) {
    diff = gpr_inf_past(GPR_CLOCK_REALTIME);
  } else {
    diff.tv_sec = a.tv_sec - b.tv_sec;
    if (dec != 0 && diff.tv_sec == INT64_MIN + 1) {
      diff = gpr_inf_past(GPR_CLOCK_REALTIME);
    } else {
      diff.tv_sec -= dec;
    }
  }
  return diff;
}

int gpr_time_similar(gpr_timespec a, gpr_timespec b, gpr_timespec threshold) {
  int cmp_ab;

  GPR_ASSERT(a.clock_type == b.clock_type);
  GPR_ASSERT(threshold.clock_type == GPR_TIMESPAN);

  cmp_ab = gpr_time_cmp(a, b);
  if (cmp_ab == 0) return 1;
  if (cmp_ab < 0) {
    return gpr_time_cmp(gpr_time_sub(b, a), threshold) <= 0;
  } else {
    return gpr_time_cmp(gpr_time_sub(a, b), threshold) <= 0;
  }
}

int32_t gpr_time_to_millis(gpr_timespec t) {
  if (t.tv_sec >= 2147483) {
    if (t.tv_sec == 2147483 && t.tv_nsec < 648 * GPR_NS_PER_MS) {
      return 2147483 * GPR_MS_PER_SEC + t.tv_nsec / GPR_NS_PER_MS;
    }
    return 2147483647;
  } else if (t.tv_sec <= -2147483) {
    /* TODO(ctiller): correct handling here (it's so far in the past do we
       care?) */
    return -2147483647;
  } else {
    return static_cast<int32_t>(t.tv_sec * GPR_MS_PER_SEC +
                                t.tv_nsec / GPR_NS_PER_MS);
  }
}

double gpr_timespec_to_micros(gpr_timespec t) {
  return static_cast<double>(t.tv_sec) * GPR_US_PER_SEC + t.tv_nsec * 1e-3;
}

gpr_timespec gpr_convert_clock_type(gpr_timespec t, gpr_clock_type clock_type) {
  if (t.clock_type == clock_type) {
    return t;
  }

  if (t.tv_sec == INT64_MAX || t.tv_sec == INT64_MIN) {
    t.clock_type = clock_type;
    return t;
  }

  if (clock_type == GPR_TIMESPAN) {
    return gpr_time_sub(t, gpr_now(t.clock_type));
  }

  if (t.clock_type == GPR_TIMESPAN) {
    return gpr_time_add(gpr_now(clock_type), t);
  }

  return gpr_time_add(gpr_now(clock_type),
                      gpr_time_sub(t, gpr_now(t.clock_type)));
}
<commit_msg>Add note to gpr_convert_clock_type<commit_after>/*
 *
 * Copyright 2015 gRPC authors.
 *
 * 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.
 *
 */

/* Generic implementation of time calls. */

#include <grpc/support/port_platform.h>

#include <grpc/support/log.h>
#include <grpc/support/time.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>

int gpr_time_cmp(gpr_timespec a, gpr_timespec b) {
  int cmp = (a.tv_sec > b.tv_sec) - (a.tv_sec < b.tv_sec);
  GPR_ASSERT(a.clock_type == b.clock_type);
  if (cmp == 0 && a.tv_sec != INT64_MAX && a.tv_sec != INT64_MIN) {
    cmp = (a.tv_nsec > b.tv_nsec) - (a.tv_nsec < b.tv_nsec);
  }
  return cmp;
}

gpr_timespec gpr_time_min(gpr_timespec a, gpr_timespec b) {
  return gpr_time_cmp(a, b) < 0 ? a : b;
}

gpr_timespec gpr_time_max(gpr_timespec a, gpr_timespec b) {
  return gpr_time_cmp(a, b) > 0 ? a : b;
}

gpr_timespec gpr_time_0(gpr_clock_type type) {
  gpr_timespec out;
  out.tv_sec = 0;
  out.tv_nsec = 0;
  out.clock_type = type;
  return out;
}

gpr_timespec gpr_inf_future(gpr_clock_type type) {
  gpr_timespec out;
  out.tv_sec = INT64_MAX;
  out.tv_nsec = 0;
  out.clock_type = type;
  return out;
}

gpr_timespec gpr_inf_past(gpr_clock_type type) {
  gpr_timespec out;
  out.tv_sec = INT64_MIN;
  out.tv_nsec = 0;
  out.clock_type = type;
  return out;
}

static gpr_timespec to_seconds_from_sub_second_time(int64_t time_in_units,
                                                    int64_t units_per_sec,
                                                    gpr_clock_type type) {
  gpr_timespec out;
  if (time_in_units == INT64_MAX) {
    out = gpr_inf_future(type);
  } else if (time_in_units == INT64_MIN) {
    out = gpr_inf_past(type);
  } else {
    if (time_in_units >= 0) {
      out.tv_sec = time_in_units / units_per_sec;
    } else {
      out.tv_sec = (-((units_per_sec - 1) - (time_in_units + units_per_sec)) /
                    units_per_sec) -
                   1;
    }
    out.tv_nsec =
        static_cast<int32_t>((time_in_units - out.tv_sec * units_per_sec) *
                             GPR_NS_PER_SEC / units_per_sec);
    out.clock_type = type;
  }
  return out;
}

static gpr_timespec to_seconds_from_above_second_time(int64_t time_in_units,
                                                      int64_t secs_per_unit,
                                                      gpr_clock_type type) {
  gpr_timespec out;
  if (time_in_units >= INT64_MAX / secs_per_unit) {
    out = gpr_inf_future(type);
  } else if (time_in_units <= INT64_MIN / secs_per_unit) {
    out = gpr_inf_past(type);
  } else {
    out.tv_sec = time_in_units * secs_per_unit;
    out.tv_nsec = 0;
    out.clock_type = type;
  }
  return out;
}

gpr_timespec gpr_time_from_nanos(int64_t ns, gpr_clock_type type) {
  return to_seconds_from_sub_second_time(ns, GPR_NS_PER_SEC, type);
}

gpr_timespec gpr_time_from_micros(int64_t us, gpr_clock_type type) {
  return to_seconds_from_sub_second_time(us, GPR_US_PER_SEC, type);
}

gpr_timespec gpr_time_from_millis(int64_t ms, gpr_clock_type type) {
  return to_seconds_from_sub_second_time(ms, GPR_MS_PER_SEC, type);
}

gpr_timespec gpr_time_from_seconds(int64_t s, gpr_clock_type type) {
  return to_seconds_from_sub_second_time(s, 1, type);
}

gpr_timespec gpr_time_from_minutes(int64_t m, gpr_clock_type type) {
  return to_seconds_from_above_second_time(m, 60, type);
}

gpr_timespec gpr_time_from_hours(int64_t h, gpr_clock_type type) {
  return to_seconds_from_above_second_time(h, 3600, type);
}

gpr_timespec gpr_time_add(gpr_timespec a, gpr_timespec b) {
  gpr_timespec sum;
  int64_t inc = 0;
  GPR_ASSERT(b.clock_type == GPR_TIMESPAN);
  // tv_nsec in a timespan is always +ve. -ve timespan is represented as (-ve
  // tv_sec, +ve tv_nsec). For example, timespan = -2.5 seconds is represented
  // as {-3, 5e8, GPR_TIMESPAN}
  GPR_ASSERT(b.tv_nsec >= 0);
  sum.clock_type = a.clock_type;
  sum.tv_nsec = a.tv_nsec + b.tv_nsec;
  if (sum.tv_nsec >= GPR_NS_PER_SEC) {
    sum.tv_nsec -= GPR_NS_PER_SEC;
    inc++;
  }
  if (a.tv_sec == INT64_MAX || a.tv_sec == INT64_MIN) {
    sum = a;
  } else if (b.tv_sec == INT64_MAX ||
             (b.tv_sec >= 0 && a.tv_sec >= INT64_MAX - b.tv_sec)) {
    sum = gpr_inf_future(sum.clock_type);
  } else if (b.tv_sec == INT64_MIN ||
             (b.tv_sec <= 0 && a.tv_sec <= INT64_MIN - b.tv_sec)) {
    sum = gpr_inf_past(sum.clock_type);
  } else {
    sum.tv_sec = a.tv_sec + b.tv_sec;
    if (inc != 0 && sum.tv_sec == INT64_MAX - 1) {
      sum = gpr_inf_future(sum.clock_type);
    } else {
      sum.tv_sec += inc;
    }
  }
  return sum;
}

gpr_timespec gpr_time_sub(gpr_timespec a, gpr_timespec b) {
  gpr_timespec diff;
  int64_t dec = 0;
  if (b.clock_type == GPR_TIMESPAN) {
    diff.clock_type = a.clock_type;
    // tv_nsec in a timespan is always +ve. -ve timespan is represented as (-ve
    // tv_sec, +ve tv_nsec). For example, timespan = -2.5 seconds is represented
    // as {-3, 5e8, GPR_TIMESPAN}
    GPR_ASSERT(b.tv_nsec >= 0);
  } else {
    GPR_ASSERT(a.clock_type == b.clock_type);
    diff.clock_type = GPR_TIMESPAN;
  }
  diff.tv_nsec = a.tv_nsec - b.tv_nsec;
  if (diff.tv_nsec < 0) {
    diff.tv_nsec += GPR_NS_PER_SEC;
    dec++;
  }
  if (a.tv_sec == INT64_MAX || a.tv_sec == INT64_MIN) {
    diff = a;
  } else if (b.tv_sec == INT64_MIN ||
             (b.tv_sec <= 0 && a.tv_sec >= INT64_MAX + b.tv_sec)) {
    diff = gpr_inf_future(GPR_CLOCK_REALTIME);
  } else if (b.tv_sec == INT64_MAX ||
             (b.tv_sec >= 0 && a.tv_sec <= INT64_MIN + b.tv_sec)) {
    diff = gpr_inf_past(GPR_CLOCK_REALTIME);
  } else {
    diff.tv_sec = a.tv_sec - b.tv_sec;
    if (dec != 0 && diff.tv_sec == INT64_MIN + 1) {
      diff = gpr_inf_past(GPR_CLOCK_REALTIME);
    } else {
      diff.tv_sec -= dec;
    }
  }
  return diff;
}

int gpr_time_similar(gpr_timespec a, gpr_timespec b, gpr_timespec threshold) {
  int cmp_ab;

  GPR_ASSERT(a.clock_type == b.clock_type);
  GPR_ASSERT(threshold.clock_type == GPR_TIMESPAN);

  cmp_ab = gpr_time_cmp(a, b);
  if (cmp_ab == 0) return 1;
  if (cmp_ab < 0) {
    return gpr_time_cmp(gpr_time_sub(b, a), threshold) <= 0;
  } else {
    return gpr_time_cmp(gpr_time_sub(a, b), threshold) <= 0;
  }
}

int32_t gpr_time_to_millis(gpr_timespec t) {
  if (t.tv_sec >= 2147483) {
    if (t.tv_sec == 2147483 && t.tv_nsec < 648 * GPR_NS_PER_MS) {
      return 2147483 * GPR_MS_PER_SEC + t.tv_nsec / GPR_NS_PER_MS;
    }
    return 2147483647;
  } else if (t.tv_sec <= -2147483) {
    /* TODO(ctiller): correct handling here (it's so far in the past do we
       care?) */
    return -2147483647;
  } else {
    return static_cast<int32_t>(t.tv_sec * GPR_MS_PER_SEC +
                                t.tv_nsec / GPR_NS_PER_MS);
  }
}

double gpr_timespec_to_micros(gpr_timespec t) {
  return static_cast<double>(t.tv_sec) * GPR_US_PER_SEC + t.tv_nsec * 1e-3;
}

gpr_timespec gpr_convert_clock_type(gpr_timespec t, gpr_clock_type clock_type) {
  if (t.clock_type == clock_type) {
    return t;
  }

  if (t.tv_sec == INT64_MAX || t.tv_sec == INT64_MIN) {
    t.clock_type = clock_type;
    return t;
  }

  if (clock_type == GPR_TIMESPAN) {
    return gpr_time_sub(t, gpr_now(t.clock_type));
  }

  if (t.clock_type == GPR_TIMESPAN) {
    return gpr_time_add(gpr_now(clock_type), t);
  }

  // If the given input hits this code, the same result is not guaranteed for
  // the same input because it relies on `gpr_now` to calculate the difference
  // between two different clocks. Please be careful when you want to use this
  // function in unit tests. (e.g. https://github.com/grpc/grpc/pull/22655)
  return gpr_time_add(gpr_now(clock_type),
                      gpr_time_sub(t, gpr_now(t.clock_type)));
}
<|endoftext|>