<commit_before>/*
 * Copyright 2007-2018 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * 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.
 *
 * 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
 * FOUNDATION 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 "Input.hxx"
#include "Error.hxx"
#include "event/SocketEvent.hxx"
#include "istream/istream.hxx"
#include "istream/UnusedPtr.hxx"
#include "istream/Result.hxx"
#include "istream/Bucket.hxx"
#include "pool/pool.hxx"
#include "fb_pool.hxx"
#include "SliceFifoBuffer.hxx"
#include "io/Buffered.hxx"
#include "system/Error.hxx"
#include "util/ScopeExit.hxx"
#include "util/Exception.hxx"

#include <was/protocol.h>

#include <errno.h>
#include <string.h>
#include <unistd.h>

class WasInput final : Istream {
	FileDescriptor fd;
	SocketEvent event;

	WasInputHandler &handler;

	SliceFifoBuffer buffer;

	uint64_t received = 0, length;

	bool enabled = false;

	bool closed = false, known_length = false;

public:
	WasInput(struct pool &p, EventLoop &event_loop, FileDescriptor _fd,
		 WasInputHandler &_handler) noexcept
		:Istream(p), fd(_fd),
		 event(event_loop, BIND_THIS_METHOD(EventCallback),
		       SocketDescriptor::FromFileDescriptor(fd)),
		 handler(_handler) {
	}

	void Free(std::exception_ptr ep) noexcept;

	using Istream::Destroy;

	void DestroyUnused() noexcept {
		assert(!HasHandler());
		assert(!closed);
		assert(!buffer.IsDefined());

		Destroy();
	}

	UnusedIstreamPtr Enable() noexcept {
		assert(!enabled);
		enabled = true;
		ScheduleRead();
		return UnusedIstreamPtr(this);
	}

	void Disable() noexcept {
		event.Cancel();
	}

	bool SetLength(uint64_t _length) noexcept;
	void PrematureThrow(uint64_t _length);
	bool Premature(uint64_t _length) noexcept;

private:
	bool CanRelease() const {
		return known_length && received == length;
	}

	/**
	 * @return false if the #WasInput has been destroyed
	 */
	bool ReleasePipe() noexcept {
		assert(fd.IsDefined());
		fd.SetUndefined();
		event.Cancel();

		return handler.WasInputRelease();
	}

	/**
	 * @return false if the #WasInput has been destroyed
	 */
	bool CheckReleasePipe() noexcept {
		return !CanRelease() || ReleasePipe();
	}

	void ScheduleRead() noexcept {
		assert(fd.IsDefined());
		assert(!buffer.IsDefined() || !buffer.IsFull());

		event.ScheduleRead();
	}

	void AbortError(std::exception_ptr ep) noexcept {
		buffer.FreeIfDefined();
		event.Cancel();

		/* protect against recursive Free() call within the istream
		   handler */
		closed = true;

		handler.WasInputError();
		DestroyError(ep);
	}

	void AbortError(const char *msg) noexcept {
		AbortError(std::make_exception_ptr(WasProtocolError(msg)));
	}

	void Eof() noexcept {
		assert(known_length);
		assert(received == length);
		assert(!buffer.IsDefined());

		event.Cancel();

		handler.WasInputEof();
		DestroyEof();
	}

	bool CheckEof() noexcept {
		if (CanRelease() && buffer.empty()) {
			Eof();
			return true;
		} else
			return false;
	}

	/**
	 * Consume data from the input buffer.
	 *
	 * @return false if the handler blocks or if this object has been
	 * destroyed
	 */
	bool SubmitBuffer() noexcept {
		auto r = buffer.Read();
		if (!r.empty()) {
			size_t nbytes = InvokeData(r.data, r.size);
			if (nbytes == 0)
				return false;

			buffer.Consume(nbytes);
			buffer.FreeIfEmpty();
		}

		if (CheckEof())
			return false;

		return true;
	}

	/*
	 * socket i/o
	 *
	 */

	/**
	 * Throws on error.
	 */
	void ReadToBuffer();

	bool TryBuffered() noexcept;
	bool TryDirect() noexcept;

	void TryRead() noexcept {
		if (CheckDirect(FdType::FD_PIPE)) {
			if (SubmitBuffer() && buffer.empty())
				TryDirect();
		} else {
			TryBuffered();
		}
	}

	void EventCallback(unsigned events) noexcept;

	/* virtual methods from class Istream */

	off_t _GetAvailable(bool partial) noexcept override {
		if (known_length)
			return length - received + buffer.GetAvailable();
		else if (partial)
			return buffer.GetAvailable();
		else
			return -1;
	}

	void _Read() noexcept override {
		event.Cancel();

		if (SubmitBuffer())
			TryRead();
	}

	void _FillBucketList(IstreamBucketList &list) override;
	size_t _ConsumeBucketList(size_t nbytes) noexcept override;

	void _Close() noexcept override {
		buffer.FreeIfDefined();
		event.Cancel();

		/* protect against recursive Free() call within the istream
		   handler */
		closed = true;

		handler.WasInputClose(received);

		Destroy();
	}
};

void
WasInput::ReadToBuffer()
{
	buffer.AllocateIfNull(fb_pool_get());

	size_t max_length = 4096;
	if (known_length) {
		uint64_t rest = length - received;
		if (rest < (uint64_t)max_length)
			max_length = rest;

		if (max_length == 0)
			/* all the data we need is already in the buffer */
			return;
	}

	ssize_t nbytes = read_to_buffer(fd.Get(), buffer, max_length);
	assert(nbytes != -2);

	if (nbytes == 0)
		throw WasProtocolError("server closed the data connection");

	if (nbytes < 0) {
		const int e = errno;

		if (e == EAGAIN) {
			buffer.FreeIfEmpty();
			ScheduleRead();
			return;
		}

		throw MakeErrno(e, "read error on WAS data connection");
	}

	received += nbytes;

	if (buffer.IsFull())
		event.CancelRead();
}

inline bool
WasInput::TryBuffered() noexcept
{
	if (fd.IsDefined()) {
		try {
			ReadToBuffer();
		} catch (...) {
			AbortError(std::current_exception());
			return false;
		}

		if (!CheckReleasePipe())
			return false;
	}

	if (SubmitBuffer()) {
		assert(!buffer.IsDefinedAndFull());

		if (fd.IsDefined())
			ScheduleRead();
	}

	return true;
}

inline bool
WasInput::TryDirect() noexcept
{
	assert(buffer.empty());
	assert(!buffer.IsDefined());

	size_t max_length = 0x1000000;
	if (known_length) {
		uint64_t rest = length - received;
		if (rest < (uint64_t)max_length)
			max_length = rest;
	}

	ssize_t nbytes = InvokeDirect(FdType::FD_PIPE, fd.Get(), max_length);
	if (nbytes == ISTREAM_RESULT_BLOCKING) {
		event.CancelRead();
		return false;
	}

	if (nbytes == ISTREAM_RESULT_EOF || nbytes == ISTREAM_RESULT_CLOSED)
		return false;

	if (nbytes < 0) {
		const int e = errno;

		if (e == EAGAIN) {
			ScheduleRead();
			return false;
		}

		AbortError(std::make_exception_ptr(MakeErrno(e,
							     "read error on WAS data connection")));
		return false;
	}

	received += nbytes;

	if (!CheckReleasePipe())
		return false;

	if (CheckEof())
		return false;

	ScheduleRead();
	return true;
}

/*
 * libevent callback
 *
 */

inline void
WasInput::EventCallback(unsigned) noexcept
{
	assert(fd.IsDefined());

	TryRead();
}

/*
 * constructor
 *
 */

WasInput *
was_input_new(struct pool &pool, EventLoop &event_loop, FileDescriptor fd,
	      WasInputHandler &handler) noexcept
{
	assert(fd.IsDefined());

	return NewFromPool<WasInput>(pool, pool, event_loop, fd,
				     handler);
}

inline void
WasInput::Free(std::exception_ptr ep) noexcept
{
	assert(ep || closed || !enabled);

	buffer.FreeIfDefined();

	event.Cancel();

	if (!closed && enabled)
		DestroyError(ep);
}

void
was_input_free(WasInput *input, std::exception_ptr ep) noexcept
{
	input->Free(ep);
}

void
was_input_free_unused(WasInput *input) noexcept
{
	input->DestroyUnused();
}

UnusedIstreamPtr
was_input_enable(WasInput &input) noexcept
{
	return input.Enable();
}

void
was_input_disable(WasInput &input) noexcept
{
	input.Disable();
}

inline bool
WasInput::SetLength(uint64_t _length) noexcept
{
	if (known_length) {
		if (_length == length)
			return true;

		// TODO: don't invoke Istream::DestroyError() if not yet enabled
		AbortError("wrong input length announced");
		return false;
	}

	if (_length < received) {
		/* this length must be bogus, because we already received more than that from the socket */
		AbortError("announced length is too small");
		return false;
	}

	length = _length;
	known_length = true;

	if (!CheckReleasePipe())
		return false;

	if (enabled && CheckEof())
		return false;

	return true;
}

bool
was_input_set_length(WasInput *input, uint64_t length) noexcept
{
	return input->SetLength(length);
}

void
WasInput::PrematureThrow(uint64_t _length)
{
	buffer.FreeIfDefined();
	event.Cancel();

	if (known_length && _length > length)
		throw WasProtocolError("announced premature length is too large");

	if (_length < received)
		throw WasProtocolError("announced premature length is too small");

	uint64_t remaining = _length - received;

	while (remaining > 0) {
		uint8_t discard_buffer[4096];
		size_t size = std::min(remaining, uint64_t(sizeof(discard_buffer)));
		ssize_t nbytes = fd.Read(discard_buffer, size);
		if (nbytes < 0)
			throw NestException(std::make_exception_ptr(MakeErrno("Read error")),
					    WasError("read error on WAS data connection"));

		if (nbytes == 0)
			throw WasProtocolError("server closed the WAS data connection");

		remaining -= nbytes;
	}
}

inline bool
WasInput::Premature(uint64_t _length) noexcept
{
	try {
		PrematureThrow(_length);
	} catch (...) {
		/* protocol - notify our WasInputHandler */
		handler.WasInputError();
		DestroyError(std::current_exception());
		return false;
	}

	/* recovery was successful - let our IstreamHandler know that
	   the stream was closed prematurely and return success */
	DestroyError(std::make_exception_ptr(WasProtocolError("premature end of WAS response")));
	return true;
}

bool
was_input_premature(WasInput *input, uint64_t length) noexcept
{
	return input->Premature(length);
}

void
was_input_premature_throw(WasInput *input, uint64_t length)
{
	AtScopeExit(input) { input->Destroy(); };
	input->PrematureThrow(length);
	throw WasProtocolError("premature end of WAS response");
}

void
WasInput::_FillBucketList(IstreamBucketList &list)
{
	auto r = buffer.Read();
	if (r.empty()) {
		if (!fd.IsDefined())
			return;

		ReadToBuffer();

		if (!CheckReleasePipe())
			// TODO: deal with this condition properly or improve error message
			throw std::runtime_error("WAS peer failed");

		r = buffer.Read();
		if (r.empty()) {
			list.SetMore();
			return;
		}
	}

	list.Push(r.ToVoid());

	if (!known_length || received < length)
		list.SetMore();
}

