<commit_before>#include <crypto/crypto_encryption.h>

#include <event/event_callback.h>
#include <event/event_main.h>
#include <event/event_system.h>

#include <io/net/tcp_server.h>

#include <io/pipe/pipe.h>
#include <io/pipe/pipe_producer.h>
#include <io/pipe/splice.h>

#include <io/socket/simple_server.h>

#include <ssh/ssh_algorithm_negotiation.h>
#include <ssh/ssh_protocol.h>
#include <ssh/ssh_server_host_key.h>
#include <ssh/ssh_session.h>
#include <ssh/ssh_transport_pipe.h>

/*
 * XXX Create an SSH chat program.  Let only one of each user be connected at a time.  Send lines of data to all others.
 */

class SSHConnection {
	struct SSHChannel {
		uint32_t local_channel_;
		uint32_t local_window_size_;
		uint32_t local_packet_size_;
		uint32_t remote_channel_;
		uint32_t remote_window_size_;
		uint32_t remote_packet_size_;

		std::map<std::string, Buffer> environment_;

		SSHChannel(uint32_t local_channel, uint32_t remote_channel, uint32_t local_window_size, uint32_t local_packet_size, uint32_t remote_window_size, uint32_t remote_packet_size)
		: local_channel_(local_channel),
		  local_window_size_(local_window_size),
		  local_packet_size_(local_packet_size),
		  remote_channel_(remote_channel),
		  remote_window_size_(remote_window_size),
		  remote_packet_size_(remote_packet_size),
		  environment_()
		{ }
	};

	LogHandle log_;
	Socket *peer_;
	SSH::Session session_;
	SSH::TransportPipe *pipe_;
	Action *receive_action_;
	Splice *splice_;
	Action *splice_action_;
	Action *close_action_;
	uint32_t channel_next_;
	std::map<uint32_t, SSHChannel *> channel_map_;
	std::map<uint32_t, uint32_t> remote_channel_map_;
public:
	SSHConnection(Socket *peer)
	: log_("/ssh/connection"),
	  peer_(peer),
	  session_(SSH::ServerRole),
	  pipe_(NULL),
	  splice_(NULL),
	  splice_action_(NULL),
	  close_action_(NULL),
	  channel_next_(0),
	  channel_map_()
	{
		session_.algorithm_negotiation_ = new SSH::AlgorithmNegotiation(&session_);
		if (session_.role_ == SSH::ServerRole) {
			SSH::ServerHostKey *server_host_key = SSH::ServerHostKey::server(&session_, "ssh-server1.pem");
			session_.algorithm_negotiation_->add_algorithm(server_host_key);
		}
		session_.algorithm_negotiation_->add_algorithms();

		pipe_ = new SSH::TransportPipe(&session_);
		EventCallback *rcb = callback(this, &SSHConnection::receive_complete);
		receive_action_ = pipe_->receive(rcb);

		splice_ = new Splice(log_ + "/splice", peer_, pipe_, peer_);
		EventCallback *cb = callback(this, &SSHConnection::splice_complete);
		splice_action_ = splice_->start(cb);
	}

	~SSHConnection()
	{
		ASSERT(log_, close_action_ == NULL);
		ASSERT(log_, splice_action_ == NULL);
		ASSERT(log_, splice_ == NULL);
		ASSERT(log_, receive_action_ == NULL);
		ASSERT(log_, pipe_ == NULL);
		ASSERT(log_, peer_ == NULL);
	}

private:
	void receive_complete(Event e)
	{
		receive_action_->cancel();
		receive_action_ = NULL;

		switch (e.type_) {
		case Event::Done:
			break;
		default:
			ERROR(log_) << "Unexpected event while waiting for a packet: " << e;
			return;
		}

		ASSERT(log_, !e.buffer_.empty());

		Buffer service;
		Buffer type;
		Buffer msg;
		SSHChannel *channel;
		uint32_t recipient_channel, sender_channel, window_size, packet_size;
		bool want_reply;
		std::map<uint32_t, uint32_t>::const_iterator rchit;
		std::map<uint32_t, SSHChannel *>::const_iterator chit;
		switch (e.buffer_.peek()) {
		case SSH::Message::TransportDisconnectMessage:
			break;
		case SSH::Message::TransportServiceRequestMessage:
			/* Claim to support any kind of service the client requests.  */
			e.buffer_.skip(1);
			if (e.buffer_.empty()) {
				ERROR(log_) << "No service name after transport request.";
				return;
			}
			if (!SSH::String::decode(&service, &e.buffer_)) {
				ERROR(log_) << "Could not decode service name.";
				return;
			}
			if (!e.buffer_.empty()) {
				ERROR(log_) << "Extraneous data after service name.";
				return;
			}

			msg.append(SSH::Message::TransportServiceAcceptMessage);
			SSH::String::encode(&msg, service);
			pipe_->send(&msg);

			if (service.equal("ssh-userauth")) {
				msg.append(SSH::Message::UserAuthenticationBannerMessage);
				SSH::String::encode(&msg, std::string(" *\r\n\007 * This is a test server.  Sessions, including authentication, may be logged.\r\n *\r\n"));
				SSH::String::encode(&msg, std::string("en-CA"));
				pipe_->send(&msg);
			}
			break;
		case SSH::Message::UserAuthenticationRequestMessage:
			/* Any authentication request succeeds.  */
			e.buffer_.skip(1);
			msg.append(SSH::Message::UserAuthenticationSuccessMessage);
			pipe_->send(&msg);
			break;
		case SSH::Message::ConnectionChannelOpen:
			/* Opening a channel.  */
			e.buffer_.skip(1);
			if (e.buffer_.empty()) {
				ERROR(log_) << "No channel type after channel open.";
				return;
			}
			if (!SSH::String::decode(&type, &e.buffer_)) {
				ERROR(log_) << "Could not decode channel type.";
				return;
			}
			if (!SSH::UInt32::decode(&sender_channel, &e.buffer_)) {
				ERROR(log_) << "Could not decode sender channel.";
				return;
			}
			if (!SSH::UInt32::decode(&window_size, &e.buffer_)) {
				ERROR(log_) << "Could not decode window size.";
				return;
			}
			if (!SSH::UInt32::decode(&packet_size, &e.buffer_)) {
				ERROR(log_) << "Could not decode packet size.";
				return;
			}

			/* Only support session channels.  */
			if (!type.equal("session")) {
				msg.append(SSH::Message::ConnectionChannelOpenFailure);
				SSH::UInt32::encode(&msg, sender_channel);
				SSH::UInt32::encode(&msg, 3);
				SSH::String::encode(&msg, std::string("Unsupported session type."));
				SSH::String::encode(&msg, std::string("en-CA"));
				pipe_->send(&msg);
				return;
			}

			recipient_channel = sender_channel;
			sender_channel = channel_setup(recipient_channel, window_size, packet_size);

			/* Set up session.  */
			msg.append(SSH::Message::ConnectionChannelOpenConfirmation);
			SSH::UInt32::encode(&msg, recipient_channel);
			SSH::UInt32::encode(&msg, sender_channel);
			SSH::UInt32::encode(&msg, window_size);
			SSH::UInt32::encode(&msg, packet_size);
			pipe_->send(&msg);
			break;
		case SSH::Message::ConnectionChannelRequest:
			/* For now just fail any channel request.  */
			e.buffer_.skip(1);
			if (e.buffer_.empty()) {
				ERROR(log_) << "No channel after channel request.";
				return;
			}
			if (!SSH::UInt32::decode(&recipient_channel, &e.buffer_)) {
				ERROR(log_) << "Could not decode recipient channel.";
				return;
			}
			if (!SSH::String::decode(&type, &e.buffer_)) {
				ERROR(log_) << "Could not decode channel request type.";
				return;
			}
			if (e.buffer_.empty()) {
				ERROR(log_) << "Missing want_reply field.";
				return;
			}
			want_reply = e.buffer_.pop();

			chit = channel_map_.find(recipient_channel);
			if (chit == channel_map_.end()) {
				if (want_reply) {
					msg.append(SSH::Message::ConnectionChannelRequestFailure);
					SSH::UInt32::encode(&msg, 0); /* XXX What to do for a request that fails due to unknown channel?  */
					pipe_->send(&msg);
				}
				break;
			}
			channel = chit->second;

			if (type.equal("pty-req")) {
				/* Fail for now.  */
			} else if (type.equal("env")) {
				Buffer keybuf;
				if (!SSH::String::decode(&keybuf, &e.buffer_)) {
					ERROR(log_) << "Could not decode environment key.";
					return;
				}

				Buffer value;
				if (!SSH::String::decode(&value, &e.buffer_)) {
					ERROR(log_) << "Could not decode environment value.";
					return;
				}

				std::string key;
				keybuf.extract(key);

				if (channel->environment_.find(key) == channel->environment_.end()) {
					channel->environment_[key] = value;

					DEBUG(log_) << "Client set environment variable.";
					if (want_reply) {
						msg.append(SSH::Message::ConnectionChannelRequestSuccess);
						SSH::UInt32::encode(&msg, channel->remote_channel_);
						pipe_->send(&msg);
					}
					break;
				}
				INFO(log_) << "Client attempted to set environment variable twice.";
				if (want_reply) {
					msg.append(SSH::Message::ConnectionChannelRequestFailure);
					SSH::UInt32::encode(&msg, channel->remote_channel_);
					pipe_->send(&msg);
				}
				break;
			} else if (type.equal("shell")) {
				if (want_reply) {
					msg.append(SSH::Message::ConnectionChannelRequestSuccess);
					SSH::UInt32::encode(&msg, channel->remote_channel_);
					pipe_->send(&msg);
				}
				break;
			} else {
				DEBUG(log_) << "Unhandled channel request type:" << std::endl << type.hexdump();
			}

			if (want_reply) {
				msg.append(SSH::Message::ConnectionChannelRequestFailure);
				SSH::UInt32::encode(&msg, channel->remote_channel_);
				pipe_->send(&msg);
			}
			break;
		case SSH::Message::ConnectionChannelWindowAdjust:
			/* Follow our peer's lead on window adjustments.  */
		case SSH::Message::ConnectionChannelData:
			/* Just echo data back.  We do not need to decode at present because channels are the same in both directions.  */
			pipe_->send(&e.buffer_);
			break;
		default:
			DEBUG(log_) << "Unhandled message:" << std::endl << e.buffer_.hexdump();
			break;
		}

		EventCallback *rcb = callback(this, &SSHConnection::receive_complete);
		receive_action_ = pipe_->receive(rcb);
	}

	void close_complete(void)
	{
		close_action_->cancel();
		close_action_ = NULL;

		ASSERT(log_, peer_ != NULL);
		delete peer_;
		peer_ = NULL;

		delete this;
	}

	void splice_complete(Event e)
	{
		splice_action_->cancel();
		splice_action_ = NULL;

		switch (e.type_) {
		case Event::EOS:
			DEBUG(log_) << "Peer exiting normally.";
			break;
		case Event::Error:
			ERROR(log_) << "Peer exiting with error: " << e;
			break;
		default:
			ERROR(log_) << "Peer exiting with unknown event: " << e;
			break;
		}

	        ASSERT(log_, splice_ != NULL);
		delete splice_;
		splice_ = NULL;

		if (receive_action_ != NULL) {
			INFO(log_) << "Peer exiting while waiting for a packet.";

			receive_action_->cancel();
			receive_action_ = NULL;
		}

		ASSERT(log_, pipe_ != NULL);
		delete pipe_;
		pipe_ = NULL;

		ASSERT(log_, close_action_ == NULL);
		SimpleCallback *cb = callback(this, &SSHConnection::close_complete);
		close_action_ = peer_->close(cb);
	}

	uint32_t channel_setup(const uint32_t& remote_channel, const uint32_t& window_size, const uint32_t& packet_size)
	{
		std::map<uint32_t, SSHChannel *>::const_iterator it;
		uint32_t local_channel;

		uint32_t next = channel_next_;
		for (;;) {
			it = channel_map_.find(next);
			if (it == channel_map_.end())
				break;
			next++;
		}
		channel_next_ = next + 1;

		local_channel = next;
		channel_map_[local_channel] = new SSHChannel(local_channel, remote_channel, 65536, 65536, window_size, packet_size);
		return (local_channel);
	}
};