size_t
WasInput::_ConsumeBucketList(size_t nbytes) noexcept
{
	size_t consumed = std::min(buffer.GetAvailable(), nbytes);

	buffer.Consume(consumed);
	buffer.FreeIfEmpty();

	Consumed(consumed);
	return consumed;
}
<commit_msg>was/Input: fix comment typo<commit_after>/*
 * Copyright 2007-2018 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * 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.
 *
 * 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
 * FOUNDATION 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 "Input.hxx"
#include "Error.hxx"
#include "event/SocketEvent.hxx"
#include "istream/istream.hxx"
#include "istream/UnusedPtr.hxx"
#include "istream/Result.hxx"
#include "istream/Bucket.hxx"
#include "pool/pool.hxx"
#include "fb_pool.hxx"
#include "SliceFifoBuffer.hxx"
#include "io/Buffered.hxx"
#include "system/Error.hxx"
#include "util/ScopeExit.hxx"
#include "util/Exception.hxx"

#include <was/protocol.h>

#include <errno.h>
#include <string.h>
#include <unistd.h>

class WasInput final : Istream {
	FileDescriptor fd;
	SocketEvent event;

	WasInputHandler &handler;

	SliceFifoBuffer buffer;

	uint64_t received = 0, length;

	bool enabled = false;

	bool closed = false, known_length = false;

public:
	WasInput(struct pool &p, EventLoop &event_loop, FileDescriptor _fd,
		 WasInputHandler &_handler) noexcept
		:Istream(p), fd(_fd),
		 event(event_loop, BIND_THIS_METHOD(EventCallback),
		       SocketDescriptor::FromFileDescriptor(fd)),
		 handler(_handler) {
	}

	void Free(std::exception_ptr ep) noexcept;

	using Istream::Destroy;

	void DestroyUnused() noexcept {
		assert(!HasHandler());
		assert(!closed);
		assert(!buffer.IsDefined());

		Destroy();
	}

	UnusedIstreamPtr Enable() noexcept {
		assert(!enabled);
		enabled = true;
		ScheduleRead();
		return UnusedIstreamPtr(this);
	}

	void Disable() noexcept {
		event.Cancel();
	}

	bool SetLength(uint64_t _length) noexcept;
	void PrematureThrow(uint64_t _length);
	bool Premature(uint64_t _length) noexcept;

private:
	bool CanRelease() const {
		return known_length && received == length;
	}

	/**
	 * @return false if the #WasInput has been destroyed
	 */
	bool ReleasePipe() noexcept {
		assert(fd.IsDefined());
		fd.SetUndefined();
		event.Cancel();

		return handler.WasInputRelease();
	}

	/**
	 * @return false if the #WasInput has been destroyed
	 */
	bool CheckReleasePipe() noexcept {
		return !CanRelease() || ReleasePipe();
	}

	void ScheduleRead() noexcept {
		assert(fd.IsDefined());
		assert(!buffer.IsDefined() || !buffer.IsFull());

		event.ScheduleRead();
	}

	void AbortError(std::exception_ptr ep) noexcept {
		buffer.FreeIfDefined();
		event.Cancel();

		/* protect against recursive Free() call within the istream
		   handler */
		closed = true;

		handler.WasInputError();
		DestroyError(ep);
	}

	void AbortError(const char *msg) noexcept {
		AbortError(std::make_exception_ptr(WasProtocolError(msg)));
	}

	void Eof() noexcept {
		assert(known_length);
		assert(received == length);
		assert(!buffer.IsDefined());

		event.Cancel();

		handler.WasInputEof();
		DestroyEof();
	}

	bool CheckEof() noexcept {
		if (CanRelease() && buffer.empty()) {
			Eof();
			return true;
		} else
			return false;
	}

	/**
	 * Consume data from the input buffer.
	 *
	 * @return false if the handler blocks or if this object has been
	 * destroyed
	 */
	bool SubmitBuffer() noexcept {
		auto r = buffer.Read();
		if (!r.empty()) {
			size_t nbytes = InvokeData(r.data, r.size);
			if (nbytes == 0)
				return false;

			buffer.Consume(nbytes);
			buffer.FreeIfEmpty();
		}

		if (CheckEof())
			return false;

		return true;
	}

	/*
	 * socket i/o
	 *
	 */

	/**
	 * Throws on error.
	 */
	void ReadToBuffer();

	bool TryBuffered() noexcept;
	bool TryDirect() noexcept;

	void TryRead() noexcept {
		if (CheckDirect(FdType::FD_PIPE)) {
			if (SubmitBuffer() && buffer.empty())
				TryDirect();
		} else {
			TryBuffered();
		}
	}

	void EventCallback(unsigned events) noexcept;

	/* virtual methods from class Istream */

	off_t _GetAvailable(bool partial) noexcept override {
		if (known_length)
			return length - received + buffer.GetAvailable();
		else if (partial)
			return buffer.GetAvailable();
		else
			return -1;
	}

	void _Read() noexcept override {
		event.Cancel();

		if (SubmitBuffer())
			TryRead();
	}

	void _FillBucketList(IstreamBucketList &list) override;
	size_t _ConsumeBucketList(size_t nbytes) noexcept override;

	void _Close() noexcept override {
		buffer.FreeIfDefined();
		event.Cancel();

		/* protect against recursive Free() call within the istream
		   handler */
		closed = true;

		handler.WasInputClose(received);

		Destroy();
	}
};

void
WasInput::ReadToBuffer()
{
	buffer.AllocateIfNull(fb_pool_get());

	size_t max_length = 4096;
	if (known_length) {
		uint64_t rest = length - received;
		if (rest < (uint64_t)max_length)
			max_length = rest;

		if (max_length == 0)
			/* all the data we need is already in the buffer */
			return;
	}

	ssize_t nbytes = read_to_buffer(fd.Get(), buffer, max_length);
	assert(nbytes != -2);

	if (nbytes == 0)
		throw WasProtocolError("server closed the data connection");

	if (nbytes < 0) {
		const int e = errno;

		if (e == EAGAIN) {
			buffer.FreeIfEmpty();
			ScheduleRead();
			return;
		}

		throw MakeErrno(e, "read error on WAS data connection");
	}

	received += nbytes;

	if (buffer.IsFull())
		event.CancelRead();
}

inline bool
WasInput::TryBuffered() noexcept
{
	if (fd.IsDefined()) {
		try {
			ReadToBuffer();
		} catch (...) {
			AbortError(std::current_exception());
			return false;
		}

		if (!CheckReleasePipe())
			return false;
	}

	if (SubmitBuffer()) {
		assert(!buffer.IsDefinedAndFull());

		if (fd.IsDefined())
			ScheduleRead();
	}

	return true;
}

inline bool
WasInput::TryDirect() noexcept
{
	assert(buffer.empty());
	assert(!buffer.IsDefined());

	size_t max_length = 0x1000000;
	if (known_length) {
		uint64_t rest = length - received;
		if (rest < (uint64_t)max_length)
			max_length = rest;
	}

	ssize_t nbytes = InvokeDirect(FdType::FD_PIPE, fd.Get(), max_length);
	if (nbytes == ISTREAM_RESULT_BLOCKING) {
		event.CancelRead();
		return false;
	}

	if (nbytes == ISTREAM_RESULT_EOF || nbytes == ISTREAM_RESULT_CLOSED)
		return false;

	if (nbytes < 0) {
		const int e = errno;

		if (e == EAGAIN) {
			ScheduleRead();
			return false;
		}

		AbortError(std::make_exception_ptr(MakeErrno(e,
							     "read error on WAS data connection")));
		return false;
	}

	received += nbytes;

	if (!CheckReleasePipe())
		return false;

	if (CheckEof())
		return false;

	ScheduleRead();
	return true;
}

/*
 * libevent callback
 *
 */

inline void
WasInput::EventCallback(unsigned) noexcept
{
	assert(fd.IsDefined());

	TryRead();
}

/*
 * constructor
 *
 */

WasInput *
was_input_new(struct pool &pool, EventLoop &event_loop, FileDescriptor fd,
	      WasInputHandler &handler) noexcept
{
	assert(fd.IsDefined());

	return NewFromPool<WasInput>(pool, pool, event_loop, fd,
				     handler);
}

inline void
WasInput::Free(std::exception_ptr ep) noexcept
{
	assert(ep || closed || !enabled);

	buffer.FreeIfDefined();

	event.Cancel();

	if (!closed && enabled)
		DestroyError(ep);
}

void
was_input_free(WasInput *input, std::exception_ptr ep) noexcept
{
	input->Free(ep);
}

void
was_input_free_unused(WasInput *input) noexcept
{
	input->DestroyUnused();
}

UnusedIstreamPtr
was_input_enable(WasInput &input) noexcept
{
	return input.Enable();
}

void
was_input_disable(WasInput &input) noexcept
{
	input.Disable();
}

inline bool
WasInput::SetLength(uint64_t _length) noexcept
{
	if (known_length) {
		if (_length == length)
			return true;

		// TODO: don't invoke Istream::DestroyError() if not yet enabled
		AbortError("wrong input length announced");
		return false;
	}

	if (_length < received) {
		/* this length must be bogus, because we already received more than that from the socket */
		AbortError("announced length is too small");
		return false;
	}

	length = _length;
	known_length = true;

	if (!CheckReleasePipe())
		return false;

	if (enabled && CheckEof())
		return false;

	return true;
}

bool
was_input_set_length(WasInput *input, uint64_t length) noexcept
{
	return input->SetLength(length);
}

void
WasInput::PrematureThrow(uint64_t _length)
{
	buffer.FreeIfDefined();
	event.Cancel();

	if (known_length && _length > length)
		throw WasProtocolError("announced premature length is too large");

	if (_length < received)
		throw WasProtocolError("announced premature length is too small");

	uint64_t remaining = _length - received;

	while (remaining > 0) {
		uint8_t discard_buffer[4096];
		size_t size = std::min(remaining, uint64_t(sizeof(discard_buffer)));
		ssize_t nbytes = fd.Read(discard_buffer, size);
		if (nbytes < 0)
			throw NestException(std::make_exception_ptr(MakeErrno("Read error")),
					    WasError("read error on WAS data connection"));

		if (nbytes == 0)
			throw WasProtocolError("server closed the WAS data connection");

		remaining -= nbytes;
	}
}

inline bool
WasInput::Premature(uint64_t _length) noexcept
{
	try {
		PrematureThrow(_length);
	} catch (...) {
		/* protocol error - notify our WasInputHandler */
		handler.WasInputError();
		DestroyError(std::current_exception());
		return false;
	}

	/* recovery was successful - let our IstreamHandler know that
	   the stream was closed prematurely and return success */
	DestroyError(std::make_exception_ptr(WasProtocolError("premature end of WAS response")));
	return true;
}

bool
was_input_premature(WasInput *input, uint64_t length) noexcept
{
	return input->Premature(length);
}

void
was_input_premature_throw(WasInput *input, uint64_t length)
{
	AtScopeExit(input) { input->Destroy(); };
	input->PrematureThrow(length);
	throw WasProtocolError("premature end of WAS response");
}

void
WasInput::_FillBucketList(IstreamBucketList &list)
{
	auto r = buffer.Read();
	if (r.empty()) {
		if (!fd.IsDefined())
			return;

		ReadToBuffer();

		if (!CheckReleasePipe())
			// TODO: deal with this condition properly or improve error message
			throw std::runtime_error("WAS peer failed");

		r = buffer.Read();
		if (r.empty()) {
			list.SetMore();
			return;
		}
	}

	list.Push(r.ToVoid());

	if (!known_length || received < length)
		list.SetMore();
}

size_t
WasInput::_ConsumeBucketList(size_t nbytes) noexcept
{
	size_t consumed = std::min(buffer.GetAvailable(), nbytes);

	buffer.Consume(consumed);
	buffer.FreeIfEmpty();

	Consumed(consumed);
	return consumed;
}
<|endoftext|>


<commit_before>/*
 * RemoteSyslogAppender.cpp
 *
 * Copyright 2001, LifeLine Networks BV (www.lifeline.nl). All rights reserved.
 * Copyright 2001, Walter Stroebel. All rights reserved.
 *
 * See the COPYING file for the terms of usage and distribution.
 */

#include "log4cpp/Portability.hh"

#ifdef LOG4CPP_HAVE_UNISTD_H
#    include <unistd.h>
#endif
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "log4cpp/RemoteSyslogAppender.hh"
#ifdef WIN32
#include <winsock2.h>
#else
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif

namespace log4cpp {

    int RemoteSyslogAppender::toSyslogPriority(Priority::Value priority) {
        static int priorities[8] = { LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_ERR,
                                     LOG_WARNING, LOG_NOTICE, LOG_INFO,
                                     LOG_DEBUG };
        int result;

        priority++;
        priority /= 100;

        if (priority < 0) {
            result = LOG_EMERG;
        } else if (priority > 7) {
            result = LOG_DEBUG;
        } else {
            result = priorities[priority];
        }

        return result;
    }

    RemoteSyslogAppender::RemoteSyslogAppender(const std::string& name,
                                   const std::string& syslogName,
				   const std::string& relayer,
                                   int facility,
				   int portNumber) :
        AppenderSkeleton(name),
        _syslogName(syslogName),
	_relayer(relayer),
        _facility(facility),
	_portNumber (portNumber),
	_socket (0),
	_ipAddr (0),
	_cludge (0)
    {
        open();
    }

    RemoteSyslogAppender::~RemoteSyslogAppender() {
        close();
#ifdef WIN32
	if (_cludge) {
	    // we started it, we end it.
	    WSACleanup ();
	}
#endif
    }

    void RemoteSyslogAppender::open() {
	if (!_ipAddr) {
	    struct hostent *pent = gethostbyname (_relayer.c_str ());
	    if (pent == NULL) {
#ifdef WIN32
		if (WSAGetLastError () == WSANOTINITIALISED) {
		    WSADATA wsaData;
		    int err;

		    err = WSAStartup (0x101, &wsaData );
		    if (err) abort ();
		    pent = gethostbyname (_relayer.c_str ());
		    _cludge = 1;
		} else {
		    abort ();
		}
#endif
	    }
	    if (pent == NULL) {
		unsigned long ip = (unsigned long) inet_addr (_relayer.c_str ());
		pent = gethostbyaddr ((const char *) &ip, 4, AF_INET);
	    }
	    if (pent == NULL) {
		abort ();
	    }
	    _ipAddr = *((unsigned long *) pent->h_addr);
	}
	// Get a datagram socket.

	if ((_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
	    abort ();
	} else {
	    sockaddr_in sain;
	    sain.sin_family = AF_INET;
	    sain.sin_port   = htons (_portNumber);
	    sain.sin_addr.s_addr = htonl (_ipAddr);
	    if (connect (_socket, (struct sockaddr *) &sain, sizeof (sain)) < 0) {
		abort ();
	    }
	}
    }

    void RemoteSyslogAppender::close() {
	if (_socket) {
#if WIN32
	    closesocket (_socket);
#else
	    ::close (_socket);
#endif
	    _socket = 0;
	}
    }

    void RemoteSyslogAppender::_append(const LoggingEvent& event) {
        if (!_layout) {
            // XXX help! help!
            return;
        }

	std::string msgStr = _layout->format(event);
        const char* message = msgStr.c_str();
	int len = strlen (message) + 16;
	char *buf = new char [len];
        int priority = toSyslogPriority(event.priority);
	sprintf (buf, "<%d>", priority);
	memcpy (buf + strlen (buf), message, len - 16);
	sockaddr_in sain;
	sain.sin_family = AF_INET;
	sain.sin_port   = htons (_portNumber);
        sain.sin_addr.s_addr = htonl (_ipAddr);
	int r = sendto (_socket, buf, (int) len, 0, (struct sockaddr *) &sain, sizeof (sain));
	printf ("sendto: %d\n", r);
	delete buf;
    }

    bool RemoteSyslogAppender::reopen() {
        close();
        open();
        return true;
    }

    bool RemoteSyslogAppender::requiresLayout() const {
        return true;
    }

    void RemoteSyslogAppender::setLayout(Layout* layout) {
        _layout = layout;
    }

}
<commit_msg>RemoteSyslogAppender is functional<commit_after>/*
 * RemoteSyslogAppender.cpp
 *
 * Copyright 2001, LifeLine Networks BV (www.lifeline.nl). All rights reserved.
 * Copyright 2001, Walter Stroebel. All rights reserved.
 *
 * See the COPYING file for the terms of usage and distribution.
 */

#include "log4cpp/Portability.hh"

#ifdef LOG4CPP_HAVE_UNISTD_H
#    include <unistd.h>
#endif
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "log4cpp/RemoteSyslogAppender.hh"
#ifdef WIN32
#include <winsock2.h>
#else
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif

namespace log4cpp {

    int RemoteSyslogAppender::toSyslogPriority(Priority::Value priority) {
        static int priorities[8] = { LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_ERR,
                                     LOG_WARNING, LOG_NOTICE, LOG_INFO,
                                     LOG_DEBUG };
        int result;

        priority++;
        priority /= 100;

        if (priority < 0) {
            result = LOG_EMERG;
        } else if (priority > 7) {
            result = LOG_DEBUG;
        } else {
            result = priorities[priority];
        }

        return result;
    }

    RemoteSyslogAppender::RemoteSyslogAppender(const std::string& name,
                                   const std::string& syslogName,
				   const std::string& relayer,
                                   int facility,
				   int portNumber) :
        AppenderSkeleton(name),
        _syslogName(syslogName),
	_relayer(relayer),
        _facility(facility),
	_portNumber (portNumber),
	_socket (0),
	_ipAddr (0),
	_cludge (0)
    {
        open();
    }

    RemoteSyslogAppender::~RemoteSyslogAppender() {
        close();
#ifdef WIN32
	if (_cludge) {
	    // we started it, we end it.
	    WSACleanup ();
	}
#endif
    }