class SSHServer : public SimpleServer<TCPServer> {
public:
	SSHServer(SocketAddressFamily family, const std::string& interface)
	: SimpleServer<TCPServer>("/ssh/server", family, interface)
	{ }

	~SSHServer()
	{ }

	void client_connected(Socket *client)
	{
		new SSHConnection(client);
	}
};

int
main(void)
{
	new SSHServer(SocketAddressFamilyIP, "[::]:2299");
	event_main();
}
<commit_msg>Enforce the provision that says that only a single resource may be connected to a session channel.<commit_after>#include <crypto/crypto_encryption.h>

#include <event/event_callback.h>
#include <event/event_main.h>
#include <event/event_system.h>

#include <io/net/tcp_server.h>

#include <io/pipe/pipe.h>
#include <io/pipe/pipe_producer.h>
#include <io/pipe/splice.h>

#include <io/socket/simple_server.h>

#include <ssh/ssh_algorithm_negotiation.h>
#include <ssh/ssh_protocol.h>
#include <ssh/ssh_server_host_key.h>
#include <ssh/ssh_session.h>
#include <ssh/ssh_transport_pipe.h>

/*
 * XXX Create an SSH chat program.  Let only one of each user be connected at a time.  Send lines of data to all others.
 */

class SSHConnection {
	struct SSHChannel {
		enum Mode {
			SetupMode,
			ShellMode,
			ExecMode,
			SubsystemMode
		};

		Mode mode_;

		uint32_t local_channel_;
		uint32_t local_window_size_;
		uint32_t local_packet_size_;
		uint32_t remote_channel_;
		uint32_t remote_window_size_;
		uint32_t remote_packet_size_;

		std::map<std::string, Buffer> environment_;

		SSHChannel(uint32_t local_channel, uint32_t remote_channel, uint32_t local_window_size, uint32_t local_packet_size, uint32_t remote_window_size, uint32_t remote_packet_size)
		: mode_(SetupMode),
		  local_channel_(local_channel),
		  local_window_size_(local_window_size),
		  local_packet_size_(local_packet_size),
		  remote_channel_(remote_channel),
		  remote_window_size_(remote_window_size),
		  remote_packet_size_(remote_packet_size),
		  environment_()
		{ }
	};

	LogHandle log_;
	Socket *peer_;
	SSH::Session session_;
	SSH::TransportPipe *pipe_;
	Action *receive_action_;
	Splice *splice_;
	Action *splice_action_;
	Action *close_action_;
	uint32_t channel_next_;
	std::map<uint32_t, SSHChannel *> channel_map_;
	std::map<uint32_t, uint32_t> remote_channel_map_;
public:
	SSHConnection(Socket *peer)
	: log_("/ssh/connection"),
	  peer_(peer),
	  session_(SSH::ServerRole),
	  pipe_(NULL),
	  splice_(NULL),
	  splice_action_(NULL),
	  close_action_(NULL),
	  channel_next_(0),
	  channel_map_()
	{
		session_.algorithm_negotiation_ = new SSH::AlgorithmNegotiation(&session_);
		if (session_.role_ == SSH::ServerRole) {
			SSH::ServerHostKey *server_host_key = SSH::ServerHostKey::server(&session_, "ssh-server1.pem");
			session_.algorithm_negotiation_->add_algorithm(server_host_key);
		}
		session_.algorithm_negotiation_->add_algorithms();

		pipe_ = new SSH::TransportPipe(&session_);
		EventCallback *rcb = callback(this, &SSHConnection::receive_complete);
		receive_action_ = pipe_->receive(rcb);

		splice_ = new Splice(log_ + "/splice", peer_, pipe_, peer_);
		EventCallback *cb = callback(this, &SSHConnection::splice_complete);
		splice_action_ = splice_->start(cb);
	}

	~SSHConnection()
	{
		ASSERT(log_, close_action_ == NULL);
		ASSERT(log_, splice_action_ == NULL);
		ASSERT(log_, splice_ == NULL);
		ASSERT(log_, receive_action_ == NULL);
		ASSERT(log_, pipe_ == NULL);
		ASSERT(log_, peer_ == NULL);
	}

private:
	void receive_complete(Event e)
	{
		receive_action_->cancel();
		receive_action_ = NULL;

		switch (e.type_) {
		case Event::Done:
			break;
		default:
			ERROR(log_) << "Unexpected event while waiting for a packet: " << e;
			return;
		}

		ASSERT(log_, !e.buffer_.empty());

		Buffer service;
		Buffer type;
		Buffer msg;
		SSHChannel *channel;
		uint32_t recipient_channel, sender_channel, window_size, packet_size;
		bool want_reply;
		std::map<uint32_t, uint32_t>::const_iterator rchit;
		std::map<uint32_t, SSHChannel *>::const_iterator chit;
		switch (e.buffer_.peek()) {
		case SSH::Message::TransportDisconnectMessage:
			break;
		case SSH::Message::TransportServiceRequestMessage:
			/* Claim to support any kind of service the client requests.  */
			e.buffer_.skip(1);
			if (e.buffer_.empty()) {
				ERROR(log_) << "No service name after transport request.";
				return;
			}
			if (!SSH::String::decode(&service, &e.buffer_)) {
				ERROR(log_) << "Could not decode service name.";
				return;
			}
			if (!e.buffer_.empty()) {
				ERROR(log_) << "Extraneous data after service name.";
				return;
			}

			msg.append(SSH::Message::TransportServiceAcceptMessage);
			SSH::String::encode(&msg, service);
			pipe_->send(&msg);

			if (service.equal("ssh-userauth")) {
				msg.append(SSH::Message::UserAuthenticationBannerMessage);
				SSH::String::encode(&msg, std::string(" *\r\n\007 * This is a test server.  Sessions, including authentication, may be logged.\r\n *\r\n"));
				SSH::String::encode(&msg, std::string("en-CA"));
				pipe_->send(&msg);
			}
			break;
		case SSH::Message::UserAuthenticationRequestMessage:
			/* Any authentication request succeeds.  */
			e.buffer_.skip(1);
			msg.append(SSH::Message::UserAuthenticationSuccessMessage);
			pipe_->send(&msg);
			break;
		case SSH::Message::ConnectionChannelOpen:
			/* Opening a channel.  */
			e.buffer_.skip(1);
			if (e.buffer_.empty()) {
				ERROR(log_) << "No channel type after channel open.";
				return;
			}
			if (!SSH::String::decode(&type, &e.buffer_)) {
				ERROR(log_) << "Could not decode channel type.";
				return;
			}
			if (!SSH::UInt32::decode(&sender_channel, &e.buffer_)) {
				ERROR(log_) << "Could not decode sender channel.";
				return;
			}
			if (!SSH::UInt32::decode(&window_size, &e.buffer_)) {
				ERROR(log_) << "Could not decode window size.";
				return;
			}
			if (!SSH::UInt32::decode(&packet_size, &e.buffer_)) {
				ERROR(log_) << "Could not decode packet size.";
				return;
			}

			/* Only support session channels.  */
			if (!type.equal("session")) {
				msg.append(SSH::Message::ConnectionChannelOpenFailure);
				SSH::UInt32::encode(&msg, sender_channel);
				SSH::UInt32::encode(&msg, 3);
				SSH::String::encode(&msg, std::string("Unsupported session type."));
				SSH::String::encode(&msg, std::string("en-CA"));
				pipe_->send(&msg);
				return;
			}

			recipient_channel = sender_channel;
			sender_channel = channel_setup(recipient_channel, window_size, packet_size);

			/* Set up session.  */
			msg.append(SSH::Message::ConnectionChannelOpenConfirmation);
			SSH::UInt32::encode(&msg, recipient_channel);
			SSH::UInt32::encode(&msg, sender_channel);
			SSH::UInt32::encode(&msg, window_size);
			SSH::UInt32::encode(&msg, packet_size);
			pipe_->send(&msg);
			break;
		case SSH::Message::ConnectionChannelRequest:
			/* For now just fail any channel request.  */
			e.buffer_.skip(1);
			if (e.buffer_.empty()) {
				ERROR(log_) << "No channel after channel request.";
				return;
			}
			if (!SSH::UInt32::decode(&recipient_channel, &e.buffer_)) {
				ERROR(log_) << "Could not decode recipient channel.";
				return;
			}
			if (!SSH::String::decode(&type, &e.buffer_)) {
				ERROR(log_) << "Could not decode channel request type.";
				return;
			}
			if (e.buffer_.empty()) {
				ERROR(log_) << "Missing want_reply field.";
				return;
			}
			want_reply = e.buffer_.pop();

			chit = channel_map_.find(recipient_channel);
			if (chit == channel_map_.end()) {
				if (want_reply) {
					msg.append(SSH::Message::ConnectionChannelRequestFailure);
					SSH::UInt32::encode(&msg, 0); /* XXX What to do for a request that fails due to unknown channel?  */
					pipe_->send(&msg);
				}
				break;
			}
			channel = chit->second;

			if (type.equal("pty-req")) {
				/* Fail for now.  */
			} else if (type.equal("env")) {
				Buffer keybuf;
				if (!SSH::String::decode(&keybuf, &e.buffer_)) {
					ERROR(log_) << "Could not decode environment key.";
					return;
				}

				Buffer value;
				if (!SSH::String::decode(&value, &e.buffer_)) {
					ERROR(log_) << "Could not decode environment value.";
					return;
				}

				std::string key;
				keybuf.extract(key);

				if (channel->environment_.find(key) == channel->environment_.end()) {
					channel->environment_[key] = value;

					DEBUG(log_) << "Client set environment variable.";
					if (want_reply) {
						msg.append(SSH::Message::ConnectionChannelRequestSuccess);
						SSH::UInt32::encode(&msg, channel->remote_channel_);
						pipe_->send(&msg);
					}
					break;
				}
				INFO(log_) << "Client attempted to set environment variable twice.";
				if (want_reply) {
					msg.append(SSH::Message::ConnectionChannelRequestFailure);
					SSH::UInt32::encode(&msg, channel->remote_channel_);
					pipe_->send(&msg);
				}
				break;
			} else if (type.equal("shell")) {
				if (channel->mode_ == SSHChannel::SetupMode) {
					channel->mode_ = SSHChannel::ShellMode;
					if (want_reply) {
						msg.append(SSH::Message::ConnectionChannelRequestSuccess);
						SSH::UInt32::encode(&msg, channel->remote_channel_);
						pipe_->send(&msg);
					}
					break;
				}
				ERROR(log_) << "Client requested a shell session, but session is not in setup mode.";
			} else {
				DEBUG(log_) << "Unhandled channel request type:" << std::endl << type.hexdump();
			}

			if (want_reply) {
				msg.append(SSH::Message::ConnectionChannelRequestFailure);
				SSH::UInt32::encode(&msg, channel->remote_channel_);
				pipe_->send(&msg);
			}
			break;
		case SSH::Message::ConnectionChannelWindowAdjust:
			/* Follow our peer's lead on window adjustments.  */
		case SSH::Message::ConnectionChannelData:
			/* Just echo data back.  We do not need to decode at present because channels are the same in both directions.  */
			pipe_->send(&e.buffer_);
			break;
		default:
			DEBUG(log_) << "Unhandled message:" << std::endl << e.buffer_.hexdump();
			break;
		}

		EventCallback *rcb = callback(this, &SSHConnection::receive_complete);
		receive_action_ = pipe_->receive(rcb);
	}

	void close_complete(void)
	{
		close_action_->cancel();
		close_action_ = NULL;

		ASSERT(log_, peer_ != NULL);
		delete peer_;
		peer_ = NULL;

		delete this;
	}

	void splice_complete(Event e)
	{
		splice_action_->cancel();
		splice_action_ = NULL;

		switch (e.type_) {
		case Event::EOS:
			DEBUG(log_) << "Peer exiting normally.";
			break;
		case Event::Error:
			ERROR(log_) << "Peer exiting with error: " << e;
			break;
		default:
			ERROR(log_) << "Peer exiting with unknown event: " << e;
			break;
		}

	        ASSERT(log_, splice_ != NULL);
		delete splice_;
		splice_ = NULL;

		if (receive_action_ != NULL) {
			INFO(log_) << "Peer exiting while waiting for a packet.";

			receive_action_->cancel();
			receive_action_ = NULL;
		}

		ASSERT(log_, pipe_ != NULL);
		delete pipe_;
		pipe_ = NULL;

		ASSERT(log_, close_action_ == NULL);
		SimpleCallback *cb = callback(this, &SSHConnection::close_complete);
		close_action_ = peer_->close(cb);
	}