    void RemoteSyslogAppender::open() {
	if (!_ipAddr) {
	    struct hostent *pent = gethostbyname (_relayer.c_str ());
	    if (pent == NULL) {
#ifdef WIN32
		if (WSAGetLastError () == WSANOTINITIALISED) {
		    WSADATA wsaData;
		    int err;

		    err = WSAStartup (0x101, &wsaData );
		    if (err) abort ();
		    pent = gethostbyname (_relayer.c_str ());
		    _cludge = 1;
		} else {
		    abort ();
		}
#endif
	    }
	    if (pent == NULL) {
		unsigned long ip = (unsigned long) inet_addr (_relayer.c_str ());
		pent = gethostbyaddr ((const char *) &ip, 4, AF_INET);
	    }
	    if (pent == NULL) {
		abort ();
	    }
	    _ipAddr = *((unsigned long *) pent->h_addr);
	}
	// Get a datagram socket.

	if ((_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
	    abort ();
	}
    }

    void RemoteSyslogAppender::close() {
	if (_socket) {
#if WIN32
	    closesocket (_socket);
#else
	    ::close (_socket);
#endif
	    _socket = 0;
	}
    }

    void RemoteSyslogAppender::_append(const LoggingEvent& event) {
        if (!_layout) {
            // XXX help! help!
            return;
        }

	std::string msgStr = _layout->format(event);
        const char* message = msgStr.c_str();
	int len = strlen (message) + 16;
	char *buf = new char [len];
        int priority = toSyslogPriority(event.priority);
	sprintf (buf, "<%d>", priority);
	int len2 = strlen (buf);
	memcpy (buf + len2, message, len - 16);
	sockaddr_in sain;
	sain.sin_family = AF_INET;
	sain.sin_port   = htons (_portNumber);
	// NO, do NOT use htonl on _ipAddr. Is already in network order.
        sain.sin_addr.s_addr = _ipAddr;
	int r = sendto (_socket, buf, len - 16 + len2, 0, (struct sockaddr *) &sain, sizeof (sain));
	printf ("sendto: %d\n", r);
	delete buf;
    }

    bool RemoteSyslogAppender::reopen() {
        close();
        open();
        return true;
    }

    bool RemoteSyslogAppender::requiresLayout() const {
        return true;
    }

    void RemoteSyslogAppender::setLayout(Layout* layout) {
        _layout = layout;
    }

}
<|endoftext|>


<commit_before>// This file is part of the dune-gdt project:
//   https://github.com/dune-community/dune-gdt
// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved.
// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
//      or  GPL-2.0+ (http://opensource.org/licenses/gpl-license)
//          with "runtime exception" (http://www.dune-project.org/license.html)
// Authors:
//   Tobias Leibner  (2019)

#ifndef DUNE_GDT_LOCAL_INTEGRANDS_DIV_HH
#define DUNE_GDT_LOCAL_INTEGRANDS_DIV_HH

#include <dune/xt/common/memory.hh>
#include <dune/xt/functions/constant.hh>
#include <dune/xt/functions/base/function-as-grid-function.hh>
#include <dune/xt/functions/interfaces/grid-function.hh>

#include "interfaces.hh"

namespace Dune {
namespace GDT {
namespace internal {

class LocalElementDivProductIntegrandBase
{
protected:
  template <class DivBasis,
            class SecondBasis,
            class Point,
            class Result,
            class LocalFunction,
            class Jacobians,
            class Values>
  void evaluate(const DivBasis& div_basis,
                const SecondBasis& second_basis,
                const Point& reference_point,
                Result& result,
                const XT::Common::Parameter param,
                const LocalFunction& local_function,
                Jacobians& jacobians,
                Values& values) const
  {
    static const size_t d = DivBasis::d;
    // prepare storage
    const size_t rows = div_basis.size(param);
    const size_t cols = second_basis.size(param);
    if (result.rows() < rows || result.cols() < cols)
      result.resize(rows, cols);
    // evaluate
    div_basis.jacobians(reference_point, jacobians, param);
    second_basis.evaluate(reference_point, values, param);
    const auto function_value = local_function.evaluate(reference_point, param);
    // compute product
    for (size_t ii = 0; ii < rows; ++ii) {
      // calculate div(psi_ii(x))
      typename DivBasis::R div_ii = 0;
      for (size_t dd = 0; dd < d; ++dd)
        div_ii += jacobians[ii][dd][dd];
      for (size_t jj = 0; jj < cols; ++jj)
        result[ii][jj] = (function_value * div_ii) * values[jj];
    }
  }
};

} // namespace internal

/**
 * Given an inducing function f, computes `f(x) * phi(x) * div(psi(x))` for all combinations of phi and psi in the
 * bases.
 *
 * \note Note that f can also be given as a scalar value or omitted.
 *
 * \sa local_binary_to_unary_element_integrand
 */
template <class E, class TR = double, class F = double, class AR = TR>
class LocalElementAnsatzValueTestDivProductIntegrand
  : public LocalBinaryElementIntegrandInterface<E, E::dimension, 1, TR, F, 1, 1, AR>
  , public internal::LocalElementDivProductIntegrandBase
{
  using BaseType = LocalBinaryElementIntegrandInterface<E, E::dimension, 1, TR, F, 1, 1, AR>;
  using ThisType = LocalElementAnsatzValueTestDivProductIntegrand;
  using DivBaseType = internal::LocalElementDivProductIntegrandBase;

public:
  using BaseType::d;
  using typename BaseType::DomainType;
  using typename BaseType::ElementType;
  using typename BaseType::LocalAnsatzBasisType;
  using typename BaseType::LocalTestBasisType;

  using GridFunctionType = XT::Functions::GridFunctionInterface<E, 1, 1, F>;

  LocalElementAnsatzValueTestDivProductIntegrand(const F& inducing_value = F(1))
    : BaseType()
    , DivBaseType()
    , inducing_function_(new XT::Functions::ConstantGridFunction<ElementType>(inducing_value))
    , local_function_(inducing_function_.access().local_function())
  {}

  LocalElementAnsatzValueTestDivProductIntegrand(const XT::Functions::FunctionInterface<d, 1, 1, F>& inducing_function)
    : BaseType()
    , DivBaseType()
    , inducing_function_(new XT::Functions::FunctionAsGridFunctionWrapper<E, 1, 1, F>(inducing_function))
    , local_function_(inducing_function_.access().local_function())
  {}

  LocalElementAnsatzValueTestDivProductIntegrand(const GridFunctionType& inducing_function)
    : BaseType(inducing_function.parameter_type())
    , DivBaseType()
    , inducing_function_(inducing_function)
    , local_function_(inducing_function_.access().local_function())
  {}

  LocalElementAnsatzValueTestDivProductIntegrand(const ThisType& other)
    : BaseType(other.parameter_type())
    , DivBaseType()
    , inducing_function_(other.inducing_function_)
    , local_function_(inducing_function_.access().local_function())
  {}

  LocalElementAnsatzValueTestDivProductIntegrand(ThisType&& source) = default;

  std::unique_ptr<BaseType> copy() const override final
  {
    return std::make_unique<ThisType>(*this);
  }

protected:
  void post_bind(const ElementType& ele) override final
  {
    local_function_->bind(ele);
  }

public:
  int order(const LocalTestBasisType& test_basis,
            const LocalAnsatzBasisType& ansatz_basis,
            const XT::Common::Parameter& param = {}) const override final
  {
    return std::max(local_function_->order(param) + test_basis.order(param) + ansatz_basis.order(param) - 1 + 10, 0);
  }

  using BaseType::evaluate;

  void evaluate(const LocalTestBasisType& test_basis,
                const LocalAnsatzBasisType& ansatz_basis,
                const DomainType& point_in_reference_element,
                DynamicMatrix<F>& result,
                const XT::Common::Parameter& param = {}) const override final
  {
    DivBaseType::evaluate(test_basis,
                          ansatz_basis,
                          point_in_reference_element,
                          result,
                          param,
                          *local_function_,
                          test_basis_jacobians_,
                          ansatz_basis_values_);
  } // ... evaluate(...)

private:
  const XT::Common::ConstStorageProvider<GridFunctionType> inducing_function_;
  std::unique_ptr<typename GridFunctionType::LocalFunctionType> local_function_;
  mutable std::vector<typename LocalTestBasisType::DerivativeRangeType> test_basis_jacobians_;
  mutable std::vector<typename LocalAnsatzBasisType::RangeType> ansatz_basis_values_;
}; // class LocalElementAnsatzValueTestDivProductIntegrand

/**
 * Given an inducing function f, computes `f(x) * div phi(x) * psi(x)` for all combinations of phi and psi in the bases.
 *
 * \sa LocalElementAnsatzValueTestDivProductIntegrand
 */
template <class E, class TR = double, class F = double, class AR = TR>
class LocalElementAnsatzDivTestValueProductIntegrand
  : public LocalBinaryElementIntegrandInterface<E, 1, 1, TR, F, E::dimension, 1, AR>
  , public internal::LocalElementDivProductIntegrandBase
{
  using BaseType = LocalBinaryElementIntegrandInterface<E, 1, 1, TR, F, E::dimension, 1, AR>;
  using ThisType = LocalElementAnsatzDivTestValueProductIntegrand;
  using DivBaseType = internal::LocalElementDivProductIntegrandBase;

public:
  using BaseType::d;
  using typename BaseType::DomainType;
  using typename BaseType::ElementType;
  using typename BaseType::LocalAnsatzBasisType;
  using typename BaseType::LocalTestBasisType;

  using GridFunctionType = XT::Functions::GridFunctionInterface<E, 1, 1, F>;

  LocalElementAnsatzDivTestValueProductIntegrand(const F& inducing_value = F(1))
    : BaseType()
    , inducing_function_(new XT::Functions::FunctionAsGridFunctionWrapper<E, 1, 1, F>(
          new XT::Functions::ConstantFunction<d, 1, 1, F>(inducing_value)))
    , local_function_(inducing_function_.access().local_function())
  {}

  LocalElementAnsatzDivTestValueProductIntegrand(const XT::Functions::FunctionInterface<d, 1, 1, F>& inducing_function)
    : BaseType()
    , inducing_function_(new XT::Functions::FunctionAsGridFunctionWrapper<E, 1, 1, F>(inducing_function))
    , local_function_(inducing_function_.access().local_function())
  {}

  LocalElementAnsatzDivTestValueProductIntegrand(const GridFunctionType& inducing_function)
    : BaseType(inducing_function.parameter_type())
    , inducing_function_(inducing_function)
    , local_function_(inducing_function_.access().local_function())
  {}

  LocalElementAnsatzDivTestValueProductIntegrand(const ThisType& other)
    : BaseType(other.parameter_type())
    , inducing_function_(other.inducing_function_)
    , local_function_(inducing_function_.access().local_function())
  {}

  LocalElementAnsatzDivTestValueProductIntegrand(ThisType&& source) = default;

  std::unique_ptr<BaseType> copy() const override final
  {
    return std::make_unique<ThisType>(*this);
  }

protected:
  void post_bind(const ElementType& ele) override final
  {
    local_function_->bind(ele);
  }

public:
  int order(const LocalTestBasisType& test_basis,
            const LocalAnsatzBasisType& ansatz_basis,
            const XT::Common::Parameter& param = {}) const override final
  {
    return std::max(local_function_->order(param) + test_basis.order(param) + ansatz_basis.order(param) - 1 + 10, 0);
  }

  using BaseType::evaluate;

  void evaluate(const LocalTestBasisType& test_basis,
                const LocalAnsatzBasisType& ansatz_basis,
                const DomainType& point_in_reference_element,
                DynamicMatrix<F>& result,
                const XT::Common::Parameter& param = {}) const override final
  {
    DivBaseType::evaluate(test_basis,
                          ansatz_basis,
                          point_in_reference_element,
                          result,
                          param,
                          *local_function_,
                          ansatz_basis_jacobians_,
                          test_basis_values_);
  } // ... evaluate(...)

private:
  const XT::Common::ConstStorageProvider<GridFunctionType> inducing_function_;
  std::unique_ptr<typename GridFunctionType::LocalFunctionType> local_function_;
  mutable std::vector<typename LocalTestBasisType::RangeType> test_basis_values_;
  mutable std::vector<typename LocalAnsatzBasisType::DerivativeRangeType> ansatz_basis_jacobians_;
}; // class LocalElementAnsatzDivTestValueProductIntegrand

} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_LOCAL_INTEGRANDS_DIV_HH
<commit_msg>[local.integrands.div] fix order<commit_after>// This file is part of the dune-gdt project:
//   https://github.com/dune-community/dune-gdt
// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved.
// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
//      or  GPL-2.0+ (http://opensource.org/licenses/gpl-license)
//          with "runtime exception" (http://www.dune-project.org/license.html)
// Authors:
//   Tobias Leibner  (2019)

#ifndef DUNE_GDT_LOCAL_INTEGRANDS_DIV_HH
#define DUNE_GDT_LOCAL_INTEGRANDS_DIV_HH

#include <dune/xt/common/memory.hh>
#include <dune/xt/functions/constant.hh>
#include <dune/xt/functions/base/function-as-grid-function.hh>
#include <dune/xt/functions/interfaces/grid-function.hh>

#include "interfaces.hh"

namespace Dune {
namespace GDT {
namespace internal {

class LocalElementDivProductIntegrandBase
{
protected:
  template <class DivBasis,
            class SecondBasis,
            class Point,
            class Result,
            class LocalFunction,
            class Jacobians,
            class Values>
  void evaluate(const DivBasis& div_basis,
                const SecondBasis& second_basis,
                const Point& reference_point,
                Result& result,
                const XT::Common::Parameter param,
                const LocalFunction& local_function,
                Jacobians& jacobians,
                Values& values) const
  {
    static const size_t d = DivBasis::d;
    // prepare storage
    const size_t rows = div_basis.size(param);
    const size_t cols = second_basis.size(param);
    if (result.rows() < rows || result.cols() < cols)
      result.resize(rows, cols);
    // evaluate
    div_basis.jacobians(reference_point, jacobians, param);
    second_basis.evaluate(reference_point, values, param);
    const auto function_value = local_function.evaluate(reference_point, param);
    // compute product
    for (size_t ii = 0; ii < rows; ++ii) {
      // calculate div(psi_ii(x))
      typename DivBasis::R div_ii = 0;
      for (size_t dd = 0; dd < d; ++dd)
        div_ii += jacobians[ii][dd][dd];
      for (size_t jj = 0; jj < cols; ++jj)
        result[ii][jj] = (function_value * div_ii) * values[jj];
    }
  }
};

} // namespace internal

/**
 * Given an inducing function f, computes `f(x) * phi(x) * div(psi(x))` for all combinations of phi and psi in the
 * bases.
 *
 * \note Note that f can also be given as a scalar value or omitted.
 *
 * \sa local_binary_to_unary_element_integrand
 */
template <class E, class TR = double, class F = double, class AR = TR>
class LocalElementAnsatzValueTestDivProductIntegrand
  : public LocalBinaryElementIntegrandInterface<E, E::dimension, 1, TR, F, 1, 1, AR>
  , public internal::LocalElementDivProductIntegrandBase
{
  using BaseType = LocalBinaryElementIntegrandInterface<E, E::dimension, 1, TR, F, 1, 1, AR>;
  using ThisType = LocalElementAnsatzValueTestDivProductIntegrand;
  using DivBaseType = internal::LocalElementDivProductIntegrandBase;

public:
  using BaseType::d;
  using typename BaseType::DomainType;
  using typename BaseType::ElementType;
  using typename BaseType::LocalAnsatzBasisType;
  using typename BaseType::LocalTestBasisType;

  using GridFunctionType = XT::Functions::GridFunctionInterface<E, 1, 1, F>;

  LocalElementAnsatzValueTestDivProductIntegrand(const F& inducing_value = F(1))
    : BaseType()
    , DivBaseType()
    , inducing_function_(new XT::Functions::ConstantGridFunction<ElementType>(inducing_value))
    , local_function_(inducing_function_.access().local_function())
  {}

  LocalElementAnsatzValueTestDivProductIntegrand(const XT::Functions::FunctionInterface<d, 1, 1, F>& inducing_function)
    : BaseType()
    , DivBaseType()
    , inducing_function_(new XT::Functions::FunctionAsGridFunctionWrapper<E, 1, 1, F>(inducing_function))
    , local_function_(inducing_function_.access().local_function())
  {}

  LocalElementAnsatzValueTestDivProductIntegrand(const GridFunctionType& inducing_function)
    : BaseType(inducing_function.parameter_type())
    , DivBaseType()
    , inducing_function_(inducing_function)
    , local_function_(inducing_function_.access().local_function())
  {}

  LocalElementAnsatzValueTestDivProductIntegrand(const ThisType& other)
    : BaseType(other.parameter_type())
    , DivBaseType()
    , inducing_function_(other.inducing_function_)
    , local_function_(inducing_function_.access().local_function())
  {}

  LocalElementAnsatzValueTestDivProductIntegrand(ThisType&& source) = default;

  std::unique_ptr<BaseType> copy() const override final
  {
    return std::make_unique<ThisType>(*this);
  }

protected:
  void post_bind(const ElementType& ele) override final
  {
    local_function_->bind(ele);
  }

public:
  int order(const LocalTestBasisType& test_basis,
            const LocalAnsatzBasisType& ansatz_basis,
            const XT::Common::Parameter& param = {}) const override final
  {
    return std::max(local_function_->order(param) + test_basis.order(param) + ansatz_basis.order(param) - 1, 0);
  }

  using BaseType::evaluate;

  void evaluate(const LocalTestBasisType& test_basis,
                const LocalAnsatzBasisType& ansatz_basis,
                const DomainType& point_in_reference_element,
                DynamicMatrix<F>& result,
                const XT::Common::Parameter& param = {}) const override final
  {
    DivBaseType::evaluate(test_basis,
                          ansatz_basis,
                          point_in_reference_element,
                          result,
                          param,
                          *local_function_,
                          test_basis_jacobians_,
                          ansatz_basis_values_);
  } // ... evaluate(...)

private:
  const XT::Common::ConstStorageProvider<GridFunctionType> inducing_function_;
  std::unique_ptr<typename GridFunctionType::LocalFunctionType> local_function_;
  mutable std::vector<typename LocalTestBasisType::DerivativeRangeType> test_basis_jacobians_;
  mutable std::vector<typename LocalAnsatzBasisType::RangeType> ansatz_basis_values_;
}; // class LocalElementAnsatzValueTestDivProductIntegrand

/**
 * Given an inducing function f, computes `f(x) * div phi(x) * psi(x)` for all combinations of phi and psi in the bases.
 *
 * \sa LocalElementAnsatzValueTestDivProductIntegrand
 */
template <class E, class TR = double, class F = double, class AR = TR>
class LocalElementAnsatzDivTestValueProductIntegrand
  : public LocalBinaryElementIntegrandInterface<E, 1, 1, TR, F, E::dimension, 1, AR>
  , public internal::LocalElementDivProductIntegrandBase
{
  using BaseType = LocalBinaryElementIntegrandInterface<E, 1, 1, TR, F, E::dimension, 1, AR>;
  using ThisType = LocalElementAnsatzDivTestValueProductIntegrand;
  using DivBaseType = internal::LocalElementDivProductIntegrandBase;

public:
  using BaseType::d;
  using typename BaseType::DomainType;
  using typename BaseType::ElementType;
  using typename BaseType::LocalAnsatzBasisType;
  using typename BaseType::LocalTestBasisType;

  using GridFunctionType = XT::Functions::GridFunctionInterface<E, 1, 1, F>;

  LocalElementAnsatzDivTestValueProductIntegrand(const F& inducing_value = F(1))
    : BaseType()
    , inducing_function_(new XT::Functions::FunctionAsGridFunctionWrapper<E, 1, 1, F>(
          new XT::Functions::ConstantFunction<d, 1, 1, F>(inducing_value)))
    , local_function_(inducing_function_.access().local_function())
  {}

  LocalElementAnsatzDivTestValueProductIntegrand(const XT::Functions::FunctionInterface<d, 1, 1, F>& inducing_function)
    : BaseType()
    , inducing_function_(new XT::Functions::FunctionAsGridFunctionWrapper<E, 1, 1, F>(inducing_function))
    , local_function_(inducing_function_.access().local_function())
  {}

  LocalElementAnsatzDivTestValueProductIntegrand(const GridFunctionType& inducing_function)
    : BaseType(inducing_function.parameter_type())
    , inducing_function_(inducing_function)
    , local_function_(inducing_function_.access().local_function())
  {}

  LocalElementAnsatzDivTestValueProductIntegrand(const ThisType& other)
    : BaseType(other.parameter_type())
    , inducing_function_(other.inducing_function_)
    , local_function_(inducing_function_.access().local_function())
  {}

  LocalElementAnsatzDivTestValueProductIntegrand(ThisType&& source) = default;

  std::unique_ptr<BaseType> copy() const override final
  {
    return std::make_unique<ThisType>(*this);
  }

protected:
  void post_bind(const ElementType& ele) override final
  {
    local_function_->bind(ele);
  }

public:
  int order(const LocalTestBasisType& test_basis,
            const LocalAnsatzBasisType& ansatz_basis,
            const XT::Common::Parameter& param = {}) const override final
  {
    return std::max(local_function_->order(param) + test_basis.order(param) + ansatz_basis.order(param) - 1 + 10, 0);
  }

  using BaseType::evaluate;

  void evaluate(const LocalTestBasisType& test_basis,
                const LocalAnsatzBasisType& ansatz_basis,
                const DomainType& point_in_reference_element,
                DynamicMatrix<F>& result,
                const XT::Common::Parameter& param = {}) const override final
  {
    DivBaseType::evaluate(test_basis,
                          ansatz_basis,
                          point_in_reference_element,
                          result,
                          param,
                          *local_function_,
                          ansatz_basis_jacobians_,
                          test_basis_values_);
  } // ... evaluate(...)

private:
  const XT::Common::ConstStorageProvider<GridFunctionType> inducing_function_;
  std::unique_ptr<typename GridFunctionType::LocalFunctionType> local_function_;
  mutable std::vector<typename LocalTestBasisType::RangeType> test_basis_values_;
  mutable std::vector<typename LocalAnsatzBasisType::DerivativeRangeType> ansatz_basis_jacobians_;
}; // class LocalElementAnsatzDivTestValueProductIntegrand

} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_LOCAL_INTEGRANDS_DIV_HH
<|endoftext|>


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

// Transparent SSL Tunnel hooking.
// Jeff Lawson <jlawson@bovine.net>
// $Id: stunmirc.cpp,v 1.4 2003/06/01 23:53:03 jlawson Exp $

#include "stuntour.h"

// -----------------------------------
// mIRC blue-window painting specific things follow...

#ifdef SECUREBLUEWINDOW

static HWND hwndSavedWindow = NULL;
static WNDPROC lpfnOldWindowProc = NULL;

static LRESULT CALLBACK Detour_mIRCWindowProc(
  HWND hwnd,      // handle to window
  UINT uMsg,      // message identifier
  WPARAM wParam,  // first message parameter
  LPARAM lParam   // second message parameter
)
{
    if (uMsg == WM_NCPAINT) {
        // First let the original method do its work.
        LRESULT lResult = CallWindowProc(lpfnOldWindowProc, hwnd, uMsg, wParam, lParam);

        // Now overpaint the border with a blue line.
        HDC hdc = GetDCEx(hwnd, (HRGN)wParam, DCX_WINDOW|DCX_INTERSECTRGN);
        if (hdc) {
            RECT windowrect, workrect;
            GetWindowRect(hwnd, &windowrect);

            HBRUSH hBlueBrush = CreateSolidBrush(RGB(0,0,255));
            int framewidth = GetSystemMetrics(SM_CXSIZEFRAME);
            int frameheight = GetSystemMetrics(SM_CYSIZEFRAME);

            // draw the top border.
            workrect.top = 0;
            workrect.left = 0;
            workrect.right = windowrect.right - windowrect.left;
            workrect.bottom = frameheight;
            FillRect(hdc, &workrect, hBlueBrush);

            // draw the left border.
            workrect.top = 0;
            workrect.left = 0;
            workrect.right = framewidth;
            workrect.bottom = windowrect.bottom - windowrect.top;
            FillRect(hdc, &workrect, hBlueBrush);

            // draw the right border.
            workrect.top = 0;
            workrect.left = windowrect.right - windowrect.left - framewidth;
            workrect.right = windowrect.right - windowrect.left;
            workrect.bottom = windowrect.bottom - windowrect.top;
            FillRect(hdc, &workrect, hBlueBrush);

            // draw the bottom border.
            workrect.top = windowrect.bottom - windowrect.top - frameheight;
            workrect.left = 0;
            workrect.right = windowrect.right - windowrect.left;
            workrect.bottom = windowrect.bottom - windowrect.top;
            FillRect(hdc, &workrect, hBlueBrush);

            //HPEN hBluePenWidth = CreatePen(PS_INSIDEFRAME, framewidth, RGB(0,0,255));
            //HPEN hBluePenHeight = CreatePen(PS_INSIDEFRAME, frameheight, RGB(0,0,255));
            //Rectangle(hdc, windowrect.left, windowrect.top, windowrect.right, windowrect.bottom);

            DeleteObject(hBlueBrush);
            ReleaseDC(hwnd, hdc);
        }

        // Return the original result code.
        return lResult;
    } else {
        return CallWindowProc(lpfnOldWindowProc, hwnd, uMsg, wParam, lParam);
    }
}

static void ForceNonclientRepaint(HWND hwnd)
{
    RedrawWindow(hwnd, NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_NOINTERNALPAINT | RDW_ERASENOW);
}

static BOOL CALLBACK SASWEnumWindowsProc(
  HWND hwnd,      // handle to parent window
  LPARAM lParam   // application-defined value
)
{
    char szClassName[64];
    if (GetClassName(hwnd, szClassName, sizeof(szClassName)) &&
        (strcmp(szClassName, "mIRC32") == 0 || strcmp(szClassName, "mIRC") == 0)
        )
    {
        DWORD windowpid;
        GetWindowThreadProcessId(hwnd, &windowpid);
        if (windowpid == GetCurrentProcessId()) {
            // Found the window that is from our process.  Subclass it.

            if (!lpfnOldWindowProc) {
                hwndSavedWindow = hwnd;
                lpfnOldWindowProc = (WNDPROC) GetWindowLong(hwnd, GWL_WNDPROC);
                SetWindowLong(hwnd, GWL_WNDPROC, (DWORD) Detour_mIRCWindowProc);
                ForceNonclientRepaint(hwnd);
            }

            return FALSE;       // done enumerating.
        }
    }
    return TRUE;        // continue enumerating.
}

void SearchAndSubclassWindow(void)
{
    if (!lpfnOldWindowProc) {
        EnumWindows(SASWEnumWindowsProc, 0);
    }
}

#endif

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

static BOOL CALLBACK GOPWEnumWindowsProc(
  HWND hwnd,      // handle to parent window
  LPARAM lParam   // application-defined value
)
{
    char szClassName[64];
    if ( GetClassName(hwnd, szClassName, sizeof(szClassName)) &&
        (strcmp(szClassName, "mIRC32") == 0 || strcmp(szClassName, "mIRC") == 0)
        )
    {
        DWORD windowpid;
        GetWindowThreadProcessId(hwnd, &windowpid);
        if (windowpid == GetCurrentProcessId()) {
            // Found the window that is from our process.
            *reinterpret_cast<HWND*>(lParam) = hwnd;
            return FALSE;       // done enumerating.
        }
    }
    return TRUE;        // continue enumerating.
}

HWND GetOurParentWindow(void)
{
    HWND hWnd = NULL;
    EnumWindows(GOPWEnumWindowsProc, (LPARAM) &hWnd);
    DOUT(("GetOurParentWindow: found hwnd %p\n", hWnd));
    return hWnd;
}

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

// mIRC plugin specific things follow...

//! Method exported to mIRC that can be invoked to manually load the library.
/*
 * This doesn't really do anything significant, since simply loading the
 * library into the process-space will cause the winsock hooks to be installed.
 */
extern "C" int __declspec(dllexport) __stdcall load_stunnel(
      HWND mWnd, HWND aWnd, char *data, char *parms, BOOL show, BOOL nopause)
{
    DOUT(("mIRC callback for load_stunnel invoked\n"));
    strcpy(data, "/echo -s StunTour transparent SSL hook is installed. http://www.bovine.net/~jlawson/coding/stuntour/");

#ifdef SECUREBLUEWINDOW
    if (!lpfnOldWindowProc) {
        hwndSavedWindow = mWnd;
        lpfnOldWindowProc = (WNDPROC) GetWindowLong(mWnd, GWL_WNDPROC);
        SetWindowLong(mWnd, GWL_WNDPROC, (DWORD) Detour_mIRCWindowProc);
        ForceNonclientRepaint(mWnd);
    }
#endif

    return 2;       // mIRC should execute the command we returned..
}

//! Internal mIRC structure used to supervise library loading.
typedef struct {
    DWORD  mVersion;
    HWND   mHwnd;
    BOOL   mKeep;
} LOADINFO;

//! Method exported to mIRC to indicate that it should leave the library
//! always loaded, even after execution of the exported method has been run.
extern "C" void __declspec(dllexport) __stdcall LoadDll(LOADINFO *loadinfo)
{
    DOUT(("mIRC callback for LoadDll invoked\n"));
    loadinfo->mKeep = TRUE;
}

//! Method exported to mIRC to that it calls before it unloads the library.
/*
 * The only thing that this method does is try to disallow mIRC from
 * unloading our library (and breaking our hooks).
 */
extern "C" int __declspec(dllexport) __stdcall UnloadDll(int mTimeout)
{
    DOUT(("mIRC callback for UnloadDll invoked\n"));
    if (mTimeout == 1) {
        DOUT(("Instructing mIRC to not automatically unload library because of inactivity.\n"));
        return 0;       // return 0 to prevent unload, or 1 to allow it.
    } else {

#ifdef SECUREBLUEWINDOW
        // Remove our windowproc subclassing hook.
        if (lpfnOldWindowProc != NULL) {
            SetWindowLong(hwndSavedWindow, GWL_WNDPROC, (DWORD) lpfnOldWindowProc);
            lpfnOldWindowProc = NULL;
            ForceNonclientRepaint(hwndSavedWindow);
        }
#endif

    }
    return 1;       // otherwise allow it.
}

//! Method exported to mIRC that can be invoked to add interception for a port number.
/*
 * This displays a list of all sockets that are being relayed or adds additional ports.
 */
extern "C" int __declspec(dllexport) __stdcall hook_ports(
      HWND mWnd, HWND aWnd, char *data, char *parms, BOOL show, BOOL nopause)
{
    DOUT(("mIRC callback for hook_ports invoked\n"));

    if (data != NULL) {
        if (strncmp(data, "-oneshot ", 9) == 0) {
            // one-shot port interception.
            AddInterceptedPort(static_cast<unsigned short>(atoi(data + 9)), true);
        } else {
            // normal port interception.
            AddInterceptedPort(static_cast<unsigned short>(atoi(data)), false);
        }
    }

    strcpy(data, "/echo -s StunTour transparent SSL hook active for: ");
    strcat(data, QueryInterceptedPortListSpace().c_str());

    return 2;       // mIRC should execute the command we returned..
}
<commit_msg>refactor blue frame subclassing code.<commit_after>/*
 * Copyright (c) 2002-2003, Jeffrey A. Lawson and Bovine Networking
 * Technologies, Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 *
 * Neither the name of Bovine Networking Technologies, Inc. nor the names
 * of its contributors may be used to endorse or promote products derived
 * from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

// Transparent SSL Tunnel hooking.
// Jeff Lawson <jlawson@bovine.net>
// $Id: stunmirc.cpp,v 1.5 2003/07/20 03:10:19 jlawson Exp $

#include "stuntour.h"

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

namespace BlueWindow {

    typedef std::map<HWND, WNDPROC> hwndprocmap_t;

    //! List of all windows that are currently subclassed.
    static hwndprocmap_t OldWindowProcs;

    //! New window proc used for subclassing.
    static LRESULT CALLBACK SubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

    //! Method to force a window to be repainted.
    static void ForceNonclientRepaint(HWND hwnd);

    //! Entrypoint used to make another window become subclassed.
    bool SubclassNewWindow(HWND hwnd);

    //! Disables all active blue-window subclassing.
    void RemoveSubclassing(void);
};

//! Window procedure to add blue borders to windows via subclassing.
/*!
 * \param hwnd handle to window
 * \param uMsg message identifier
 * \param wParam first message parameter
 * \param lParam second message parameter
 */
LRESULT CALLBACK BlueWindow::SubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    // Obtain the original window procedure, before subclassing.
    WNDPROC lpfnOldWindowProc = NULL;
    hwndprocmap_t::const_iterator lpfnit = OldWindowProcs.find(hwnd);
    if (lpfnit != OldWindowProcs.end()) {
        lpfnOldWindowProc = lpfnit->second;
    } else {
        DOUT(("BlueWindow::SubclassProc called for unknown window %p. Ignoring.\n", (void*) hwnd));
        return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }

    // Start handling the special messages.
    if (uMsg == WM_NCPAINT) {
        // First let the original method do its work.
        LRESULT lResult = CallWindowProc(lpfnOldWindowProc, hwnd, uMsg, wParam, lParam);

        // Now overpaint the border with a blue line.
        HDC hdc = GetDCEx(hwnd, (HRGN)wParam, DCX_WINDOW|DCX_INTERSECTRGN);
        if (!hdc) {
            // If GetDCEx() failed, then try again with just GetWindowDC().
            hdc = GetWindowDC(hwnd);
        }
        if (hdc) {
            RECT windowrect, workrect;
            GetWindowRect(hwnd, &windowrect);

            HBRUSH hBlueBrush = CreateSolidBrush(RGB(0,0,255));
            const int framewidth = GetSystemMetrics(SM_CXSIZEFRAME);
            const int frameheight = GetSystemMetrics(SM_CYSIZEFRAME);

            // draw the top border.
            workrect.top = 0;
            workrect.left = 0;
            workrect.right = windowrect.right - windowrect.left;
            workrect.bottom = frameheight;
            FillRect(hdc, &workrect, hBlueBrush);

            // draw the left border.
            workrect.top = 0;
            workrect.left = 0;
            workrect.right = framewidth;
            workrect.bottom = windowrect.bottom - windowrect.top;
            FillRect(hdc, &workrect, hBlueBrush);

            // draw the right border.
            workrect.top = 0;
            workrect.left = windowrect.right - windowrect.left - framewidth;
            workrect.right = windowrect.right - windowrect.left;
            workrect.bottom = windowrect.bottom - windowrect.top;
            FillRect(hdc, &workrect, hBlueBrush);

            // draw the bottom border.
            workrect.top = windowrect.bottom - windowrect.top - frameheight;
            workrect.left = 0;
            workrect.right = windowrect.right - windowrect.left;
            workrect.bottom = windowrect.bottom - windowrect.top;
            FillRect(hdc, &workrect, hBlueBrush);

            //HPEN hBluePenWidth = CreatePen(PS_INSIDEFRAME, framewidth, RGB(0,0,255));
            //HPEN hBluePenHeight = CreatePen(PS_INSIDEFRAME, frameheight, RGB(0,0,255));
            //Rectangle(hdc, windowrect.left, windowrect.top, windowrect.right, windowrect.bottom);

            DeleteObject(hBlueBrush);
            ReleaseDC(hwnd, hdc);
        }

        // Return the original result code.
        return lResult;
    } else if (uMsg == WM_DESTROY) {
        // Window is about to be destroyed, so remove the subclassing.
        SetWindowLong(hwnd, GWL_WNDPROC, (DWORD) lpfnOldWindowProc);
        OldWindowProcs.erase(hwnd);
        return CallWindowProc(lpfnOldWindowProc, hwnd, uMsg, wParam, lParam);
    } else {
        // Otherwise let the normal window proc handle it.
        return CallWindowProc(lpfnOldWindowProc, hwnd, uMsg, wParam, lParam);
    }
}

//! Forces a window to be fully repainted.
inline void BlueWindow::ForceNonclientRepaint(HWND hwnd)
{
    RedrawWindow(hwnd, NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_NOINTERNALPAINT | RDW_ERASENOW);
}

//! Entrypoint used to make another window become subclassed.
bool BlueWindow::SubclassNewWindow(HWND hwnd)
{
    DWORD windowpid;

    if (hwnd != NULL && IsWindow(hwnd) &&
        GetWindowThreadProcessId(hwnd, &windowpid) &&
        windowpid == GetCurrentProcessId() &&
        OldWindowProcs.find(hwnd) == OldWindowProcs.end())
    {
        // Found the window that is from our process.  Subclass it.
        WNDPROC lpfnOldWindowProc = (WNDPROC) GetWindowLong(hwnd, GWL_WNDPROC);
        OldWindowProcs.insert(std::make_pair<HWND, WNDPROC>(hwnd, lpfnOldWindowProc));
        SetWindowLong(hwnd, GWL_WNDPROC, (DWORD) BlueWindow::SubclassProc);
        ForceNonclientRepaint(hwnd);
        return true;
    }

    return false;       // could not successfully subclass specified window.
}

//! Removes subclassing from all windows.
void BlueWindow::RemoveSubclassing(void)
{
    for (hwndprocmap_t::const_iterator lpfnit = OldWindowProcs.begin();
        lpfnit != OldWindowProcs.end(); lpfnit++)
    {
        SetWindowLong(lpfnit->first, GWL_WNDPROC, (DWORD) lpfnit->second);
        ForceNonclientRepaint(lpfnit->first);
    }
    OldWindowProcs.clear();
}

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

//! Identifies the HWND of the main application window of the mIRC instance
//! that is executing this DLL.
/*!
 * \return The HWND of the main application window, if it can be identified.
 *      Otherwise NULL is returned.
 */
HWND GetOurParentWindow(void)
{
    //! Silly nested class so that we can define a local function.
    class foo {
        foo() {};
    public:
        static BOOL CALLBACK GOPWEnumWindowsProc(
                HWND hwnd,      //!< handle to parent window
                LPARAM lParam   //!< application-defined value
        )
        {
            char szClassName[64];
            if ( GetClassName(hwnd, szClassName, sizeof(szClassName)) &&
                (strcmp(szClassName, "mIRC32") == 0 || strcmp(szClassName, "mIRC") == 0)
                )
            {
                DWORD windowpid;
                GetWindowThreadProcessId(hwnd, &windowpid);
                if (windowpid == GetCurrentProcessId()) {
                    // Found the window that is from our process.
                    *reinterpret_cast<HWND*>(lParam) = hwnd;
                    return FALSE;       // done enumerating.
                }
            }
            return TRUE;        // continue enumerating.
        }
    };

    // Actually do the enumeration call.
    HWND hWnd = NULL;
    EnumWindows(foo::GOPWEnumWindowsProc, (LPARAM) &hWnd);
    DOUT(("GetOurParentWindow: found hwnd %p\n", hWnd));
    return hWnd;
}

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

//! Method exported to mIRC that can be invoked to manually load the library.
/*
 * This doesn't really do anything significant, since simply loading the
 * library into the process-space will cause the winsock hooks to be installed.
 */
extern "C" int __declspec(dllexport) __stdcall load_stunnel(
      HWND mWnd, HWND aWnd, char *data, char *parms, BOOL show, BOOL nopause)
{
    DOUT(("mIRC callback for load_stunnel invoked\n"));
    strcpy(data, "/echo -s StunTour transparent SSL hook is installed. http://www.bovine.net/~jlawson/coding/stuntour/");

#if 0
    // Make the entire main mIRC application window have a blue border.
    BlueWindow::SubclassNewWindow(mWnd);
#endif

    return 2;       // mIRC should execute the command we returned..
}

//! Internal mIRC structure used to supervise library loading.
typedef struct {
    DWORD  mVersion;
    HWND   mHwnd;
    BOOL   mKeep;
} LOADINFO;

//! Method exported to mIRC to indicate that it should leave the library
//! always loaded, even after execution of the exported method has been run.
extern "C" void __declspec(dllexport) __stdcall LoadDll(LOADINFO *loadinfo)
{
    DOUT(("mIRC callback for LoadDll invoked\n"));
    loadinfo->mKeep = TRUE;
}

//! Method exported to mIRC to that it calls before it unloads the library.
/*
 * The only thing that this method does is try to disallow mIRC from
 * unloading our library (and breaking our hooks).
 */
extern "C" int __declspec(dllexport) __stdcall UnloadDll(int mTimeout)
{
    DOUT(("mIRC callback for UnloadDll invoked\n"));
    if (mTimeout == 1) {
        DOUT(("Instructing mIRC to not automatically unload library because of inactivity.\n"));
        return 0;       // return 0 to prevent unload, or 1 to allow it.
    } else {
        // Remove our windowproc subclassing hooks.
        BlueWindow::RemoveSubclassing();
    }
    return 1;       // otherwise allow it.
}

//! Method exported to mIRC that can be invoked to add interception for a port number.
/*
 * This displays a list of all sockets that are being relayed or adds additional ports.
 */
extern "C" int __declspec(dllexport) __stdcall hook_ports(
      HWND mWnd, HWND aWnd, char *data, char *parms, BOOL show, BOOL nopause)
{
    DOUT(("mIRC callback for hook_ports invoked\n"));

    if (data != NULL) {
        if (strncmp(data, "-oneshot ", 9) == 0) {
            // one-shot port interception.
            AddInterceptedPort(static_cast<unsigned short>(atoi(data + 9)), true);
        } else {
            // normal port interception.
            AddInterceptedPort(static_cast<unsigned short>(atoi(data)), false);
        }
    }

    strcpy(data, "/echo -s StunTour transparent SSL hook active for: ");
    strcat(data, QueryInterceptedPortListSpace().c_str());

    return 2;       // mIRC should execute the command we returned..
}

//! Method exported to mIRC that can be invoked to subclass a specified
//! window (by hwnd) and make its window frame blue.
extern "C" int __declspec(dllexport) __stdcall blue_window(
      HWND mWnd, HWND aWnd, char *data, char *parms, BOOL show, BOOL nopause)
{
    DOUT(("mIRC callback for blue_window invoked\n"));

    if (data != NULL) {
        HWND hwnd = (HWND) atoi(data);
        bool bResult = BlueWindow::SubclassNewWindow(hwnd);
        if (bResult) {
            DOUT(("blue_window successfully subclassed new window %p\n", (void*) hwnd));
        } else {
            DOUT(("blue_window failed to subclass new window.\n"));
        }
    }

    return 1;       // mIRC should just continue executing.
}

<|endoftext|>


<commit_before>#include <gtest/gtest.h>
#include <stan/agrad/fwd.hpp>
#include <stan/agrad/rev.hpp>
#include <test/unit/agrad/util.hpp>

TEST(AgradFwdOperatorEqual, Fvar) {
  using stan::agrad::fvar;
  fvar<double> v4 = 4;
  fvar<double> v5 = 5;
  double d4 = 4;
  double d5 = 5;

  EXPECT_FALSE(v5 == v4);
  EXPECT_FALSE(d5 == v4);
  EXPECT_FALSE(v5 == d4);
  EXPECT_FALSE(d5 == d4);

  int i4 = 4;
  int i5 = 5;
  int i6 = 5;

  EXPECT_FALSE(i5 == v4);
  EXPECT_FALSE(v5 == i4);
  EXPECT_FALSE(i5 == i4);
  EXPECT_FALSE(d5 == i4);
  EXPECT_FALSE(i5 == d4);
  EXPECT_TRUE(i6 == i5);
  EXPECT_TRUE(i6 == v5);
}

TEST(AgradFwdOperatorEqual, FvarVar) {
  using stan::agrad::fvar;
  using stan::agrad::var;

  fvar<var> x(0.5,1.3);
  fvar<var> y(1.5,1.0);
  fvar<var> z(0.5,1.3);

  EXPECT_TRUE(x == z);
  EXPECT_FALSE(x == y);
  EXPECT_FALSE(z == y);
}

TEST(AgradFwdOperatorEqual, FvarFvarDouble) {
  using stan::agrad::fvar;

  fvar<fvar<double> > x;
  x.val_.val_ = 1.5;
  x.val_.d_ = 1.0;

  fvar<fvar<double> > y;
  y.val_.val_ = 0.5;
  y.d_.val_ = 1.0;

  fvar<fvar<double> > z;
  z.val_.val_ = 0.5;
  z.d_.val_ = 1.0;

  EXPECT_FALSE(x == y);
  EXPECT_FALSE(x == z);
  EXPECT_TRUE(z == y);
}

TEST(AgradFwdOperatorEqual, FvarFvarVar) {
  using stan::agrad::fvar;
  using stan::agrad::var;

  fvar<fvar<var> > x;
  x.val_.val_ = 1.5;
  x.val_.d_ = 1.0;

  fvar<fvar<var> > y;
  y.val_.val_ = 0.5;
  y.d_.val_ = 1.0;

  fvar<fvar<var> > z;
  z.val_.val_ = 0.5;
  z.d_.val_ = 1.0;

  EXPECT_FALSE(x == y);
  EXPECT_FALSE(x == z);
  EXPECT_TRUE(z == y);
}
<commit_msg>added NaN test for operator_eq<commit_after>#include <gtest/gtest.h>
#include <stan/agrad/fwd.hpp>
#include <stan/agrad/rev.hpp>
#include <test/unit/agrad/util.hpp>

TEST(AgradFwdOperatorEqual, Fvar) {
  using stan::agrad::fvar;
  fvar<double> v4 = 4;
  fvar<double> v5 = 5;
  double d4 = 4;
  double d5 = 5;

  EXPECT_FALSE(v5 == v4);
  EXPECT_FALSE(d5 == v4);
  EXPECT_FALSE(v5 == d4);
  EXPECT_FALSE(d5 == d4);

  int i4 = 4;
  int i5 = 5;
  int i6 = 5;

  EXPECT_FALSE(i5 == v4);
  EXPECT_FALSE(v5 == i4);
  EXPECT_FALSE(i5 == i4);
  EXPECT_FALSE(d5 == i4);
  EXPECT_FALSE(i5 == d4);
  EXPECT_TRUE(i6 == i5);
  EXPECT_TRUE(i6 == v5);
}

TEST(AgradFwdOperatorEqual, FvarVar) {
  using stan::agrad::fvar;
  using stan::agrad::var;

  fvar<var> x(0.5,1.3);
  fvar<var> y(1.5,1.0);
  fvar<var> z(0.5,1.3);

  EXPECT_TRUE(x == z);
  EXPECT_FALSE(x == y);
  EXPECT_FALSE(z == y);
}

TEST(AgradFwdOperatorEqual, FvarFvarDouble) {
  using stan::agrad::fvar;

  fvar<fvar<double> > x;
  x.val_.val_ = 1.5;
  x.val_.d_ = 1.0;

  fvar<fvar<double> > y;
  y.val_.val_ = 0.5;
  y.d_.val_ = 1.0;

  fvar<fvar<double> > z;
  z.val_.val_ = 0.5;
  z.d_.val_ = 1.0;

  EXPECT_FALSE(x == y);
  EXPECT_FALSE(x == z);
  EXPECT_TRUE(z == y);
}

TEST(AgradFwdOperatorEqual, FvarFvarVar) {
  using stan::agrad::fvar;
  using stan::agrad::var;

  fvar<fvar<var> > x;
  x.val_.val_ = 1.5;
  x.val_.d_ = 1.0;

  fvar<fvar<var> > y;
  y.val_.val_ = 0.5;
  y.d_.val_ = 1.0;

  fvar<fvar<var> > z;
  z.val_.val_ = 0.5;
  z.d_.val_ = 1.0;

  EXPECT_FALSE(x == y);
  EXPECT_FALSE(x == z);
  EXPECT_TRUE(z == y);
}

TEST(AgradFwdOperatorEqual, eq_nan) {
  using stan::agrad::fvar;
  using stan::agrad::var;
  double nan = std::numeric_limits<double>::quiet_NaN();
  double a = 3.0;
  fvar<double> nan_fd = std::numeric_limits<double>::quiet_NaN();
  fvar<double> a_fd = 3.0;
  fvar<var> nan_fv = std::numeric_limits<double>::quiet_NaN();
  fvar<var> a_fv = 3.0;
  fvar<fvar<double> > nan_ffd = std::numeric_limits<double>::quiet_NaN();
  fvar<fvar<double> > a_ffd = 3.0;
  fvar<fvar<var> > nan_ffv = std::numeric_limits<double>::quiet_NaN();
  fvar<fvar<var> > a_ffv = 3.0;

  EXPECT_FALSE(a == nan_fd);
  EXPECT_FALSE(a_fd == nan_fd);
  EXPECT_FALSE(nan == nan_fd);
  EXPECT_FALSE(nan_fd == nan_fd);
  EXPECT_FALSE(a_fd == nan);
  EXPECT_FALSE(nan_fd == nan);
  EXPECT_FALSE(nan_fd == a);
  EXPECT_FALSE(nan_fd == a_fd);
  EXPECT_FALSE(nan == a_fd);

  EXPECT_FALSE(a == nan_fv);
  EXPECT_FALSE(a_fv == nan_fv);
  EXPECT_FALSE(nan == nan_fv);
  EXPECT_FALSE(nan_fv == nan_fv);
  EXPECT_FALSE(a_fv == nan);
  EXPECT_FALSE(nan_fv == nan);
  EXPECT_FALSE(nan_fv == a);
  EXPECT_FALSE(nan_fv == a_fv);
  EXPECT_FALSE(nan == a_fv);

  EXPECT_FALSE(a == nan_ffd);
  EXPECT_FALSE(a_ffd == nan_ffd);
  EXPECT_FALSE(nan == nan_ffd);
  EXPECT_FALSE(nan_ffd == nan_ffd);
  EXPECT_FALSE(a_ffd == nan);
  EXPECT_FALSE(nan_ffd == nan);
  EXPECT_FALSE(nan_ffd == a);
  EXPECT_FALSE(nan_ffd == a_ffd);
  EXPECT_FALSE(nan == a_ffd);

  EXPECT_FALSE(a == nan_ffv);
  EXPECT_FALSE(a_ffv == nan_ffv);
  EXPECT_FALSE(nan == nan_ffv);
  EXPECT_FALSE(nan_ffv == nan_ffv);
  EXPECT_FALSE(a_ffv == nan);
  EXPECT_FALSE(nan_ffv == nan);
  EXPECT_FALSE(nan_ffv == a);
  EXPECT_FALSE(nan_ffv == a_ffv);
  EXPECT_FALSE(nan == a_ffv);
}
<|endoftext|>


<commit_before>#include <stan/services/util/generate_transitions.hpp>
#include <gtest/gtest.h>
#include <stan/io/empty_var_context.hpp>
#include <test/test-models/good/optimization/rosenbrock.hpp>
#include <test/unit/services/instrumented_callbacks.hpp>
#include <iostream>
#include <exception>

class ServicesSamplesGenerateTransitions : public testing::Test {
public:
  ServicesSamplesGenerateTransitions()
    : model(context, &model_log) {}