	uint32_t channel_setup(const uint32_t& remote_channel, const uint32_t& window_size, const uint32_t& packet_size)
	{
		std::map<uint32_t, SSHChannel *>::const_iterator it;
		uint32_t local_channel;

		uint32_t next = channel_next_;
		for (;;) {
			it = channel_map_.find(next);
			if (it == channel_map_.end())
				break;
			next++;
		}
		channel_next_ = next + 1;

		local_channel = next;
		channel_map_[local_channel] = new SSHChannel(local_channel, remote_channel, 65536, 65536, window_size, packet_size);
		return (local_channel);
	}
};

class SSHServer : public SimpleServer<TCPServer> {
public:
	SSHServer(SocketAddressFamily family, const std::string& interface)
	: SimpleServer<TCPServer>("/ssh/server", family, interface)
	{ }

	~SSHServer()
	{ }

	void client_connected(Socket *client)
	{
		new SSHConnection(client);
	}
};

int
main(void)
{
	new SSHServer(SocketAddressFamilyIP, "[::]:2299");
	event_main();
}
<|endoftext|>


<commit_before>/**
 * This file is part of the "libfnord" project
 *   Copyright (c) 2015 Paul Asmuth
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <csql/defaults.h>

using namespace stx;

namespace csql {

void installDefaultSymbols(SymbolTable* rt) {
  /* expressions/aggregate.h */
  rt->registerFunction("count", expressions::kCountExpr);
  rt->registerFunction("sum", expressions::kSumExpr);
  rt->registerFunction("mean", expressions::kMeanExpr);

  //rt->registerSymbol(
  //    "mean",
  //    &expressions::meanExpr,
  //    expressions::meanExprScratchpadSize(),
  //    &expressions::meanExprFree);

  //rt->registerSymbol(
  //    "avg",
  //    &expressions::meanExpr,
  //    expressions::meanExprScratchpadSize(),
  //    &expressions::meanExprFree);

  //rt->registerSymbol(
  //    "average",
  //    &expressions::meanExpr,
  //    expressions::meanExprScratchpadSize(),
  //    &expressions::meanExprFree);

  //rt->registerSymbol(
  //    "min",
  //    &expressions::minExpr,
  //    expressions::minExprScratchpadSize(),
  //    &expressions::minExprFree);

  //rt->registerSymbol(
  //    "max",
  //    &expressions::maxExpr,
  //    expressions::maxExprScratchpadSize(),
  //    &expressions::maxExprFree);

  /* expressions/boolean.h */
  rt->registerFunction("eq",  PureFunction(&expressions::eqExpr));
  rt->registerFunction("neq", PureFunction(&expressions::neqExpr));
  rt->registerFunction("and", PureFunction(&expressions::andExpr));
  rt->registerFunction("or",  PureFunction(&expressions::orExpr));
  rt->registerFunction("neg", PureFunction(&expressions::negExpr));
  rt->registerFunction("lt",  PureFunction(&expressions::ltExpr));
  rt->registerFunction("lte", PureFunction(&expressions::lteExpr));
  rt->registerFunction("gt",  PureFunction(&expressions::gtExpr));
  rt->registerFunction("gte", PureFunction(&expressions::gteExpr));

  /* expressions/UnixTime.h */
  rt->registerFunction(
      "FROM_TIMESTAMP",
      PureFunction(&expressions::fromTimestamp));

  /* expressions/math.h */
  rt->registerFunction("add", PureFunction(&expressions::addExpr));
  rt->registerFunction("sub", PureFunction(&expressions::subExpr));
  rt->registerFunction("mul", PureFunction(&expressions::mulExpr));
  rt->registerFunction("div", PureFunction(&expressions::divExpr));
  rt->registerFunction("mod", PureFunction(&expressions::modExpr));
  rt->registerFunction("pow", PureFunction(&expressions::powExpr));

}

} // namespace csql
<commit_msg>update deps<commit_after>/**
 * This file is part of the "libfnord" project
 *   Copyright (c) 2015 Paul Asmuth
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <csql/defaults.h>

using namespace stx;

namespace csql {

void installDefaultSymbols(SymbolTable* rt) {
  /* expressions/aggregate.h */
  rt->registerFunction("count", expressions::kCountExpr);
  rt->registerFunction("sum", expressions::kSumExpr);

  //rt->registerSymbol(
  //    "mean",
  //    &expressions::meanExpr,
  //    expressions::meanExprScratchpadSize(),
  //    &expressions::meanExprFree);

  //rt->registerSymbol(
  //    "avg",
  //    &expressions::meanExpr,
  //    expressions::meanExprScratchpadSize(),
  //    &expressions::meanExprFree);

  //rt->registerSymbol(
  //    "average",
  //    &expressions::meanExpr,
  //    expressions::meanExprScratchpadSize(),
  //    &expressions::meanExprFree);

  //rt->registerSymbol(
  //    "min",
  //    &expressions::minExpr,
  //    expressions::minExprScratchpadSize(),
  //    &expressions::minExprFree);

  //rt->registerSymbol(
  //    "max",
  //    &expressions::maxExpr,
  //    expressions::maxExprScratchpadSize(),
  //    &expressions::maxExprFree);

  /* expressions/boolean.h */
  rt->registerFunction("eq",  PureFunction(&expressions::eqExpr));
  rt->registerFunction("neq", PureFunction(&expressions::neqExpr));
  rt->registerFunction("and", PureFunction(&expressions::andExpr));
  rt->registerFunction("or",  PureFunction(&expressions::orExpr));
  rt->registerFunction("neg", PureFunction(&expressions::negExpr));
  rt->registerFunction("lt",  PureFunction(&expressions::ltExpr));
  rt->registerFunction("lte", PureFunction(&expressions::lteExpr));
  rt->registerFunction("gt",  PureFunction(&expressions::gtExpr));
  rt->registerFunction("gte", PureFunction(&expressions::gteExpr));

  /* expressions/UnixTime.h */
  rt->registerFunction(
      "FROM_TIMESTAMP",
      PureFunction(&expressions::fromTimestamp));

  /* expressions/math.h */
  rt->registerFunction("add", PureFunction(&expressions::addExpr));
  rt->registerFunction("sub", PureFunction(&expressions::subExpr));
  rt->registerFunction("mul", PureFunction(&expressions::mulExpr));
  rt->registerFunction("div", PureFunction(&expressions::divExpr));
  rt->registerFunction("mod", PureFunction(&expressions::modExpr));
  rt->registerFunction("pow", PureFunction(&expressions::powExpr));

}

} // namespace csql
<|endoftext|>


<commit_before>/***************************Copyright-DO-NOT-REMOVE-THIS-LINE**
 * CONDOR Copyright Notice
 *
 * See LICENSE.TXT for additional notices and disclaimers.
 *
 * Copyright (c)1990-1998 CONDOR Team, Computer Sciences Department,
 * University of Wisconsin-Madison, Madison, WI.  All Rights Reserved.
 * No use of the CONDOR Software Program Source Code is authorized
 * without the express consent of the CONDOR Team.  For more information
 * contact: CONDOR Team, Attention: Professor Miron Livny,
 * 7367 Computer Sciences, 1210 W. Dayton St., Madison, WI 53706-1685,
 * (608) 262-0856 or miron@cs.wisc.edu.
 *
 * U.S. Government Rights Restrictions: Use, duplication, or disclosure
 * by the U.S. Government is subject to restrictions as set forth in
 * subparagraph (c)(1)(ii) of The Rights in Technical Data and Computer
 * Software clause at DFARS 252.227-7013 or subparagraphs (c)(1) and
 * (2) of Commercial Computer Software-Restricted Rights at 48 CFR
 * 52.227-19, as applicable, CONDOR Team, Attention: Professor Miron
 * Livny, 7367 Computer Sciences, 1210 W. Dayton St., Madison,
 * WI 53706-1685, (608) 262-0856 or miron@cs.wisc.edu.
****************************Copyright-DO-NOT-REMOVE-THIS-LINE**/

/* Here is the version string - update before a public release */
static char* CondorVersionString = "$Version: 6.1.2 1999/01/12 $";

extern "C" {

char*
CondorVersion()
{
	return CondorVersionString;
}

} /* extern "C" */
<commit_msg>6.1.3 version string.<commit_after>/***************************Copyright-DO-NOT-REMOVE-THIS-LINE**
 * CONDOR Copyright Notice
 *
 * See LICENSE.TXT for additional notices and disclaimers.
 *
 * Copyright (c)1990-1998 CONDOR Team, Computer Sciences Department,
 * University of Wisconsin-Madison, Madison, WI.  All Rights Reserved.
 * No use of the CONDOR Software Program Source Code is authorized
 * without the express consent of the CONDOR Team.  For more information
 * contact: CONDOR Team, Attention: Professor Miron Livny,
 * 7367 Computer Sciences, 1210 W. Dayton St., Madison, WI 53706-1685,
 * (608) 262-0856 or miron@cs.wisc.edu.
 *
 * U.S. Government Rights Restrictions: Use, duplication, or disclosure
 * by the U.S. Government is subject to restrictions as set forth in
 * subparagraph (c)(1)(ii) of The Rights in Technical Data and Computer
 * Software clause at DFARS 252.227-7013 or subparagraphs (c)(1) and
 * (2) of Commercial Computer Software-Restricted Rights at 48 CFR
 * 52.227-19, as applicable, CONDOR Team, Attention: Professor Miron
 * Livny, 7367 Computer Sciences, 1210 W. Dayton St., Madison,
 * WI 53706-1685, (608) 262-0856 or miron@cs.wisc.edu.
****************************Copyright-DO-NOT-REMOVE-THIS-LINE**/

/* Here is the version string - update before a public release */
static char* CondorVersionString = "$Version: 6.1.3 1999/02/15 $";

extern "C" {

char*
CondorVersion()
{
	return CondorVersionString;
}

} /* extern "C" */
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2016, The OpenThread Authors.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. 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.
 *  3. Neither the name of the copyright holder 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 HOLDER 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.
 */

#define WPP_NAME "secure_coap_server.tmh"

#include <coap/secure_coap_server.hpp>
#include <common/logging.hpp>
#include <meshcop/dtls.hpp>
#include <thread/thread_netif.hpp>

/**
 * @file
 *   This file implements the secure CoAP server.
 */

namespace Thread {
namespace Coap {

SecureServer::SecureServer(ThreadNetif &aNetif, uint16_t aPort):
    Server(aNetif, aPort, &SecureServer::Send, &SecureServer::Receive),
    mTransmitCallback(NULL),
    mContext(NULL),
    mNetif(aNetif),
    mTransmitMessage(NULL),
    mTransmitTask(aNetif.GetIp6().mTaskletScheduler, &SecureServer::HandleUdpTransmit, this)
{
}

ThreadError SecureServer::Start(TransportCallback aCallback, void *aContext)
{
    ThreadError error = kThreadError_None;
    mTransmitCallback = aCallback;
    mContext = aContext;

    // Passing mTransmitCallback means that we do not want to use socket
    // to transmit/receive messages, so do not open it in that case.
    if (mTransmitCallback == NULL)
    {
        error = Server::Start();
    }

    return error;
}

ThreadError SecureServer::Stop()
{
    if (mNetif.GetDtls().IsStarted())
    {
        mNetif.GetDtls().Stop();
    }

    if (mTransmitMessage != NULL)
    {
        mTransmitMessage->Free();
        mTransmitMessage = NULL;
    }

    mTransmitCallback = NULL;
    mContext = NULL;

    otLogFuncExit();

    return Server::Stop();
}

bool SecureServer::IsConnectionActive(void)
{
    return mNetif.GetDtls().IsStarted();
};

ThreadError SecureServer::Send(void *aContext, Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
    return static_cast<SecureServer *>(aContext)->Send(aMessage, aMessageInfo);
}

ThreadError SecureServer::Send(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
    (void)aMessageInfo;
    return mNetif.GetDtls().Send(aMessage, aMessage.GetLength());
}

void SecureServer::Receive(void *aContext, Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
    return static_cast<SecureServer *>(aContext)->Receive(aMessage, aMessageInfo);
}

void SecureServer::Receive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
    otLogFuncEntry();

    if (!mNetif.GetDtls().IsStarted())
    {
        mPeerAddress.SetPeerAddr(aMessageInfo.GetPeerAddr());
        mPeerAddress.SetPeerPort(aMessageInfo.GetPeerPort());

        mNetif.GetDtls().Start(false, HandleDtlsConnected, HandleDtlsReceive, HandleDtlsSend, this);
    }
    else
    {
        // Once DTLS session is started, communicate only with a peer.
        VerifyOrExit((mPeerAddress.GetPeerAddr() == aMessageInfo.GetPeerAddr()) &&
                     (mPeerAddress.GetPeerPort() == aMessageInfo.GetPeerPort()), ;);
    }

    mNetif.GetDtls().SetClientId(mPeerAddress.GetPeerAddr().mFields.m8,
                                 sizeof(mPeerAddress.GetPeerAddr().mFields));
    mNetif.GetDtls().Receive(aMessage, aMessage.GetOffset(), aMessage.GetLength() - aMessage.GetOffset());

exit:
    otLogFuncExit();
}

ThreadError SecureServer::SetPsk(const uint8_t *aPsk, uint8_t aPskLength)
{
    return mNetif.GetDtls().SetPsk(aPsk, aPskLength);
}

void SecureServer::HandleDtlsConnected(void *aContext, bool aConnected)
{
    return static_cast<SecureServer *>(aContext)->HandleDtlsConnected(aConnected);
}

void SecureServer::HandleDtlsConnected(bool aConnected)
{
    (void)aConnected;
}

void SecureServer::HandleDtlsReceive(void *aContext, uint8_t *aBuf, uint16_t aLength)
{
    return static_cast<SecureServer *>(aContext)->HandleDtlsReceive(aBuf, aLength);
}

void SecureServer::HandleDtlsReceive(uint8_t *aBuf, uint16_t aLength)
{
    Message *message;

    otLogFuncEntry();

    VerifyOrExit((message = mNetif.GetIp6().mMessagePool.New(Message::kTypeIp6, 0)) != NULL, ;);
    SuccessOrExit(message->Append(aBuf, aLength));

    ProcessReceivedMessage(*message, mPeerAddress);

exit:

    if (message != NULL)
    {
        message->Free();
    }

    otLogFuncExit();
}

ThreadError SecureServer::HandleDtlsSend(void *aContext, const uint8_t *aBuf, uint16_t aLength, uint8_t aMessageSubType)
{
    return static_cast<SecureServer *>(aContext)->HandleDtlsSend(aBuf, aLength, aMessageSubType);
}

ThreadError SecureServer::HandleDtlsSend(const uint8_t *aBuf, uint16_t aLength, uint8_t aMessageSubType)
{
    ThreadError error = kThreadError_None;

    otLogFuncEntry();

    if (mTransmitMessage == NULL)
    {
        VerifyOrExit((mTransmitMessage = mSocket.NewMessage(0)) != NULL, error = kThreadError_NoBufs);
        mTransmitMessage->SetSubType(aMessageSubType);
        mTransmitMessage->SetLinkSecurityEnabled(false);
    }

    VerifyOrExit(mTransmitMessage->Append(aBuf, aLength) == kThreadError_None, error = kThreadError_NoBufs);

    mTransmitTask.Post();

exit:

    if (error != kThreadError_None && mTransmitMessage != NULL)
    {
        mTransmitMessage->Free();
    }

    otLogFuncExitErr(error);

    return error;
}

void SecureServer::HandleUdpTransmit(void *aContext)
{
    return static_cast<SecureServer *>(aContext)->HandleUdpTransmit();
}

void SecureServer::HandleUdpTransmit(void)
{
    ThreadError error = kThreadError_None;

    otLogFuncEntry();

    VerifyOrExit(mTransmitMessage != NULL, error = kThreadError_NoBufs);

    if (mTransmitCallback)
    {
        SuccessOrExit(error = mTransmitCallback(mContext, *mTransmitMessage, mPeerAddress));
    }
    else
    {
        SuccessOrExit(error = mSocket.SendTo(*mTransmitMessage, mPeerAddress));
    }

exit:

    if (error != kThreadError_None && mTransmitMessage != NULL)
    {
        mTransmitMessage->Free();
    }

    mTransmitMessage = NULL;

    otLogFuncExit();
}

}  // namespace Coap
}  // namespace Thread
<commit_msg>Fix mismatching source address of secured CoAP server (#1520)<commit_after>/*
 *  Copyright (c) 2016, The OpenThread Authors.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. 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.
 *  3. Neither the name of the copyright holder 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 HOLDER 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.
 */

#define WPP_NAME "secure_coap_server.tmh"

#include <coap/secure_coap_server.hpp>
#include <common/logging.hpp>
#include <meshcop/dtls.hpp>
#include <thread/thread_netif.hpp>

/**
 * @file
 *   This file implements the secure CoAP server.
 */

namespace Thread {
namespace Coap {

SecureServer::SecureServer(ThreadNetif &aNetif, uint16_t aPort):
    Server(aNetif, aPort, &SecureServer::Send, &SecureServer::Receive),
    mTransmitCallback(NULL),
    mContext(NULL),
    mNetif(aNetif),
    mTransmitMessage(NULL),
    mTransmitTask(aNetif.GetIp6().mTaskletScheduler, &SecureServer::HandleUdpTransmit, this)
{
}

ThreadError SecureServer::Start(TransportCallback aCallback, void *aContext)
{
    ThreadError error = kThreadError_None;
    mTransmitCallback = aCallback;
    mContext = aContext;

    // Passing mTransmitCallback means that we do not want to use socket
    // to transmit/receive messages, so do not open it in that case.
    if (mTransmitCallback == NULL)
    {
        error = Server::Start();
    }

    return error;
}

ThreadError SecureServer::Stop()
{
    if (mNetif.GetDtls().IsStarted())
    {
        mNetif.GetDtls().Stop();
    }

    if (mTransmitMessage != NULL)
    {
        mTransmitMessage->Free();
        mTransmitMessage = NULL;
    }

    mTransmitCallback = NULL;
    mContext = NULL;

    otLogFuncExit();

    return Server::Stop();
}

bool SecureServer::IsConnectionActive(void)
{
    return mNetif.GetDtls().IsStarted();
};

ThreadError SecureServer::Send(void *aContext, Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
    return static_cast<SecureServer *>(aContext)->Send(aMessage, aMessageInfo);
}

ThreadError SecureServer::Send(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
    (void)aMessageInfo;
    return mNetif.GetDtls().Send(aMessage, aMessage.GetLength());
}

void SecureServer::Receive(void *aContext, Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
    return static_cast<SecureServer *>(aContext)->Receive(aMessage, aMessageInfo);
}

void SecureServer::Receive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
    otLogFuncEntry();

    if (!mNetif.GetDtls().IsStarted())
    {
        mPeerAddress.SetPeerAddr(aMessageInfo.GetPeerAddr());
        mPeerAddress.SetPeerPort(aMessageInfo.GetPeerPort());

        if (mNetif.IsUnicastAddress(aMessageInfo.GetSockAddr()))
        {
            mPeerAddress.SetSockAddr(aMessageInfo.GetSockAddr());
        }

        mPeerAddress.SetSockPort(aMessageInfo.GetSockPort());

        mNetif.GetDtls().Start(false, HandleDtlsConnected, HandleDtlsReceive, HandleDtlsSend, this);
    }
    else
    {
        // Once DTLS session is started, communicate only with a peer.
        VerifyOrExit((mPeerAddress.GetPeerAddr() == aMessageInfo.GetPeerAddr()) &&
                     (mPeerAddress.GetPeerPort() == aMessageInfo.GetPeerPort()), ;);
    }

    mNetif.GetDtls().SetClientId(mPeerAddress.GetPeerAddr().mFields.m8,
                                 sizeof(mPeerAddress.GetPeerAddr().mFields));
    mNetif.GetDtls().Receive(aMessage, aMessage.GetOffset(), aMessage.GetLength() - aMessage.GetOffset());

exit:
    otLogFuncExit();
}

ThreadError SecureServer::SetPsk(const uint8_t *aPsk, uint8_t aPskLength)
{
    return mNetif.GetDtls().SetPsk(aPsk, aPskLength);
}

void SecureServer::HandleDtlsConnected(void *aContext, bool aConnected)
{
    return static_cast<SecureServer *>(aContext)->HandleDtlsConnected(aConnected);
}

void SecureServer::HandleDtlsConnected(bool aConnected)
{
    (void)aConnected;
}

void SecureServer::HandleDtlsReceive(void *aContext, uint8_t *aBuf, uint16_t aLength)
{
    return static_cast<SecureServer *>(aContext)->HandleDtlsReceive(aBuf, aLength);
}

void SecureServer::HandleDtlsReceive(uint8_t *aBuf, uint16_t aLength)
{
    Message *message;

    otLogFuncEntry();

    VerifyOrExit((message = mNetif.GetIp6().mMessagePool.New(Message::kTypeIp6, 0)) != NULL, ;);
    SuccessOrExit(message->Append(aBuf, aLength));

    ProcessReceivedMessage(*message, mPeerAddress);

exit:

    if (message != NULL)
    {
        message->Free();
    }

    otLogFuncExit();
}

ThreadError SecureServer::HandleDtlsSend(void *aContext, const uint8_t *aBuf, uint16_t aLength, uint8_t aMessageSubType)
{
    return static_cast<SecureServer *>(aContext)->HandleDtlsSend(aBuf, aLength, aMessageSubType);
}

ThreadError SecureServer::HandleDtlsSend(const uint8_t *aBuf, uint16_t aLength, uint8_t aMessageSubType)
{
    ThreadError error = kThreadError_None;

    otLogFuncEntry();

    if (mTransmitMessage == NULL)
    {
        VerifyOrExit((mTransmitMessage = mSocket.NewMessage(0)) != NULL, error = kThreadError_NoBufs);
        mTransmitMessage->SetSubType(aMessageSubType);
        mTransmitMessage->SetLinkSecurityEnabled(false);
    }

    VerifyOrExit(mTransmitMessage->Append(aBuf, aLength) == kThreadError_None, error = kThreadError_NoBufs);

    mTransmitTask.Post();

exit:

    if (error != kThreadError_None && mTransmitMessage != NULL)
    {
        mTransmitMessage->Free();
    }

    otLogFuncExitErr(error);

    return error;
}

void SecureServer::HandleUdpTransmit(void *aContext)
{
    return static_cast<SecureServer *>(aContext)->HandleUdpTransmit();
}

void SecureServer::HandleUdpTransmit(void)
{
    ThreadError error = kThreadError_None;

    otLogFuncEntry();

    VerifyOrExit(mTransmitMessage != NULL, error = kThreadError_NoBufs);

    if (mTransmitCallback)
    {
        SuccessOrExit(error = mTransmitCallback(mContext, *mTransmitMessage, mPeerAddress));
    }
    else
    {
        SuccessOrExit(error = mSocket.SendTo(*mTransmitMessage, mPeerAddress));
    }

exit:

    if (error != kThreadError_None && mTransmitMessage != NULL)
    {
        mTransmitMessage->Free();
    }

    mTransmitMessage = NULL;

    otLogFuncExit();
}

}  // namespace Coap
}  // namespace Thread
<|endoftext|>


<commit_before>#include <gtest/gtest.h>
#include "keycode.hpp"

using namespace org_pqrs_KeyRemap4MacBook;

TEST(ModifierFlag, stripFN) {
  unsigned int flags = ModifierFlag::SHIFT_L | ModifierFlag::CONTROL_R | ModifierFlag::COMMAND_R;
  EXPECT_EQ(ModifierFlag::stripFN(flags), flags);
  EXPECT_EQ(ModifierFlag::stripFN(flags | ModifierFlag::FN), flags);
}

TEST(ModifierFlag, stripCURSOR) {
  unsigned int flags = ModifierFlag::SHIFT_L | ModifierFlag::CONTROL_R | ModifierFlag::COMMAND_R;
  EXPECT_EQ(ModifierFlag::stripCURSOR(flags), flags);
  EXPECT_EQ(ModifierFlag::stripCURSOR(flags | ModifierFlag::CURSOR), flags);
}