  std::stringstream model_log;
  stan::test::unit::instrumented_writer message, init, error;
  stan::test::unit::instrumented_writer parameter, diagnostic;
  stan::io::empty_var_context context;
  stan_model model;
};

TEST_F(ServicesSamplesGenerateTransitions, rosenbrock) {
  unsigned int seed = 0;
  unsigned int chain = 1;
  double init_radius = 0;
  int refresh = 0;
  int num_iterations = 10;
  stan::test::unit::instrumented_interrupt interrupt;
  EXPECT_EQ(interrupt.call_count(), 0);

  boost::ecuyer1988 rng = stan::services::util::rng(seed, chain);

  std::vector<int> disc_vector;
  std::vector<double> cont_vector
    = stan::services::util::initialize(model, context, rng, init_radius,
                                       false,
                                       message, diagnostic);

  stan::mcmc::fixed_param_sampler sampler;
  stan::services::sample::mcmc_writer
    writer(parameter, diagnostic, message);
  Eigen::VectorXd cont_params(cont_vector.size());
  for (size_t i = 0; i < cont_vector.size(); i++)
    cont_params[i] = cont_vector[i];
  stan::mcmc::sample s(cont_params, 0, 0);

  writer.write_sample_names(s, sampler, model);
  writer.write_diagnostic_names(s, sampler, model);

  stan::services::util::generate_transitions(
    sampler, num_iterations, 0, 20, 1, refresh, true, false, writer,
    s, model, rng, interrupt, message, error);

  // Expect interrupt to be called once per iteration.
  EXPECT_EQ(interrupt.call_count(), num_iterations);

  // Expect no messages, no init messages, and no error messages.
  EXPECT_EQ(message.call_count(), 0);
  EXPECT_EQ(init.call_count(), 0);
  EXPECT_EQ(error.call_count(), 0);

  // Expect on call to set parameter names, and one set of output per
  // iteration.
  EXPECT_EQ(parameter.call_count("vector_string"), 1);
  EXPECT_EQ(parameter.call_count("vector_double"), num_iterations);

  std::vector<std::vector<std::string> > parameter_names;
  parameter_names = parameter.vector_string_values();
  EXPECT_EQ(parameter_names[0][0], "lp__");
  EXPECT_EQ(parameter_names[0][1], "accept_stat__");
  std::vector<std::vector<double> > parameter_values;
  parameter_values = parameter.vector_double_values();

  // Expect one parameter name per parameter value.
  EXPECT_EQ(parameter_names[0].size(), parameter_values[0].size());

  // Expect one call to set parameter names, and one set of output per
  // iteration, not sure where the "+1" is coming from yet...
  EXPECT_EQ(diagnostic.call_count("vector_string"), 1);
  EXPECT_EQ(diagnostic.call_count("vector_double"), num_iterations + 1);
  std::vector<std::vector<std::string> > diagnostic_names;
  diagnostic_names = diagnostic.vector_string_values();
  EXPECT_EQ(diagnostic_names[0][0], "lp__");
  EXPECT_EQ(diagnostic_names[0][1], "accept_stat__");
  std::vector<std::vector<double> > diagnostic_values;
  diagnostic_values = diagnostic.vector_double_values();
  EXPECT_EQ(diagnostic_names[0].size(), diagnostic_values[0].size());

}

<commit_msg>generate_transitions basic test split up to call counting and output sizes/names.<commit_after>#include <stan/services/util/generate_transitions.hpp>
#include <stan/services/sample/fixed_param.hpp>
#include <stan/services/util/initialize.hpp>
#include <stan/services/util/rng.hpp>
#include <gtest/gtest.h>
#include <stan/io/empty_var_context.hpp>
#include <test/test-models/good/optimization/rosenbrock.hpp>
#include <test/unit/services/instrumented_callbacks.hpp>
#include <iostream>
#include <exception>

class ServicesSamplesGenerateTransitions : public testing::Test {
public:
  ServicesSamplesGenerateTransitions()
    : model(context, &model_log) {}