TEST(ModifierFlag, stripKEYPAD) {
  unsigned int flags = ModifierFlag::SHIFT_L | ModifierFlag::CONTROL_R | ModifierFlag::COMMAND_R;
  EXPECT_EQ(ModifierFlag::stripKEYPAD(flags), flags);
  EXPECT_EQ(ModifierFlag::stripKEYPAD(flags | ModifierFlag::KEYPAD), flags);
}

TEST(ModifierFlag, stripNONE) {
  unsigned int flags = ModifierFlag::SHIFT_L | ModifierFlag::CONTROL_R | ModifierFlag::COMMAND_R;
  EXPECT_EQ(ModifierFlag::stripNONE(flags), flags);
  EXPECT_EQ(ModifierFlag::stripNONE(flags | ModifierFlag::NONE), flags);
}

TEST(ModifierFlag, isOn) {
  unsigned int flags = ModifierFlag::SHIFT_L | ModifierFlag::CONTROL_R | ModifierFlag::COMMAND_R;
  EXPECT_TRUE(ModifierFlag::isOn(flags, ModifierFlag::SHIFT_L));
  EXPECT_FALSE(ModifierFlag::isOn(flags, ModifierFlag::SHIFT_R));

  flags = ModifierFlag::NONE;
  EXPECT_TRUE(ModifierFlag::isOn(flags, ModifierFlag::NONE));
}

namespace {
  unsigned int keypads[][2] = {
    { KeyCode::KEYPAD_0, KeyCode::M },
    { KeyCode::KEYPAD_1, KeyCode::J },
    { KeyCode::KEYPAD_2, KeyCode::K },
    { KeyCode::KEYPAD_3, KeyCode::L },
    { KeyCode::KEYPAD_4, KeyCode::U },
    { KeyCode::KEYPAD_5, KeyCode::I },
    { KeyCode::KEYPAD_6, KeyCode::O },
    { KeyCode::KEYPAD_7, KeyCode::KEY_7 },
    { KeyCode::KEYPAD_8, KeyCode::KEY_8 },
    { KeyCode::KEYPAD_9, KeyCode::KEY_9 },
    { KeyCode::KEYPAD_CLEAR, KeyCode::KEY_6 },
    { KeyCode::KEYPAD_PLUS, KeyCode::SLASH },
    { KeyCode::KEYPAD_MINUS, KeyCode::SEMICOLON },
    { KeyCode::KEYPAD_MULTIPLY, KeyCode::P },
    { KeyCode::KEYPAD_SLASH, KeyCode::KEY_0 },
    { KeyCode::KEYPAD_EQUAL, KeyCode::MINUS },
    { KeyCode::KEYPAD_DOT, KeyCode::DOT },
  };

  unsigned int cursors[][2] = {
    { KeyCode::PAGEUP, KeyCode::CURSOR_UP },
    { KeyCode::PAGEDOWN, KeyCode::CURSOR_DOWN },
    { KeyCode::HOME, KeyCode::CURSOR_LEFT },
    { KeyCode::END, KeyCode::CURSOR_RIGHT },
  };
}

TEST(KeyCode, normalizeKey) {
  unsigned int key = 0;
  unsigned int flags = 0;
  unsigned int keyboardType = 0;

  // ENTER_POWERBOOK -> ENTER
  key = KeyCode::ENTER_POWERBOOK; flags = ModifierFlag::SHIFT_L; keyboardType = KeyboardType::POWERBOOK;
  KeyCode::normalizeKey(key, flags, keyboardType);
  EXPECT_EQ(key, static_cast<unsigned int>(KeyCode::ENTER)); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L));

  // ENTER_POWERBOOK(+FN) -> ENTER(+FN) -> RETURN
  key = KeyCode::ENTER_POWERBOOK; flags = ModifierFlag::SHIFT_L | ModifierFlag::FN; keyboardType = KeyboardType::POWERBOOK;
  KeyCode::normalizeKey(key, flags, keyboardType);
  EXPECT_EQ(key, static_cast<unsigned int>(KeyCode::RETURN)); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L));

  // normal key
  key = KeyCode::A; flags = ModifierFlag::SHIFT_L; keyboardType = KeyboardType::MACBOOK;
  KeyCode::normalizeKey(key, flags, keyboardType);
  EXPECT_EQ(key, static_cast<unsigned int>(KeyCode::A)); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L));

  // KEYPAD
  for (size_t i = 0; i < sizeof(keypads) / sizeof(keypads[0]); ++i) {
    key = keypads[i][0]; flags = ModifierFlag::SHIFT_L | ModifierFlag::KEYPAD; keyboardType = KeyboardType::MACBOOK;
    KeyCode::normalizeKey(key, flags, keyboardType);
    EXPECT_EQ(key, keypads[i][0]); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L | ModifierFlag::KEYPAD));
  }

  // PAGEUP
  for (size_t i = 0; i < sizeof(cursors) / sizeof(cursors[0]); ++i) {
    key = cursors[i][0]; flags = ModifierFlag::SHIFT_L; keyboardType = KeyboardType::MACBOOK;
    KeyCode::normalizeKey(key, flags, keyboardType);
    EXPECT_EQ(key, cursors[i][0]); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L));
  }

  // ENTER
  key = KeyCode::ENTER; flags = ModifierFlag::SHIFT_L; keyboardType = KeyboardType::MACBOOK;
  KeyCode::normalizeKey(key, flags, keyboardType);
  EXPECT_EQ(key, static_cast<unsigned int>(KeyCode::ENTER)); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L));

  // FORWARD_DELETE
  key = KeyCode::FORWARD_DELETE; flags = ModifierFlag::SHIFT_L; keyboardType = KeyboardType::MACBOOK;
  KeyCode::normalizeKey(key, flags, keyboardType);
  EXPECT_EQ(key, static_cast<unsigned int>(KeyCode::FORWARD_DELETE)); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L));

  // normal key(+FN)
  key = KeyCode::A; flags = ModifierFlag::SHIFT_L | ModifierFlag::FN; keyboardType = KeyboardType::MACBOOK;
  KeyCode::normalizeKey(key, flags, keyboardType);
  EXPECT_EQ(key, static_cast<unsigned int>(KeyCode::A)); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L | ModifierFlag::FN));

  // KEYPAD(+FN)
  for (size_t i = 0; i < sizeof(keypads) / sizeof(keypads[0]); ++i) {
    key = keypads[i][0]; flags = ModifierFlag::SHIFT_L | ModifierFlag::FN | ModifierFlag::KEYPAD; keyboardType = KeyboardType::MACBOOK;
    KeyCode::normalizeKey(key, flags, keyboardType);
    EXPECT_EQ(key, static_cast<unsigned int>(keypads[i][1])); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L | ModifierFlag::KEYPAD));
  }

  // PAGEUP(+FN)
  for (size_t i = 0; i < sizeof(cursors) / sizeof(cursors[0]); ++i) {
    key = cursors[i][0]; flags = ModifierFlag::SHIFT_L | ModifierFlag::FN; keyboardType = KeyboardType::MACBOOK;
    KeyCode::normalizeKey(key, flags, keyboardType);
    EXPECT_EQ(key, cursors[i][1]); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L | ModifierFlag::CURSOR));
  }

  // ENTER(+FN)
  key = KeyCode::ENTER; flags = ModifierFlag::SHIFT_L | ModifierFlag::FN; keyboardType = KeyboardType::MACBOOK;
  KeyCode::normalizeKey(key, flags, keyboardType);
  EXPECT_EQ(key, static_cast<unsigned int>(KeyCode::RETURN)); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L));

  // FORWARD_DELETE(+FN)
  key = KeyCode::FORWARD_DELETE; flags = ModifierFlag::SHIFT_L | ModifierFlag::FN; keyboardType = KeyboardType::MACBOOK;
  KeyCode::normalizeKey(key, flags, keyboardType);
  EXPECT_EQ(key, static_cast<unsigned int>(KeyCode::DELETE)); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L));
}

TEST(KeyCode, reverseNormalizeKey) {
  unsigned int key = 0;
  unsigned int flags = 0;
  unsigned int keyboardType = 0;

  // ENTER_POWERBOOK -> ENTER
  key = KeyCode::ENTER_POWERBOOK; flags = ModifierFlag::SHIFT_L; keyboardType = KeyboardType::POWERBOOK;
  KeyCode::normalizeKey(key, flags, keyboardType);
  KeyCode::reverseNormalizeKey(key, flags, keyboardType);
  EXPECT_EQ(key, static_cast<unsigned int>(KeyCode::ENTER_POWERBOOK)); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L));

  // ENTER_POWERBOOK(+FN) -> ENTER(+FN) -> RETURN
  key = KeyCode::ENTER_POWERBOOK; flags = ModifierFlag::SHIFT_L | ModifierFlag::FN; keyboardType = KeyboardType::POWERBOOK;
  KeyCode::normalizeKey(key, flags, keyboardType);
  flags |= ModifierFlag::FN;
  KeyCode::reverseNormalizeKey(key, flags, keyboardType);
  EXPECT_EQ(key, static_cast<unsigned int>(KeyCode::ENTER_POWERBOOK)); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L | ModifierFlag::FN));

  // normal key
  key = KeyCode::A; flags = ModifierFlag::SHIFT_L; keyboardType = KeyboardType::MACBOOK;
  KeyCode::normalizeKey(key, flags, keyboardType);
  KeyCode::reverseNormalizeKey(key, flags, keyboardType);
  EXPECT_EQ(key, static_cast<unsigned int>(KeyCode::A)); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L));

  // KEYPAD
  for (size_t i = 0; i < sizeof(keypads) / sizeof(keypads[0]); ++i) {
    key = keypads[i][0]; flags = ModifierFlag::SHIFT_L | ModifierFlag::KEYPAD; keyboardType = KeyboardType::MACBOOK;
    KeyCode::normalizeKey(key, flags, keyboardType);
    KeyCode::reverseNormalizeKey(key, flags, keyboardType);
    EXPECT_EQ(key, keypads[i][0]); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L | ModifierFlag::KEYPAD));
  }

  // PAGEUP
  for (size_t i = 0; i < sizeof(cursors) / sizeof(cursors[0]); ++i) {
    key = cursors[i][0]; flags = ModifierFlag::SHIFT_L; keyboardType = KeyboardType::MACBOOK;
    KeyCode::normalizeKey(key, flags, keyboardType);
    KeyCode::reverseNormalizeKey(key, flags, keyboardType);
    EXPECT_EQ(key, cursors[i][0]); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L));
  }

  // ENTER
  key = KeyCode::ENTER; flags = ModifierFlag::SHIFT_L; keyboardType = KeyboardType::MACBOOK;
  KeyCode::normalizeKey(key, flags, keyboardType);
  KeyCode::reverseNormalizeKey(key, flags, keyboardType);
  EXPECT_EQ(key, static_cast<unsigned int>(KeyCode::ENTER)); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L));

  // FORWARD_DELETE
  key = KeyCode::FORWARD_DELETE; flags = ModifierFlag::SHIFT_L; keyboardType = KeyboardType::MACBOOK;
  KeyCode::normalizeKey(key, flags, keyboardType);
  KeyCode::reverseNormalizeKey(key, flags, keyboardType);
  EXPECT_EQ(key, static_cast<unsigned int>(KeyCode::FORWARD_DELETE)); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L));

  // CURSOR
  for (size_t i = 0; i < sizeof(cursors) / sizeof(cursors[0]); ++i) {
    key = cursors[i][1]; flags = ModifierFlag::CURSOR; keyboardType = KeyboardType::MACBOOK;
    KeyCode::normalizeKey(key, flags, keyboardType);
    KeyCode::reverseNormalizeKey(key, flags, keyboardType);
    EXPECT_EQ(key, static_cast<unsigned int>(cursors[i][1])); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::CURSOR));
  }

  // normal key(+FN)
  key = KeyCode::A; flags = ModifierFlag::SHIFT_L | ModifierFlag::FN; keyboardType = KeyboardType::MACBOOK;
  KeyCode::normalizeKey(key, flags, keyboardType);
  flags |= ModifierFlag::FN;
  KeyCode::reverseNormalizeKey(key, flags, keyboardType);
  EXPECT_EQ(key, static_cast<unsigned int>(KeyCode::A)); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L | ModifierFlag::FN));

  // KEYPAD(+FN)
  for (size_t i = 0; i < sizeof(keypads) / sizeof(keypads[0]); ++i) {
    key = keypads[i][0]; flags = ModifierFlag::SHIFT_L | ModifierFlag::FN | ModifierFlag::KEYPAD; keyboardType = KeyboardType::MACBOOK;
    KeyCode::normalizeKey(key, flags, keyboardType);
    flags |= ModifierFlag::FN;
    KeyCode::reverseNormalizeKey(key, flags, keyboardType);
    EXPECT_EQ(key, static_cast<unsigned int>(keypads[i][0])); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L | ModifierFlag::FN | ModifierFlag::KEYPAD));
  }

  // PAGEUP(+FN)
  for (size_t i = 0; i < sizeof(cursors) / sizeof(cursors[0]); ++i) {
    key = cursors[i][0]; flags = ModifierFlag::SHIFT_L | ModifierFlag::FN; keyboardType = KeyboardType::MACBOOK;
    KeyCode::normalizeKey(key, flags, keyboardType);
    flags |= ModifierFlag::FN;
    KeyCode::reverseNormalizeKey(key, flags, keyboardType);
    EXPECT_EQ(key, cursors[i][0]); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L | ModifierFlag::FN));
  }

  // ENTER(+FN)
  key = KeyCode::ENTER; flags = ModifierFlag::SHIFT_L | ModifierFlag::FN; keyboardType = KeyboardType::MACBOOK;
  KeyCode::normalizeKey(key, flags, keyboardType);
  flags |= ModifierFlag::FN;
  KeyCode::reverseNormalizeKey(key, flags, keyboardType);
  EXPECT_EQ(key, static_cast<unsigned int>(KeyCode::ENTER)); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L | ModifierFlag::FN));

  // FORWARD_DELETE(+FN)
  key = KeyCode::FORWARD_DELETE; flags = ModifierFlag::SHIFT_L | ModifierFlag::FN; keyboardType = KeyboardType::MACBOOK;
  KeyCode::normalizeKey(key, flags, keyboardType);
  flags |= ModifierFlag::FN;
  KeyCode::reverseNormalizeKey(key, flags, keyboardType);
  EXPECT_EQ(key, static_cast<unsigned int>(KeyCode::FORWARD_DELETE)); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L | ModifierFlag::FN));
}
<commit_msg>update kext/Tests<commit_after>#include <gtest/gtest.h>
#include "keycode.hpp"

using namespace org_pqrs_KeyRemap4MacBook;

TEST(ModifierFlag, stripFN) {
  unsigned int flags = ModifierFlag::SHIFT_L | ModifierFlag::CONTROL_R | ModifierFlag::COMMAND_R;
  EXPECT_EQ(ModifierFlag::stripFN(flags), flags);
  EXPECT_EQ(ModifierFlag::stripFN(flags | ModifierFlag::FN), flags);
}

TEST(ModifierFlag, stripCURSOR) {
  unsigned int flags = ModifierFlag::SHIFT_L | ModifierFlag::CONTROL_R | ModifierFlag::COMMAND_R;
  EXPECT_EQ(ModifierFlag::stripCURSOR(flags), flags);
  EXPECT_EQ(ModifierFlag::stripCURSOR(flags | ModifierFlag::CURSOR), flags);
}

TEST(ModifierFlag, stripKEYPAD) {
  unsigned int flags = ModifierFlag::SHIFT_L | ModifierFlag::CONTROL_R | ModifierFlag::COMMAND_R;
  EXPECT_EQ(ModifierFlag::stripKEYPAD(flags), flags);
  EXPECT_EQ(ModifierFlag::stripKEYPAD(flags | ModifierFlag::KEYPAD), flags);
}

TEST(ModifierFlag, stripNONE) {
  unsigned int flags = ModifierFlag::SHIFT_L | ModifierFlag::CONTROL_R | ModifierFlag::COMMAND_R;
  EXPECT_EQ(ModifierFlag::stripNONE(flags), flags);
  EXPECT_EQ(ModifierFlag::stripNONE(flags | ModifierFlag::NONE), flags);
}

TEST(ModifierFlag, isOn) {
  unsigned int flags = ModifierFlag::SHIFT_L | ModifierFlag::CONTROL_R | ModifierFlag::COMMAND_R;
  EXPECT_TRUE(ModifierFlag::isOn(flags, ModifierFlag::SHIFT_L));
  EXPECT_FALSE(ModifierFlag::isOn(flags, ModifierFlag::SHIFT_R));

  flags = ModifierFlag::NONE;
  EXPECT_TRUE(ModifierFlag::isOn(flags, ModifierFlag::NONE));
}

namespace {
  unsigned int keypads[][2] = {
    { KeyCode::KEYPAD_0, KeyCode::M },
    { KeyCode::KEYPAD_1, KeyCode::J },
    { KeyCode::KEYPAD_2, KeyCode::K },
    { KeyCode::KEYPAD_3, KeyCode::L },
    { KeyCode::KEYPAD_4, KeyCode::U },
    { KeyCode::KEYPAD_5, KeyCode::I },
    { KeyCode::KEYPAD_6, KeyCode::O },
    { KeyCode::KEYPAD_7, KeyCode::KEY_7 },
    { KeyCode::KEYPAD_8, KeyCode::KEY_8 },
    { KeyCode::KEYPAD_9, KeyCode::KEY_9 },
    { KeyCode::KEYPAD_CLEAR, KeyCode::KEY_6 },
    { KeyCode::KEYPAD_PLUS, KeyCode::SLASH },
    { KeyCode::KEYPAD_MINUS, KeyCode::SEMICOLON },
    { KeyCode::KEYPAD_MULTIPLY, KeyCode::P },
    { KeyCode::KEYPAD_SLASH, KeyCode::KEY_0 },
    { KeyCode::KEYPAD_EQUAL, KeyCode::MINUS },
    { KeyCode::KEYPAD_DOT, KeyCode::DOT },
  };

  unsigned int cursors[][2] = {
    { KeyCode::PAGEUP, KeyCode::CURSOR_UP },
    { KeyCode::PAGEDOWN, KeyCode::CURSOR_DOWN },
    { KeyCode::HOME, KeyCode::CURSOR_LEFT },
    { KeyCode::END, KeyCode::CURSOR_RIGHT },
  };
}

TEST(KeyCode, normalizeKey) {
  unsigned int key = 0;
  unsigned int flags = 0;
  unsigned int keyboardType = 0;

  // ENTER_POWERBOOK -> ENTER
  key = KeyCode::ENTER_POWERBOOK; flags = ModifierFlag::SHIFT_L; keyboardType = KeyboardType::POWERBOOK;
  KeyCode::normalizeKey(key, flags, keyboardType);
  EXPECT_EQ(key, static_cast<unsigned int>(KeyCode::ENTER)); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L));

  // ENTER_POWERBOOK(+FN) -> ENTER(+FN) -> RETURN
  key = KeyCode::ENTER_POWERBOOK; flags = ModifierFlag::SHIFT_L | ModifierFlag::FN; keyboardType = KeyboardType::POWERBOOK;
  KeyCode::normalizeKey(key, flags, keyboardType);
  EXPECT_EQ(key, static_cast<unsigned int>(KeyCode::RETURN)); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L));

  // normal key
  key = KeyCode::A; flags = ModifierFlag::SHIFT_L; keyboardType = KeyboardType::MACBOOK;
  KeyCode::normalizeKey(key, flags, keyboardType);
  EXPECT_EQ(key, static_cast<unsigned int>(KeyCode::A)); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L));

  // KEYPAD
  for (size_t i = 0; i < sizeof(keypads) / sizeof(keypads[0]); ++i) {
    key = keypads[i][0]; flags = ModifierFlag::SHIFT_L | ModifierFlag::KEYPAD; keyboardType = KeyboardType::MACBOOK;
    KeyCode::normalizeKey(key, flags, keyboardType);
    EXPECT_EQ(key, keypads[i][0]); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L | ModifierFlag::KEYPAD));
  }

  // PAGEUP
  for (size_t i = 0; i < sizeof(cursors) / sizeof(cursors[0]); ++i) {
    key = cursors[i][0]; flags = ModifierFlag::SHIFT_L; keyboardType = KeyboardType::MACBOOK;
    KeyCode::normalizeKey(key, flags, keyboardType);
    EXPECT_EQ(key, cursors[i][0]); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L));
  }

  // ENTER
  key = KeyCode::ENTER; flags = ModifierFlag::SHIFT_L; keyboardType = KeyboardType::MACBOOK;
  KeyCode::normalizeKey(key, flags, keyboardType);
  EXPECT_EQ(key, static_cast<unsigned int>(KeyCode::ENTER)); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L));

  // FORWARD_DELETE
  key = KeyCode::FORWARD_DELETE; flags = ModifierFlag::SHIFT_L; keyboardType = KeyboardType::MACBOOK;
  KeyCode::normalizeKey(key, flags, keyboardType);
  EXPECT_EQ(key, static_cast<unsigned int>(KeyCode::FORWARD_DELETE)); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L));

  // normal key(+FN)
  key = KeyCode::A; flags = ModifierFlag::SHIFT_L | ModifierFlag::FN; keyboardType = KeyboardType::MACBOOK;
  KeyCode::normalizeKey(key, flags, keyboardType);
  EXPECT_EQ(key, static_cast<unsigned int>(KeyCode::A)); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L | ModifierFlag::FN));

  // KEYPAD(+FN)
  for (size_t i = 0; i < sizeof(keypads) / sizeof(keypads[0]); ++i) {
    key = keypads[i][0]; flags = ModifierFlag::SHIFT_L | ModifierFlag::FN | ModifierFlag::KEYPAD; keyboardType = KeyboardType::MACBOOK;
    KeyCode::normalizeKey(key, flags, keyboardType);
    EXPECT_EQ(key, static_cast<unsigned int>(keypads[i][1])); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L));
  }

  // PAGEUP(+FN)
  for (size_t i = 0; i < sizeof(cursors) / sizeof(cursors[0]); ++i) {
    key = cursors[i][0]; flags = ModifierFlag::SHIFT_L | ModifierFlag::FN; keyboardType = KeyboardType::MACBOOK;
    KeyCode::normalizeKey(key, flags, keyboardType);
    EXPECT_EQ(key, cursors[i][1]); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L | ModifierFlag::CURSOR));
  }

  // ENTER(+FN)
  key = KeyCode::ENTER; flags = ModifierFlag::SHIFT_L | ModifierFlag::FN; keyboardType = KeyboardType::MACBOOK;
  KeyCode::normalizeKey(key, flags, keyboardType);
  EXPECT_EQ(key, static_cast<unsigned int>(KeyCode::RETURN)); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L));

  // FORWARD_DELETE(+FN)
  key = KeyCode::FORWARD_DELETE; flags = ModifierFlag::SHIFT_L | ModifierFlag::FN; keyboardType = KeyboardType::MACBOOK;
  KeyCode::normalizeKey(key, flags, keyboardType);
  EXPECT_EQ(key, static_cast<unsigned int>(KeyCode::DELETE)); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L));
}