  std::stringstream model_log;
  stan::test::unit::instrumented_writer message, init, error;
  stan::test::unit::instrumented_writer parameter, diagnostic;
  stan::io::empty_var_context context;
  stan_model model;
};

TEST_F(ServicesSamplesGenerateTransitions, call_counting) {
  unsigned int seed = 0;
  unsigned int chain = 1;
  double init_radius = 0;
  int refresh = 0;
  int num_iterations = 10;
  stan::test::unit::instrumented_interrupt interrupt;
  EXPECT_EQ(interrupt.call_count(), 0);

  boost::ecuyer1988 rng = stan::services::util::rng(seed, chain);

  std::vector<int> disc_vector;
  std::vector<double> cont_vector
    = stan::services::util::initialize(model, context, rng, init_radius,
                                       false,
                                       message, diagnostic);

  stan::mcmc::fixed_param_sampler sampler;
  stan::services::sample::mcmc_writer
    writer(parameter, diagnostic, message);
  Eigen::VectorXd cont_params(cont_vector.size());
  for (size_t i = 0; i < cont_vector.size(); i++)
    cont_params[i] = cont_vector[i];
  stan::mcmc::sample s(cont_params, 0, 0);

  writer.write_sample_names(s, sampler, model);
  writer.write_diagnostic_names(s, sampler, model);

  stan::services::util::generate_transitions(
    sampler, num_iterations, 0, 20, 1, refresh, true, false, writer,
    s, model, rng, interrupt, message, error);

  std::vector<std::vector<std::string> > parameter_names;
  parameter_names = parameter.vector_string_values();
  std::vector<std::vector<double> > parameter_values;
  parameter_values = parameter.vector_double_values();
  std::vector<std::vector<std::string> > diagnostic_names;
  diagnostic_names = diagnostic.vector_string_values();
  std::vector<std::vector<double> > diagnostic_values;
  diagnostic_values = diagnostic.vector_double_values();

  // Expect interrupt to be called once per iteration.
  EXPECT_EQ(interrupt.call_count(), num_iterations);

  // Expect no messages, no init messages, and no error messages.
  EXPECT_EQ(message.call_count(), 0);
  EXPECT_EQ(init.call_count(), 0);
  EXPECT_EQ(error.call_count(), 0);

  // Expect on call to set parameter names, and one set of output per
  // iteration.
  EXPECT_EQ(parameter.call_count("vector_string"), 1);
  EXPECT_EQ(parameter.call_count("vector_double"), num_iterations);

  // Expect one call to set parameter names, and one set of output per
  // iteration, not sure where the "+1" is coming from yet...
  EXPECT_EQ(diagnostic.call_count("vector_string"), 1);
  EXPECT_EQ(diagnostic.call_count("vector_double"), num_iterations + 1);

}

TEST_F(ServicesSamplesGenerateTransitions, output_sizes) {
  unsigned int seed = 0;
  unsigned int chain = 1;
  double init_radius = 0;
  int refresh = 0;
  int num_iterations = 10;
  stan::test::unit::instrumented_interrupt interrupt;
  EXPECT_EQ(interrupt.call_count(), 0);

  boost::ecuyer1988 rng = stan::services::util::rng(seed, chain);

  std::vector<int> disc_vector;
  std::vector<double> cont_vector
    = stan::services::util::initialize(model, context, rng, init_radius,
                                       false,
                                       message, diagnostic);

  stan::mcmc::fixed_param_sampler sampler;
  stan::services::sample::mcmc_writer
    writer(parameter, diagnostic, message);
  Eigen::VectorXd cont_params(cont_vector.size());
  for (size_t i = 0; i < cont_vector.size(); i++)
    cont_params[i] = cont_vector[i];
  stan::mcmc::sample s(cont_params, 0, 0);

  writer.write_sample_names(s, sampler, model);
  writer.write_diagnostic_names(s, sampler, model);

  stan::services::util::generate_transitions(
    sampler, num_iterations, 0, 20, 1, refresh, true, false, writer,
    s, model, rng, interrupt, message, error);

  std::vector<std::vector<std::string> > parameter_names;
  parameter_names = parameter.vector_string_values();
  std::vector<std::vector<double> > parameter_values;
  parameter_values = parameter.vector_double_values();
  std::vector<std::vector<std::string> > diagnostic_names;
  diagnostic_names = diagnostic.vector_string_values();
  std::vector<std::vector<double> > diagnostic_values;
  diagnostic_values = diagnostic.vector_double_values();

  // First parameters are log density and acceptance prob.
  EXPECT_EQ(parameter_names[0][0], "lp__");
  EXPECT_EQ(parameter_names[0][1], "accept_stat__");

  // First diagnostic parameters are log density and acceptance
  // prob.
  EXPECT_EQ(diagnostic_names[0][0], "lp__");
  EXPECT_EQ(diagnostic_names[0][1], "accept_stat__");

  // Expect one parameter name per parameter value.
  EXPECT_EQ(parameter_names[0].size(), parameter_values[0].size());
  EXPECT_EQ(diagnostic_names[0].size(), diagnostic_values[0].size());

}

<|endoftext|>