TEST(KeyCode, reverseNormalizeKey) {
  unsigned int key = 0;
  unsigned int flags = 0;
  unsigned int keyboardType = 0;

  // ENTER_POWERBOOK -> ENTER
  key = KeyCode::ENTER_POWERBOOK; flags = ModifierFlag::SHIFT_L; keyboardType = KeyboardType::POWERBOOK;
  KeyCode::normalizeKey(key, flags, keyboardType);
  KeyCode::reverseNormalizeKey(key, flags, keyboardType);
  EXPECT_EQ(key, static_cast<unsigned int>(KeyCode::ENTER_POWERBOOK)); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L));

  // ENTER_POWERBOOK(+FN) -> ENTER(+FN) -> RETURN
  key = KeyCode::ENTER_POWERBOOK; flags = ModifierFlag::SHIFT_L | ModifierFlag::FN; keyboardType = KeyboardType::POWERBOOK;
  KeyCode::normalizeKey(key, flags, keyboardType);
  flags |= ModifierFlag::FN;
  KeyCode::reverseNormalizeKey(key, flags, keyboardType);
  EXPECT_EQ(key, static_cast<unsigned int>(KeyCode::ENTER_POWERBOOK)); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L | ModifierFlag::FN));

  // normal key
  key = KeyCode::A; flags = ModifierFlag::SHIFT_L; keyboardType = KeyboardType::MACBOOK;
  KeyCode::normalizeKey(key, flags, keyboardType);
  KeyCode::reverseNormalizeKey(key, flags, keyboardType);
  EXPECT_EQ(key, static_cast<unsigned int>(KeyCode::A)); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L));

  // KEYPAD
  for (size_t i = 0; i < sizeof(keypads) / sizeof(keypads[0]); ++i) {
    key = keypads[i][0]; flags = ModifierFlag::SHIFT_L | ModifierFlag::KEYPAD; keyboardType = KeyboardType::MACBOOK;
    KeyCode::normalizeKey(key, flags, keyboardType);
    KeyCode::reverseNormalizeKey(key, flags, keyboardType);
    EXPECT_EQ(key, keypads[i][0]); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L | ModifierFlag::KEYPAD));
  }

  // PAGEUP
  for (size_t i = 0; i < sizeof(cursors) / sizeof(cursors[0]); ++i) {
    key = cursors[i][0]; flags = ModifierFlag::SHIFT_L; keyboardType = KeyboardType::MACBOOK;
    KeyCode::normalizeKey(key, flags, keyboardType);
    KeyCode::reverseNormalizeKey(key, flags, keyboardType);
    EXPECT_EQ(key, cursors[i][0]); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L));
  }

  // ENTER
  key = KeyCode::ENTER; flags = ModifierFlag::SHIFT_L; keyboardType = KeyboardType::MACBOOK;
  KeyCode::normalizeKey(key, flags, keyboardType);
  KeyCode::reverseNormalizeKey(key, flags, keyboardType);
  EXPECT_EQ(key, static_cast<unsigned int>(KeyCode::ENTER)); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L));

  // FORWARD_DELETE
  key = KeyCode::FORWARD_DELETE; flags = ModifierFlag::SHIFT_L; keyboardType = KeyboardType::MACBOOK;
  KeyCode::normalizeKey(key, flags, keyboardType);
  KeyCode::reverseNormalizeKey(key, flags, keyboardType);
  EXPECT_EQ(key, static_cast<unsigned int>(KeyCode::FORWARD_DELETE)); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L));

  // CURSOR
  for (size_t i = 0; i < sizeof(cursors) / sizeof(cursors[0]); ++i) {
    key = cursors[i][1]; flags = ModifierFlag::CURSOR; keyboardType = KeyboardType::MACBOOK;
    KeyCode::normalizeKey(key, flags, keyboardType);
    KeyCode::reverseNormalizeKey(key, flags, keyboardType);
    EXPECT_EQ(key, static_cast<unsigned int>(cursors[i][1])); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::CURSOR));
  }

  // normal key(+FN)
  key = KeyCode::A; flags = ModifierFlag::SHIFT_L | ModifierFlag::FN; keyboardType = KeyboardType::MACBOOK;
  KeyCode::normalizeKey(key, flags, keyboardType);
  flags |= ModifierFlag::FN;
  KeyCode::reverseNormalizeKey(key, flags, keyboardType);
  EXPECT_EQ(key, static_cast<unsigned int>(KeyCode::A)); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L | ModifierFlag::FN));

  // KEYPAD(+FN)
  for (size_t i = 0; i < sizeof(keypads) / sizeof(keypads[0]); ++i) {
    key = keypads[i][0]; flags = ModifierFlag::SHIFT_L | ModifierFlag::FN | ModifierFlag::KEYPAD; keyboardType = KeyboardType::MACBOOK;
    KeyCode::normalizeKey(key, flags, keyboardType);
    flags |= ModifierFlag::FN;
    KeyCode::reverseNormalizeKey(key, flags, keyboardType);
    EXPECT_EQ(key, static_cast<unsigned int>(keypads[i][0])); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L | ModifierFlag::FN | ModifierFlag::KEYPAD));
  }

  // PAGEUP(+FN)
  for (size_t i = 0; i < sizeof(cursors) / sizeof(cursors[0]); ++i) {
    key = cursors[i][0]; flags = ModifierFlag::SHIFT_L | ModifierFlag::FN; keyboardType = KeyboardType::MACBOOK;
    KeyCode::normalizeKey(key, flags, keyboardType);
    flags |= ModifierFlag::FN;
    KeyCode::reverseNormalizeKey(key, flags, keyboardType);
    EXPECT_EQ(key, cursors[i][0]); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L | ModifierFlag::FN));
  }

  // ENTER(+FN)
  key = KeyCode::ENTER; flags = ModifierFlag::SHIFT_L | ModifierFlag::FN; keyboardType = KeyboardType::MACBOOK;
  KeyCode::normalizeKey(key, flags, keyboardType);
  flags |= ModifierFlag::FN;
  KeyCode::reverseNormalizeKey(key, flags, keyboardType);
  EXPECT_EQ(key, static_cast<unsigned int>(KeyCode::ENTER)); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L | ModifierFlag::FN));

  // FORWARD_DELETE(+FN)
  key = KeyCode::FORWARD_DELETE; flags = ModifierFlag::SHIFT_L | ModifierFlag::FN; keyboardType = KeyboardType::MACBOOK;
  KeyCode::normalizeKey(key, flags, keyboardType);
  flags |= ModifierFlag::FN;
  KeyCode::reverseNormalizeKey(key, flags, keyboardType);
  EXPECT_EQ(key, static_cast<unsigned int>(KeyCode::FORWARD_DELETE)); EXPECT_EQ(flags, static_cast<unsigned int>(ModifierFlag::SHIFT_L | ModifierFlag::FN));
}
<|endoftext|>


<commit_before>#include "core/physics/physics_manager.h"
#include "core/physics/constraint.h"
#include "core/rendering/render_manager.h"
#include <glm/gtx/norm.hpp>
#include <bitset>

namespace eversim { namespace core { namespace physics {

	namespace {
		template <typename Constraints, typename Func, size_t... Is>
		void iterate(Constraints const& c, std::index_sequence<Is...>, Func&& fun)
		{
			std::initializer_list<int>{
				(std::forward<Func>(fun)(std::get<Is>(c), Is), 0)...
			};
		}
	}

	void physics_manager::add_particle(particle const& p)
	{
		particles.push_back(p);
	}

	void physics_manager::integrate(float dt)
	{
		apply_external_forces(dt);
		damp_velocities();
		for (auto& p : particles)
		{
			p.projected_position = p.pos + dt * p.vel;
		}

		for (auto i = 0; i < solver_iterations; ++i)
		{
			project_constraints();
		}

		for (auto& p : particles)
		{
			p.vel = (p.projected_position - p.pos) / dt;
			p.pos = p.projected_position;
		}
	}

	void physics_manager::atomic_step(float dt)
	{
		switch (current_state)
		{
		case simulation_state::external:
			apply_external_forces(dt);
			current_state = simulation_state::damp;
			break;
		case simulation_state::damp:
			damp_velocities();
			current_state = simulation_state::apply_velocity;
			break;
		case simulation_state::apply_velocity:
			for (auto& p : particles)
			{
				p.projected_position = p.pos + dt * p.vel;
			}
			current_state = simulation_state::constraint_iteration;
			break;
		case simulation_state::constraint_iteration:
			if(current_iteration < solver_iterations)
			{
				project_constraints();
				current_iteration++;
			}else
			{
				current_iteration = 0;
				current_state = simulation_state::apply_changes;
			}
			break;
		case simulation_state::apply_changes:
			for (auto& p : particles)
			{
				p.vel = (p.projected_position - p.pos) / dt;
				p.pos = p.projected_position;
			}
			current_state = simulation_state::external;
			break;
		default: ;
			assert(!"unknown state!");
		}
	}

	void physics_manager::draw_constraints(std::bitset<max_constraint_arity> to_render)
	{
		iterate(constraints, std::make_index_sequence<max_constraint_arity>{}, [to_render](auto const& cs, size_t I)
		{
			if(to_render[I])
			{
				for (auto const& c : cs) {
					for (int i = 0; i < c->arity(); ++i)
					{
						for (int j = 0; j < i; ++j)
						{
							auto p1 = c->particles[i];
							auto p2 = c->particles[j];
							rendering::draw_line(p1->projected_position, p2->projected_position);
						}
					}
				}
			}
		});
	}

	void physics_manager::apply_external_forces(float dt)
	{
		for (auto& p : particles)
		{
			if (p.inv_mass == 0.f)
				continue;
			p.vel += dt * glm::vec2{0,-1};
		}
	}

	void physics_manager::damp_velocities()
	{
		for (auto& p : particles)
		{
			p.vel *= 0.99; // TODO: improve
		}
	}

	namespace {
		template <size_t N>
		void project_single_constraint(constraint<N> const& c)
		{
			const auto err = c();
			switch (c.get_type())
			{
			case constraint_type::equality:
				{
					if (err == 0)
						return;
					break;
				}
			case constraint_type::inequality:
				{
					if (err >= 0)
						return;
					break;
				}
			default:
				{
					assert(!"Unhandled constraint type!");
				}
			}

			const auto grad = c.grad();

			const auto sum = [&]
			{
				auto sum = 0.f;
				for (auto i = 0; i < N; ++i)
				{
					sum += c.particles[i]->inv_mass * length2(grad[i]);
				}
				return sum;
			}();
			const auto scale = err / sum;

			for (auto i = 0; i < N; ++i)
			{
				auto& p = c.particles[i];
				const auto correction = -scale * p->inv_mass * grad[i];
				rendering::draw_line(p->projected_position, p->projected_position + correction,60);
				p->projected_position += correction;
			}
		}
	}

	void physics_manager::project_constraints()
	{
		iterate(constraints, std::make_index_sequence<max_constraint_arity>{}, [](auto&& cs, auto){
			for(auto const& c : cs)
			{
				project_single_constraint(*c);
			}
		});
	}
}}}
<commit_msg>implemented missing code for stiffness parameter<commit_after>#include "core/physics/physics_manager.h"
#include "core/physics/constraint.h"
#include "core/rendering/render_manager.h"
#include <glm/gtx/norm.hpp>
#include <bitset>

namespace eversim { namespace core { namespace physics {

	namespace {
		template <typename Constraints, typename Func, size_t... Is>
		void iterate(Constraints const& c, std::index_sequence<Is...>, Func&& fun)
		{
			std::initializer_list<int>{
				(std::forward<Func>(fun)(std::get<Is>(c), Is), 0)...
			};
		}
	}

	void physics_manager::add_particle(particle const& p)
	{
		particles.push_back(p);
	}

	void physics_manager::integrate(float dt)
	{
		apply_external_forces(dt);
		damp_velocities();
		for (auto& p : particles)
		{
			p.projected_position = p.pos + dt * p.vel;
		}

		for (auto i = 0; i < solver_iterations; ++i)
		{
			project_constraints();
		}

		for (auto& p : particles)
		{
			p.vel = (p.projected_position - p.pos) / dt;
			p.pos = p.projected_position;
		}
	}

	void physics_manager::atomic_step(float dt)
	{
		switch (current_state)
		{
		case simulation_state::external:
			apply_external_forces(dt);
			current_state = simulation_state::damp;
			break;
		case simulation_state::damp:
			damp_velocities();
			current_state = simulation_state::apply_velocity;
			break;
		case simulation_state::apply_velocity:
			for (auto& p : particles)
			{
				p.projected_position = p.pos + dt * p.vel;
			}
			current_state = simulation_state::constraint_iteration;
			break;
		case simulation_state::constraint_iteration:
			if(current_iteration < solver_iterations)
			{
				project_constraints();
				current_iteration++;
			}else
			{
				current_iteration = 0;
				current_state = simulation_state::apply_changes;
			}
			break;
		case simulation_state::apply_changes:
			for (auto& p : particles)
			{
				p.vel = (p.projected_position - p.pos) / dt;
				p.pos = p.projected_position;
			}
			current_state = simulation_state::external;
			break;
		default: ;
			assert(!"unknown state!");
		}
	}

	void physics_manager::draw_constraints(std::bitset<max_constraint_arity> to_render)
	{
		iterate(constraints, std::make_index_sequence<max_constraint_arity>{}, [to_render](auto const& cs, size_t I)
		{
			if(to_render[I])
			{
				for (auto const& c : cs) {
					for (int i = 0; i < c->arity(); ++i)
					{
						for (int j = 0; j < i; ++j)
						{
							auto p1 = c->particles[i];
							auto p2 = c->particles[j];
							rendering::draw_line(p1->projected_position, p2->projected_position);
						}
					}
				}
			}
		});
	}

	void physics_manager::apply_external_forces(float dt)
	{
		for (auto& p : particles)
		{
			if (p.inv_mass == 0.f)
				continue;
			p.vel += dt * glm::vec2{0,-1};
		}
	}

	void physics_manager::damp_velocities()
	{
		for (auto& p : particles)
		{
			p.vel *= 0.99; // TODO: improve
		}
	}

	namespace {
		template <size_t N>
		void project_single_constraint(constraint<N> const& c, int solver_iterations)
		{
			const auto err = c();
			switch (c.get_type())
			{
			case constraint_type::equality:
				{
					if (err == 0)
						return;
					break;
				}
			case constraint_type::inequality:
				{
					if (err >= 0)
						return;
					break;
				}
			default:
				{
					assert(!"Unhandled constraint type!");
				}
			}

			const auto grad = c.grad();

			const auto sum = [&]
			{
				auto sum = 0.f;
				for (auto i = 0; i < N; ++i)
				{
					sum += c.particles[i]->inv_mass * length2(grad[i]);
				}
				return sum;
			}();
			const auto scale = err / sum;

			const auto k = 1.f - powf(1.f - c.stiffness, 1.f / solver_iterations);

			for (auto i = 0; i < N; ++i)
			{
				auto& p = c.particles[i];
				const auto correction = -scale * p->inv_mass * grad[i] * k;
				rendering::draw_line(p->projected_position, p->projected_position + correction,60);
				p->projected_position += correction;
			}
		}
	}

	void physics_manager::project_constraints()
	{
		iterate(constraints, std::make_index_sequence<max_constraint_arity>{}, [this](auto&& cs, auto){
			for(auto const& c : cs)
			{
				project_single_constraint(*c, solver_iterations);
			}
		});
	}
}}}
<|endoftext|>


<commit_before>//
// PROJECT CHRONO - http://projectchrono.org
//
// Copyright (c) 2013 Project Chrono
// All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file at the top level of the distribution
// and at http://projectchrono.org/license-chrono.txt.
//

//
//   Demo code about
//
//     - FEA for 3D beams of 'cable' type (ANCF gradient-deficient beams)
//       uses the Chrono MKL module

#include "chrono/timestepper/ChTimestepper.h"
#include "chrono_irrlicht/ChIrrApp.h"
#include "chrono_mkl/ChSolverMKL.h"

#include "FEAcables.h"
/*
using namespace chrono;
using namespace fea;
using namespace irr;
*/
int main(int argc, char* argv[]) {
    // Create a Chrono::Engine physical system
    ChSystem my_system;

    // Create the Irrlicht visualization (open the Irrlicht device,
    // bind a simple user interface, etc. etc.)
    ChIrrApp application(&my_system, L"Cables FEM (MKL)", core::dimension2d<u32>(800, 600), false, true);

    // Easy shortcuts to add camera, lights, logo and sky in Irrlicht scene:
    application.AddTypicalLogo();
    application.AddTypicalSky();
    application.AddTypicalLights();
    application.AddTypicalCamera(core::vector3df(0.f, 0.6f, -1.f));

    // Create a mesh, that is a container for groups of elements and
    // their referenced nodes.
    auto my_mesh = std::make_shared<ChMesh>();

    // Create the model (defined in FEAcables.h)
    model3(my_system, my_mesh);

    // Remember to add the mesh to the system!
    my_system.Add(my_mesh);

    // ==Asset== attach a visualization of the FEM mesh.
    // This will automatically update a triangle mesh (a ChTriangleMeshShape
    // asset that is internally managed) by setting  proper
    // coordinates and vertex colours as in the FEM elements.
    // Such triangle mesh can be rendered by Irrlicht or POVray or whatever
    // postprocessor that can handle a coloured ChTriangleMeshShape).
    // Do not forget AddAsset() at the end!

    auto mvisualizebeamA = std::make_shared<ChVisualizationFEAmesh>(*(my_mesh.get()));
    mvisualizebeamA->SetFEMdataType(ChVisualizationFEAmesh::E_PLOT_ELEM_BEAM_MZ);
    mvisualizebeamA->SetColorscaleMinMax(-0.4, 0.4);
    mvisualizebeamA->SetSmoothFaces(true);
    mvisualizebeamA->SetWireframe(false);
    my_mesh->AddAsset(mvisualizebeamA);

    auto mvisualizebeamC = std::make_shared<ChVisualizationFEAmesh>(*(my_mesh.get()));
    mvisualizebeamC->SetFEMglyphType(ChVisualizationFEAmesh::E_GLYPH_NODE_CSYS);
    mvisualizebeamC->SetFEMdataType(ChVisualizationFEAmesh::E_PLOT_NONE);
    mvisualizebeamC->SetSymbolsThickness(0.006);
    mvisualizebeamC->SetSymbolsScale(0.01);
    mvisualizebeamC->SetZbufferHide(false);
    my_mesh->AddAsset(mvisualizebeamC);

    // ==IMPORTANT!== Use this function for adding a ChIrrNodeAsset to all items
    // in the system. These ChIrrNodeAsset assets are 'proxies' to the Irrlicht meshes.
    // If you need a finer control on which item really needs a visualization proxy in
    // Irrlicht, just use application.AssetBind(myitem); on a per-item basis.
    application.AssetBindAll();

    // ==IMPORTANT!== Use this function for 'converting' into Irrlicht meshes the assets
    // that you added to the bodies into 3D shapes, they can be visualized by Irrlicht!
    application.AssetUpdateAll();

    // Mark completion of system construction
    my_system.SetupInitial();

    // Change solver to MKL
    ChSolverMKL<>* mkl_solver_stab = new ChSolverMKL<>;
    ChSolverMKL<>* mkl_solver_speed = new ChSolverMKL<>;
    my_system.ChangeSolverStab(mkl_solver_stab);
    my_system.ChangeSolverSpeed(mkl_solver_speed);
	mkl_solver_stab->SetSparsityPatternLock(true);
	mkl_solver_speed->SetSparsityPatternLock(true);
    application.GetSystem()->Update();

    // Change type of integrator:
    my_system.SetIntegrationType(chrono::ChSystem::INT_EULER_IMPLICIT_LINEARIZED);  // fast, less precise
    // my_system.SetIntegrationType(chrono::ChSystem::INT_HHT);  // precise,slower, might iterate each step

    // if later you want to change integrator settings:
    if (auto mystepper = std::dynamic_pointer_cast<ChTimestepperHHT>(my_system.GetTimestepper())) {
        mystepper->SetAlpha(-0.2);
        mystepper->SetMaxiters(2);
        mystepper->SetAbsTolerances(1e-6);
    }

    //
    // THE SOFT-REAL-TIME CYCLE
    //

    application.SetTimestep(0.01);

    while (application.GetDevice()->run()) {
        application.BeginScene();
        application.DrawAll();
        application.DoStep();
        application.EndScene();
    }

    return 0;
}
<commit_msg>demo_FEAcablesMKL cannot use sparsity pattern lock (Pardiso bug)<commit_after>//
// PROJECT CHRONO - http://projectchrono.org
//
// Copyright (c) 2013 Project Chrono
// All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file at the top level of the distribution
// and at http://projectchrono.org/license-chrono.txt.
//

//
//   Demo code about
//
//     - FEA for 3D beams of 'cable' type (ANCF gradient-deficient beams)
//       uses the Chrono MKL module

#include "chrono/timestepper/ChTimestepper.h"
#include "chrono_irrlicht/ChIrrApp.h"
#include "chrono_mkl/ChSolverMKL.h"

#include "FEAcables.h"
/*
using namespace chrono;
using namespace fea;
using namespace irr;
*/
int main(int argc, char* argv[]) {
    // Create a Chrono::Engine physical system
    ChSystem my_system;

    // Create the Irrlicht visualization (open the Irrlicht device,
    // bind a simple user interface, etc. etc.)
    ChIrrApp application(&my_system, L"Cables FEM (MKL)", core::dimension2d<u32>(800, 600), false, true);

    // Easy shortcuts to add camera, lights, logo and sky in Irrlicht scene:
    application.AddTypicalLogo();
    application.AddTypicalSky();
    application.AddTypicalLights();
    application.AddTypicalCamera(core::vector3df(0.f, 0.6f, -1.f));

    // Create a mesh, that is a container for groups of elements and
    // their referenced nodes.
    auto my_mesh = std::make_shared<ChMesh>();

    // Create the model (defined in FEAcables.h)
    model3(my_system, my_mesh);

    // Remember to add the mesh to the system!
    my_system.Add(my_mesh);

    // ==Asset== attach a visualization of the FEM mesh.
    // This will automatically update a triangle mesh (a ChTriangleMeshShape
    // asset that is internally managed) by setting  proper
    // coordinates and vertex colours as in the FEM elements.
    // Such triangle mesh can be rendered by Irrlicht or POVray or whatever
    // postprocessor that can handle a coloured ChTriangleMeshShape).
    // Do not forget AddAsset() at the end!

    auto mvisualizebeamA = std::make_shared<ChVisualizationFEAmesh>(*(my_mesh.get()));
    mvisualizebeamA->SetFEMdataType(ChVisualizationFEAmesh::E_PLOT_ELEM_BEAM_MZ);
    mvisualizebeamA->SetColorscaleMinMax(-0.4, 0.4);
    mvisualizebeamA->SetSmoothFaces(true);
    mvisualizebeamA->SetWireframe(false);
    my_mesh->AddAsset(mvisualizebeamA);

    auto mvisualizebeamC = std::make_shared<ChVisualizationFEAmesh>(*(my_mesh.get()));
    mvisualizebeamC->SetFEMglyphType(ChVisualizationFEAmesh::E_GLYPH_NODE_CSYS);
    mvisualizebeamC->SetFEMdataType(ChVisualizationFEAmesh::E_PLOT_NONE);
    mvisualizebeamC->SetSymbolsThickness(0.006);
    mvisualizebeamC->SetSymbolsScale(0.01);
    mvisualizebeamC->SetZbufferHide(false);
    my_mesh->AddAsset(mvisualizebeamC);

    // ==IMPORTANT!== Use this function for adding a ChIrrNodeAsset to all items
    // in the system. These ChIrrNodeAsset assets are 'proxies' to the Irrlicht meshes.
    // If you need a finer control on which item really needs a visualization proxy in
    // Irrlicht, just use application.AssetBind(myitem); on a per-item basis.
    application.AssetBindAll();

    // ==IMPORTANT!== Use this function for 'converting' into Irrlicht meshes the assets
    // that you added to the bodies into 3D shapes, they can be visualized by Irrlicht!
    application.AssetUpdateAll();

    // Mark completion of system construction
    my_system.SetupInitial();

    // Change solver to MKL
    auto mkl_solver_stab = new ChSolverMKL<>;
    auto mkl_solver_speed = new ChSolverMKL<>;
    my_system.ChangeSolverStab(mkl_solver_stab);
    my_system.ChangeSolverSpeed(mkl_solver_speed);
	mkl_solver_stab->SetSparsityPatternLock(false);
	mkl_solver_speed->SetSparsityPatternLock(false);
    // WARNING: due to known issues on MKL Pardiso, if CSR matrix is used, sparsity pattern lock should be put OFF
    // Look at ChCSR3Matrix::SetElement comments to further details.
    application.GetSystem()->Update();

    // Change type of integrator:
    my_system.SetIntegrationType(chrono::ChSystem::INT_EULER_IMPLICIT_LINEARIZED);  // fast, less precise
    // my_system.SetIntegrationType(chrono::ChSystem::INT_HHT);  // precise,slower, might iterate each step

    // if later you want to change integrator settings:
    if (auto mystepper = std::dynamic_pointer_cast<ChTimestepperHHT>(my_system.GetTimestepper())) {
        mystepper->SetAlpha(-0.2);
        mystepper->SetMaxiters(2);
        mystepper->SetAbsTolerances(1e-6);
    }

    //
    // THE SOFT-REAL-TIME CYCLE
    //

    application.SetTimestep(0.01);

    while (application.GetDevice()->run()) {
        application.BeginScene();
        application.DrawAll();
        application.DoStep();
        application.EndScene();
    }

    return 0;
}
<|endoftext|>