<commit_before>// Filename: 	main.cpp
// Author: 		Christopher Goes
// Course: 		CS 404 Machine Learning and Data Mining
// Semester: 	Spring 2016
// Description:	Assignment 3 main program logic
// Github:		https://github.com/GhostofGoes/cgoes-cs404

#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <vector>
#include <cmath>
#include "matrix.h"

#define DEBUG 0
#define DEBUGINPUT 0
#define DEBUG_RESULTS 0

using namespace std;

double sigmoid( double input );     // Sigmoid function

int main() {

	// Initialization
	// weird init values are paranoia for error catching
	int numInputs = 0;
	int numOutputs = 0;
	int rows = 0;
	int cols = 0;
	int testRows = 0;
	int testCols = 0;
	double temp = -99;
	double bias = -1.0; // -1 is what the book uses.
	double eta = 0.025; // 0.25 is what the book uses. open to tweaking.
	int attempts = 1; // if debugging, SET THIS TO A SMALL NUMBER!
	//int num_hidden_layers = 1; // is this a thing
	int num_hidden_nodes = 0;
	double max = 1;
	double min = 1;

	//		Training Data Input 	//
	cin >> numInputs;
	cin >> num_hidden_nodes;
	cin >> rows;
	cin >> cols;
	numOutputs = cols - numInputs;

	Matrix* tinput = new Matrix(rows, numInputs + 1); // +1 for bias
	Matrix* toutput = new Matrix(rows, numOutputs);

	if(DEBUGINPUT) {
		cout << "Inputs: " << numInputs << "\nHidden Nodes: " << num_hidden_nodes << "\nRows: " << rows << "\nCols: " << cols << endl;
	}

	// Fill the matrix
	for(int r = 0; r < rows; r++) {
		for(int c = 0; c < numInputs; c++) {
			cin >> temp;
			if( temp > max ) max = temp;
			else if( temp < min ) min = temp;
			tinput->setValue( r, c, temp);
		}

		for(int c = 0; c < numOutputs; c++ ) {
			cin >> temp;
			if( temp > max ) max = temp;
			else if( temp < min ) min = temp;
			toutput->setValue( r, c, temp);
		}
	}

	// Append the bias
	for( int r = 0; r < rows; r++ ) {
		tinput->setValue(r, numInputs, bias);
	}
	numInputs++;

	if(DEBUGINPUT) {
		cout << "\nTraining Inputs..." << endl;
		tinput->printAll();
		cout << "\nTraining Outputs..." << endl;
		toutput->printAll();
	}

	//		Test Data Input 	//
	cin >> testRows;
	cin >> testCols;
	Matrix * testInput = new Matrix(testRows, testCols + 1);

	// Fill the matrix
	for(int r = 0; r < testRows; r++) {
		for(int c = 0; c < testCols; c++) {
			cin >> temp;
			if( temp > max ) max = temp;
			else if( temp < min ) min = temp;
			testInput->setValue(r, c, temp);
		}
	}

	// Append the bias
	for( int r = 0; r < testRows; r++ ) {
		testInput->setValue(r, testCols, bias);
	}
	testCols;

	if(DEBUGINPUT) {
		cout << "\nTest Inputs matrix" << endl;
		testInput->printAll();
	}

	// 						//
	// 		* Training * 	//

	Matrix * hw = new Matrix(num_hidden_nodes, numOutputs, 2);
	Matrix * ow = new Matrix(num_hidden_nodes + 1, numOutputs, 2); // +1 for the extra bias between hidden and output layers
	Matrix * tempmat;
	Matrix * deltah; // error in hidden layer
	Matrix * deltao; // error in output layer
	Matrix * a; // hidden layer output
	Matrix * y; // output layer output
	Matrix * hVec;
	Matrix * inVec;
	Matrix * t;
	temp = -99;

	if(DEBUG) {
		cout << "\nInitialized Hidden Weight matrix..." << endl;
		hw->printAll();
	}

	// Normalize our input
	tinput->normalize(min, max);

	// re-re-implementation
	for( int attempt = 0; attempt < attempts; attempt++ ) {
		// TODO randomize order rows are done each attempt?
		for( int r = 0; r < rows; r++ ) {
			inVec = tinput->getRow(r);
			t = toutput->getRow(r);

			if(DEBUG) {
			cout << "inVec" << endl;
			inVec->printAll();
			cout << endl;
			}
			// hidden layer
			a = inVec->dot(hw);
			a->sigmoid();

			if(DEBUG) {
			cout << "a" << endl;
			a->printAll();
			cout << endl;
			}
			hVec = new Matrix(a);
			hVec->data[0].push_back(bias);
			hVec->numCols++;

			if(DEBUG) {
			cout << "hVec" << endl;
			hVec->printAll();
			cout << endl;
			}
			// output layer
			y = hVec->dot(hw);
			y->sigmoid();

			if(DEBUG) {
			cout << "y" << endl;
			y->printAll();
			cout << endl;
			}
			// output error
			t = t->sub(y);
			t = t->dot(y);

			if(DEBUG) {
			cout << "y" << endl;
			t->printAll();
			cout << endl;
			}

			y->scalarPreSub(1.0);
			deltao = t->mult(y);

			if(DEBUG) {
			cout << "deltao" << endl;
			deltao->printAll();
			cout << endl;
			}

			// hidden error
			deltah = hVec;
			hVec->scalarPreSub(1.0);
			deltah->mult(hVec);
			hVec->scalarPreSub(1.0);
			tempmat = deltao->dot(ow);
			tempmat = tempmat->transpose();
			deltah = deltah->mult(tempmat);

			if(DEBUG) {
			cout << "deltah" << endl;
			deltah->printAll();
			cout << endl;
			}

			// update matricies
			hVec = hVec->transpose();
			hVec = hVec->dot(deltao);
			hVec = hVec->dot(eta);
			ow = ow->add(tempmat);

			deltah->data[0].pop_back();
			deltah->numCols--;

			tempmat = inVec->transpose();
			tempmat = inVec->dot(deltah);
			tempmat = tempmat->dot(eta);
			hw = hw->add(tempmat);

			delete deltao;
			delete deltah;
			delete a;
			delete y;
			delete hVec;
			delete inVec;
			delete t;
		} // rows

	} // attempts

	//							//
	//		 	Testing			//

	cout <<  "BEGIN TESTING" << endl;
	testInput->normalize(min, max);

	for( int r = 0; r < testRows; r++ ) { // Each row in testing set
		inVec = testInput->getRow(r);

		for (int i = 0; i < testCols; i++) {
			cout << fixed <<  setprecision(2) <<  testInput->getValue(r, i) <<  " ";
		}

		// hidden layer
		a = inVec->dot(hw);
		a->sigmoid();
		hVec = new Matrix(a);
		hVec->data[0].push_back(bias);
		hVec->numCols++;

		// output layer
		y = hVec->dot(hw);
		y->sigmoid();

		for( int i = 0; i < numOutputs; i++ ) {
			cout <<  fixed <<  setprecision(2) <<  y->getValue(0, i) << " ";
		}
		cout <<  endl; // end the row's output
	} // row in set loop

	//		Final Cleanup		//
	delete hw;
	delete ow;
	delete tinput;
	delete toutput;
	delete testInput;
	return(0);
}

double sigmoid( double input ) {
	return (2 / (1 + exp(-25 * input)) - 1);
}
<commit_msg>Minor edits before final HW3 submission<commit_after>// Filename: 	main.cpp
// Author: 		Christopher Goes
// Course: 		CS 404 Machine Learning and Data Mining
// Semester: 	Spring 2016
// Description:	Assignment 3 main program logic
// Github:		https://github.com/GhostofGoes/cgoes-cs404

#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <vector>
#include <cmath>
#include "matrix.h"

#define DEBUG 0
#define DEBUGINPUT 0
#define DEBUG_RESULTS 0

using namespace std;

double sigmoid( double input );     // Sigmoid function

int main() {

	// Initialization
	// weird init values are paranoia for error catching
	int numInputs = 0;
	int numOutputs = 0;
	int rows = 0;
	int cols = 0;
	int testRows = 0;
	int testCols = 0;
	double temp = -99;
	double bias = -1.0; // -1 is what the book uses.
	double eta = 0.025; // 0.25 is what the book uses. open to tweaking.
	int attempts = 1; // if debugging, SET THIS TO A SMALL NUMBER!
	//int num_hidden_layers = 1; // is this a thing
	int num_hidden_nodes = 0;
	double max = 1;
	double min = 1;

	//		Training Data Input 	//
	cin >> numInputs;
	cin >> num_hidden_nodes;
	cin >> rows;
	cin >> cols;
	numOutputs = cols - numInputs;

	Matrix* tinput = new Matrix(rows, numInputs + 1); // +1 for bias
	Matrix* toutput = new Matrix(rows, numOutputs);

	if(DEBUGINPUT) {
		cout << "Inputs: " << numInputs << "\nHidden Nodes: " << num_hidden_nodes << "\nRows: " << rows << "\nCols: " << cols << endl;
	}

	// Fill the matrix
	for(int r = 0; r < rows; r++) {
		for(int c = 0; c < numInputs; c++) {
			cin >> temp;
			if( temp > max ) max = temp;
			else if( temp < min ) min = temp;
			tinput->setValue( r, c, temp);
		}

		for(int c = 0; c < numOutputs; c++ ) {
			cin >> temp;
			if( temp > max ) max = temp;
			else if( temp < min ) min = temp;
			toutput->setValue( r, c, temp);
		}
	}

	// Append the bias
	for( int r = 0; r < rows; r++ ) {
		tinput->setValue(r, numInputs, bias);
	}
	numInputs++;

	if(DEBUGINPUT) {
		cout << "\nTraining Inputs..." << endl;
		tinput->printAll();
		cout << "\nTraining Outputs..." << endl;
		toutput->printAll();
	}

	//		Test Data Input 	//
	cin >> testRows;
	cin >> testCols;
	Matrix * testInput = new Matrix(testRows, testCols + 1);

	// Fill the matrix
	for(int r = 0; r < testRows; r++) {
		for(int c = 0; c < testCols; c++) {
			cin >> temp;
			if( temp > max ) max = temp;
			else if( temp < min ) min = temp;
			testInput->setValue(r, c, temp);
		}
	}

	// Append the bias
	for( int r = 0; r < testRows; r++ ) {
		testInput->setValue(r, testCols, bias);
	}
	testCols;

	if(DEBUGINPUT) {
		cout << "\nTest Inputs matrix" << endl;
		testInput->printAll();
	}

	// 						//
	// 		* Training * 	//

	Matrix * hw = new Matrix(num_hidden_nodes, numOutputs, 2);
	Matrix * ow = new Matrix(num_hidden_nodes + 1, numOutputs, 2); // +1 for the extra bias between hidden and output layers
	Matrix * tempmat;
	Matrix * deltah; // error in hidden layer
	Matrix * deltao; // error in output layer
	Matrix * a; // hidden layer output
	Matrix * y; // output layer output
	Matrix * hVec;
	Matrix * inVec;
	Matrix * t;
	temp = -99;

	if(DEBUG) {
		cout << "\nInitialized Hidden Weight matrix..." << endl;
		hw->printAll();
	}

	// Normalize our input
	tinput->normalize(min, max);

	// re-re-implementation
	for( int attempt = 0; attempt < attempts; attempt++ ) {
		// TODO randomize order rows are done each attempt?
		for( int r = 0; r < rows; r++ ) {
			inVec = tinput->getRow(r);
			t = toutput->getRow(r);

			if(DEBUG) {
			cout << "inVec" << endl;
			inVec->printAll();
			cout << endl;
			}
			// hidden layer
			a = inVec->dot(hw);
			a->sigmoid();

			if(DEBUG) {
			cout << "a" << endl;
			a->printAll();
			cout << endl;
			}
			hVec = new Matrix(a);
			hVec->data[0].push_back(bias);
			hVec->numCols++;

			if(DEBUG) {
			cout << "hVec" << endl;
			hVec->printAll();
			cout << endl;
			}
			// output layer
			y = hVec->dot(hw);
			y->sigmoid();

			if(DEBUG) {
			cout << "y" << endl;
			y->printAll();
			cout << endl;
			}
			// output error
			t = t->sub(y);
			t = t->dot(y);

			if(DEBUG) {
			cout << "y" << endl;
			t->printAll();
			cout << endl;
			}

			y->scalarPreSub(1.0);
			deltao = t->mult(y);

			if(DEBUG) {
			cout << "deltao" << endl;
			deltao->printAll();
			cout << endl;
			}

			// hidden error
			deltah = hVec;
			hVec->scalarPreSub(1.0);
			deltah->mult(hVec);
			hVec->scalarPreSub(1.0);
			tempmat = deltao->dot(ow);
			tempmat = tempmat->transpose();
			deltah = deltah->mult(tempmat);

			if(DEBUG) {
			cout << "deltah" << endl;
			deltah->printAll();
			cout << endl;
			}

			// update matricies
			hVec = hVec->transpose();
			hVec = hVec->dot(deltao);
			hVec = hVec->dot(eta);
			ow = ow->add(tempmat);

			deltah->data[0].pop_back();
			deltah->numCols--;

			tempmat = inVec->transpose();
			tempmat = inVec->dot(deltah);
			tempmat = tempmat->dot(eta);
			hw = hw->add(tempmat);

			delete deltao;
			delete deltah;
			delete a;
			delete y;
			delete hVec;
			delete inVec;
			delete t;
		} // rows

	} // attempts

	//							//
	//		 	Testing			//

	Matrix * normTestInput;

	cout <<  "BEGIN TESTING" << endl;
	normTestInput = new Matrix(testInput);
	normTestInput->normalize(min, max);

	for( int r = 0; r < testRows; r++ ) { // Each row in testing set
		inVec = normTestInput->getRow(r);

		for (int i = 0; i < testCols; i++) {
			cout << fixed <<  setprecision(2) <<  testInput->getValue(r, i) <<  " ";
		}

		// hidden layer
		a = inVec->dot(hw);
		a->sigmoid();
		hVec = new Matrix(a);
		hVec->data[0].push_back(bias);
		hVec->numCols++;

		// output layer
		y = hVec->dot(hw);
		y->sigmoid();

		for( int i = 0; i < numOutputs; i++ ) {
			cout <<  fixed <<  setprecision(2) <<  y->getValue(0, i) << " ";
		}
		cout <<  endl; // end the row's output
	} // row in set loop

	//		Final Cleanup		//
	delete hw;
	delete ow;
	delete tinput;
	delete toutput;
	delete testInput;
	return(0);
}

double sigmoid( double input ) {
	return (2 / (1 + exp(-25 * input)) - 1);
}
<|endoftext|>


<commit_before>#include <common/endian.h>

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

#include <http/http_protocol.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_protocol.h>

class SSHTransportPipe : public PipeProducer {
	enum State {
		GetIdentificationString,
		GetPacket
	};

	State state_;
	Buffer input_buffer_;
	size_t mac_length_;

	EventCallback *receive_callback_;
	Action *receive_action_;
public:
	SSHTransportPipe(void)
	: PipeProducer("/ssh/transport/pipe"),
	  state_(GetIdentificationString),
	  mac_length_(0),
	  receive_callback_(NULL),
	  receive_action_(NULL)
	{
		Buffer identification_string("SSH-2.0-WANProxy " + (std::string)log_ + "\r\n");
		produce(&identification_string);
	}

	~SSHTransportPipe()
	{
		ASSERT(receive_callback_ == NULL);
		ASSERT(receive_action_ == NULL);
	}

	Action *receive(EventCallback *cb)
	{
		ASSERT(receive_callback_ == NULL);
		ASSERT(receive_action_ == NULL);

		/*
		 * XXX
		 * This pattern is implemented about three different
		 * ways in the WANProxy codebase, and they are all kind
		 * of awful.  Need a better way to handle code that
		 * needs executed either on the request of the caller
		 * or when data comes in that satisfies a deferred
		 * callback to a caller.
		 */
		receive_callback_ = cb;
		receive_do();

		if (receive_callback_ != NULL)
			return (cancellation(this, &SSHTransportPipe::receive_cancel));

		ASSERT(receive_action_ != NULL);
		Action *a = receive_action_;
		receive_action_ = NULL;
		return (a);
	}

private:
	void consume(Buffer *in)
	{
		/* XXX XXX XXX */
		if (in->empty()) {
			if (!input_buffer_.empty())
				DEBUG(log_) << "Received EOS with data outstanding.";
			Buffer eos;
			produce(&eos);
			return;
		}

		input_buffer_.append(in);
		in->clear();

		if (state_ == GetIdentificationString) {
			HTTPProtocol::ParseStatus status;

			while (!input_buffer_.empty()) {
				Buffer line;
				status = HTTPProtocol::ExtractLine(&line, &input_buffer_);
				switch (status) {
				case HTTPProtocol::ParseSuccess:
					break;
				case HTTPProtocol::ParseFailure:
					ERROR(log_) << "Invalid line while waiting for identification string.";
					produce_error();
					return;
				case HTTPProtocol::ParseIncomplete:
					/* Wait for more.  */
					return;
				}

				if (!line.prefix("SSH-"))
					continue; /* Next line.  */

				if (!line.prefix("SSH-2.0")) {
					ERROR(log_) << "Unsupported version.";
					produce_error();
					return;
				}

				state_ = GetPacket;
				break;
			}
		}

		if (state_ == GetPacket && receive_callback_ != NULL)
			receive_do();
	}

	void receive_cancel(void)
	{
		if (receive_action_ != NULL) {
			receive_action_->cancel();
			receive_action_ = NULL;
		}

		if (receive_callback_ != NULL) {
			delete receive_callback_;
			receive_callback_ = NULL;
		}
	}

	void receive_do(void)
	{
		ASSERT(receive_action_ == NULL);
		ASSERT(receive_callback_ != NULL);

		if (state_ != GetPacket)
			return;

		while (!input_buffer_.empty()) {
			Buffer packet;
			Buffer mac;
			uint32_t packet_len;
			uint8_t padding_len;

			if (input_buffer_.length() <= sizeof packet_len) {
				DEBUG(log_) << "Waiting for packet length.";
				return;
			}

			input_buffer_.extract(&packet_len);
			packet_len = BigEndian::decode(packet_len);

			if (packet_len == 0) {
				ERROR(log_) << "Need to handle 0-length packet.";
				produce_error();
				return;
			}

			if (input_buffer_.length() < sizeof packet_len + packet_len + mac_length_) {
				DEBUG(log_) << "Need " << sizeof packet_len + packet_len + mac_length_ << "bytes; have " << input_buffer_.length() << ".";
				return;
			}

			input_buffer_.moveout(&packet, sizeof packet_len, packet_len);
			if (mac_length_ != 0)
				input_buffer_.moveout(&mac, 0, mac_length_);

			padding_len = packet.peek();
			packet.skip(sizeof padding_len);
			if (padding_len != 0) {
				if (packet.length() < padding_len) {
					ERROR(log_) << "Padding too large for packet.";
					produce_error();
					return;
				}
				packet.trim(padding_len);
			}

			if (packet.empty()) {
				ERROR(log_) << "Need to handle empty packet.";
				produce_error();
				return;
			}

			/*
			 * XXX
			 * Handle Transport messages internally?
			 */

			receive_callback_->param(Event(Event::Done, packet));
			receive_action_ = receive_callback_->schedule();
			receive_callback_ = NULL;

			return;
		}
	}
};

class SSHConnection {
	LogHandle log_;
	Socket *peer_;
	SSHTransportPipe *pipe_;
	Action *receive_action_;
	Splice *splice_;
	Action *splice_action_;
	Action *close_action_;
public:
	SSHConnection(Socket *peer)
	: log_("/ssh/connection"),
	  peer_(peer),
	  pipe_(NULL),
	  splice_(NULL),
	  splice_action_(NULL),
	  close_action_(NULL)
	{
		pipe_ = new SSHTransportPipe();
		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(close_action_ == NULL);
		ASSERT(splice_action_ == NULL);
		ASSERT(splice_ == NULL);
		ASSERT(receive_action_ == NULL);
		ASSERT(pipe_ == NULL);
		ASSERT(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(!e.buffer_.empty());

		switch (e.buffer_.peek()) {
		case SSH::Protocol::KeyExchangeInitializationMessage:
			break;
		default:
			DEBUG(log_) << "Received packet:" << 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(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(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(pipe_ != NULL);
		delete pipe_;
		pipe_ = NULL;

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

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>Add a basic transmit function, use it to mirror packets.<commit_after>#include <common/endian.h>

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

#include <http/http_protocol.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_protocol.h>

namespace {
	static uint8_t zero_padding[255];
}

class SSHTransportPipe : public PipeProducer {
	enum State {
		GetIdentificationString,
		GetPacket
	};

	State state_;
	Buffer input_buffer_;

	/* XXX These parameters are different for receive and send.  */
	size_t block_size_;
	size_t mac_length_;

	EventCallback *receive_callback_;
	Action *receive_action_;
public:
	SSHTransportPipe(void)
	: PipeProducer("/ssh/transport/pipe"),
	  state_(GetIdentificationString),
	  block_size_(8),
	  mac_length_(0),
	  receive_callback_(NULL),
	  receive_action_(NULL)
	{
		Buffer identification_string("SSH-2.0-WANProxy " + (std::string)log_ + "\r\n");
		produce(&identification_string);
	}

	~SSHTransportPipe()
	{
		ASSERT(receive_callback_ == NULL);
		ASSERT(receive_action_ == NULL);
	}

	Action *receive(EventCallback *cb)
	{
		ASSERT(receive_callback_ == NULL);
		ASSERT(receive_action_ == NULL);

		/*
		 * XXX
		 * This pattern is implemented about three different
		 * ways in the WANProxy codebase, and they are all kind
		 * of awful.  Need a better way to handle code that
		 * needs executed either on the request of the caller
		 * or when data comes in that satisfies a deferred
		 * callback to a caller.
		 */
		receive_callback_ = cb;
		receive_do();

		if (receive_callback_ != NULL)
			return (cancellation(this, &SSHTransportPipe::receive_cancel));

		ASSERT(receive_action_ != NULL);
		Action *a = receive_action_;
		receive_action_ = NULL;
		return (a);
	}

	/*
	 * Because this is primarily for WAN optimization we always use minimal
	 * padding and zero padding.  Quick and dirty.  Perhaps revisit later,
	 * although it makes send() asynchronous unless we add a blocking
	 * RNG interface.
	 */
	void send(Buffer *payload)
	{
		Buffer packet;
		uint8_t padding_len;
		uint32_t packet_len;

		packet_len = sizeof padding_len + payload->length();
		padding_len = 4 + (block_size_ - ((sizeof packet_len + packet_len + 4) % block_size_));
		packet_len += padding_len;

		packet_len = BigEndian::encode(packet_len);
		packet.append(&packet_len);
		packet.append(padding_len);
		packet.append(payload);
		packet.append(zero_padding, padding_len);

		if (mac_length_ != 0)
			NOTREACHED();

		payload->clear();

		produce(&packet);
	}

private:
	void consume(Buffer *in)
	{
		/* XXX XXX XXX */
		if (in->empty()) {
			if (!input_buffer_.empty())
				DEBUG(log_) << "Received EOS with data outstanding.";
			Buffer eos;
			produce(&eos);
			return;
		}

		input_buffer_.append(in);
		in->clear();

		if (state_ == GetIdentificationString) {
			HTTPProtocol::ParseStatus status;

			while (!input_buffer_.empty()) {
				Buffer line;
				status = HTTPProtocol::ExtractLine(&line, &input_buffer_);
				switch (status) {
				case HTTPProtocol::ParseSuccess:
					break;
				case HTTPProtocol::ParseFailure:
					ERROR(log_) << "Invalid line while waiting for identification string.";
					produce_error();
					return;
				case HTTPProtocol::ParseIncomplete:
					/* Wait for more.  */
					return;
				}

				if (!line.prefix("SSH-"))
					continue; /* Next line.  */

				if (!line.prefix("SSH-2.0")) {
					ERROR(log_) << "Unsupported version.";
					produce_error();
					return;
				}

				state_ = GetPacket;
				break;
			}
		}

		if (state_ == GetPacket && receive_callback_ != NULL)
			receive_do();
	}

	void receive_cancel(void)
	{
		if (receive_action_ != NULL) {
			receive_action_->cancel();
			receive_action_ = NULL;
		}

		if (receive_callback_ != NULL) {
			delete receive_callback_;
			receive_callback_ = NULL;
		}
	}

	void receive_do(void)
	{
		ASSERT(receive_action_ == NULL);
		ASSERT(receive_callback_ != NULL);

		if (state_ != GetPacket)
			return;

		while (!input_buffer_.empty()) {
			Buffer packet;
			Buffer mac;
			uint32_t packet_len;
			uint8_t padding_len;

			if (input_buffer_.length() <= sizeof packet_len) {
				DEBUG(log_) << "Waiting for packet length.";
				return;
			}

			input_buffer_.extract(&packet_len);
			packet_len = BigEndian::decode(packet_len);

			if (packet_len == 0) {
				ERROR(log_) << "Need to handle 0-length packet.";
				produce_error();
				return;
			}

			if (input_buffer_.length() < sizeof packet_len + packet_len + mac_length_) {
				DEBUG(log_) << "Need " << sizeof packet_len + packet_len + mac_length_ << "bytes; have " << input_buffer_.length() << ".";
				return;
			}

			input_buffer_.moveout(&packet, sizeof packet_len, packet_len);
			if (mac_length_ != 0)
				input_buffer_.moveout(&mac, 0, mac_length_);

			padding_len = packet.peek();
			packet.skip(sizeof padding_len);
			if (padding_len != 0) {
				if (packet.length() < padding_len) {
					ERROR(log_) << "Padding too large for packet.";
					produce_error();
					return;
				}
				packet.trim(padding_len);
			}

			if (packet.empty()) {
				ERROR(log_) << "Need to handle empty packet.";
				produce_error();
				return;
			}

			/*
			 * XXX
			 * Handle Transport messages internally?
			 */

			receive_callback_->param(Event(Event::Done, packet));
			receive_action_ = receive_callback_->schedule();
			receive_callback_ = NULL;

			return;
		}
	}
};

class SSHConnection {
	LogHandle log_;
	Socket *peer_;
	SSHTransportPipe *pipe_;
	Action *receive_action_;
	Splice *splice_;
	Action *splice_action_;
	Action *close_action_;
public:
	SSHConnection(Socket *peer)
	: log_("/ssh/connection"),
	  peer_(peer),
	  pipe_(NULL),
	  splice_(NULL),
	  splice_action_(NULL),
	  close_action_(NULL)
	{
		pipe_ = new SSHTransportPipe();
		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(close_action_ == NULL);
		ASSERT(splice_action_ == NULL);
		ASSERT(splice_ == NULL);
		ASSERT(receive_action_ == NULL);
		ASSERT(pipe_ == NULL);
		ASSERT(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(!e.buffer_.empty());

		/*
		 * SSH Echo!
		 */
		pipe_->send(&e.buffer_);
#if 0
		switch (e.buffer_.peek()) {
		case SSH::Protocol::KeyExchangeInitializationMessage:
			break;
		default:
			DEBUG(log_) << "Received packet:" << std::endl << e.buffer_.hexdump();
			break;
		}
#endif

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

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

		ASSERT(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(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(pipe_ != NULL);
		delete pipe_;
		pipe_ = NULL;

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

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>// terark-db-schema-compile.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#define TERARK_DB_SCHEMA_COMPILER
#include <terark/db/db_conf.cpp>

#if defined(_WIN32) || defined(_WIN64)
#include <getopt.c>
#endif

using namespace std;
using namespace terark;
using namespace terark::db;

int maxColnameLen(const Schema& schema) {
	const size_t colnum = schema.columnNum();
	int maxNameLen = 0;
	for (size_t i = 0; i < colnum; ++i) {
		const fstring colname = schema.getColumnName(i);
		maxNameLen = std::max(maxNameLen, colname.ilen());
	}
	return maxNameLen;
}

void compileOneSchema(const Schema& schema, const char* className,
					  const char* rowClassName) {
	const size_t colnum = schema.columnNum();
	printf("  struct %s {\n", className);
	for (size_t i = 0; i < colnum; ++i) {
		const ColumnMeta& colmeta = schema.getColumnMeta(i);
		const fstring     colname = schema.getColumnName(i);
		switch (colmeta.type) {
		case ColumnType::Any:
			assert(0); // not supported now
			break;
		case ColumnType::Nested:
			assert(0); // not supported now
			break;
		case ColumnType::Uint08:
			printf("    unsigned char %s;\n", colname.p);
			break;
		case ColumnType::Sint08:
			printf("    signed char %s;\n", colname.p);
			break;
		case ColumnType::Uint16:
			printf("    std::uint16_t %s;\n", colname.p);
			break;
		case ColumnType::Sint16:
			printf("    std::int16_t %s;\n", colname.p);
			break;
		case ColumnType::Uint32:
			printf("    std::uint32_t %s;\n", colname.p);
			break;
		case ColumnType::Sint32:
			printf("    std::int32_t %s;\n", colname.p);
			break;
		case ColumnType::Uint64:
			printf("    std::uint64_t %s;\n", colname.p);
			break;
		case ColumnType::Sint64:
			printf("    std::int64_t %s;\n", colname.p);
			break;
		case ColumnType::Uint128:
			printf("    unsigned __int128 %s;\n", colname.p);
			break;
		case ColumnType::Sint128:
			printf("    signed __int128 %s;\n", colname.p);
			break;
		case ColumnType::Float32:
			printf("    float %s;\n", colname.p);
			break;
		case ColumnType::Float64:
			printf("    double %s;\n", colname.p);
			break;
		case ColumnType::Float128:
			printf("    __float128 %s;\n", colname.p);
			break;
		case ColumnType::Decimal128:
			printf("    __decimal128 %s;\n", colname.p);
			break;
		case ColumnType::Uuid:
			printf("    terark::db::Schema::Fixed<16> %s;\n", colname.p);
			break;
		case ColumnType::Fixed:
			if (colmeta.realtype.empty()) {
				printf("    terark::db::Schema::Fixed<%d> %s;\n", int(colmeta.fixedLen), colname.p);
			}
			else {
				const char* realtype = colmeta.realtype.c_str();
				const int fixlen = int(colmeta.fixedLen);
				printf(R"EOS(
    %s %s;
 // dumpable type does not require sizeof(T)==fixlen, it only requires that
 // dump_size(T)==fixlen, but check for dump_size(T)==fixlen is cumbersome
 // and requires big changes for terark.dataio
 // so we static assert sizeof(T)==fixlen here:
    BOOST_STATIC_ASSERT(sizeof(%s) == %d);
    BOOST_STATIC_ASSERT((terark::DataIO_is_dump<terark::NativeDataInput<terark::MemIO>, %s >::value));

)EOS", realtype, colname.p, realtype, fixlen, realtype);
			}
			break;
		case ColumnType::VarSint:
			printf("    terark::var_int64_t %s;\n", colname.p);
			break;
		case ColumnType::VarUint:
			printf("    terark::var_uint64_t %s;\n", colname.p);
			break;
		case ColumnType::StrZero:
			printf("    std::string %s;\n", colname.p);
			break;
		case ColumnType::TwoStrZero:
			printf("    terark::db::Schema::TwoStrZero %s;\n", colname.p);
			break;
		case ColumnType::Binary:
			if (colmeta.realtype.empty()) {
				printf("    std::string %s;\n", colname.p);
			}
			else {
				const char* realtype = colmeta.realtype.c_str();
				printf("    %s %s;\n", realtype, colname.p);
			}
			break;
		case ColumnType::CarBin:
			if (colmeta.realtype.empty()) {
				printf("    terark::db::Schema::CarBin %s;\n", colname.p);
			}
			else {
				const char* realtype = colmeta.realtype.c_str();
				printf("    %s %s;\n", realtype, colname.p);
			}
			break;
		}
	}
	printf("\n");
	printf("    DATA_IO_LOAD_SAVE(%s,\n", className);
	for (size_t i = 0; i < colnum; ++i) {
		const ColumnMeta& colmeta = schema.getColumnMeta(i);
		const fstring     colname = schema.getColumnName(i);
		switch (colmeta.type) {
		case ColumnType::Any:
			assert(0); // not supported now
			break;
		case ColumnType::Nested:
			assert(0); // not supported now
			break;
		case ColumnType::Uint08:
		case ColumnType::Sint08:
		case ColumnType::Uint16:
		case ColumnType::Sint16:
		case ColumnType::Uint32:
		case ColumnType::Sint32:
		case ColumnType::Uint64:
		case ColumnType::Sint64:
		case ColumnType::Uint128:
		case ColumnType::Sint128:
		case ColumnType::Float32:
		case ColumnType::Float64:
		case ColumnType::Float128:
		case ColumnType::Decimal128:
		case ColumnType::Uuid:
		case ColumnType::Fixed:
		case ColumnType::VarSint:
		case ColumnType::VarUint:
			printf("      &%s\n", colname.p);
			break;
		case ColumnType::StrZero:
			if (i < colnum-1) {
				printf("      &terark::db::Schema::StrZero(%s)\n", colname.p);
			} else {
				printf("      &terark::RestAll(%s)\n", colname.p);
			}
			break;
		case ColumnType::TwoStrZero:
		case ColumnType::Binary:
		Case_Binary:
			if (i < colnum-1) {
				printf("      &%s\n", colname.p);
			} else {
				printf("      &terark::RestAll(%s)\n", colname.p);
			}
			break;
		case ColumnType::CarBin:
			if (colmeta.realtype.empty()) {
				goto Case_Binary;
			}
			if (i < colnum-1) {
				// read carbin size and check carbin size with real size
				printf("      &terark::db::Schema::CarBinPack(%s)\n", colname.p);
			} else {
				printf("      &%s\n", colname.p);
			}
			break;
		}
	}
	printf("    )\n");
	printf(
R"EOS(
    %s& decode(terark::fstring ___row) {
      terark::NativeDataInput<terark::MemIO> ___dio(___row.range());
      ___dio >> *this;
      return *this;
    }
    terark::fstring
    encode(terark::NativeDataOutput<terark::AutoGrownMemIO>& ___dio) const {
      ___dio.rewind();
      ___dio << *this;
      return ___dio.written();
    }
)EOS", className
	);
	int maxNameLen = maxColnameLen(schema);
	printf("    %s& select(const %s& ___row) {\n", className, rowClassName);
	for (size_t i = 0; i < colnum; ++i) {
		const char* colname = schema.getColumnName(i).c_str();
		printf("      %-*s = ___row.%s;\n", maxNameLen, colname, colname);
	}
	printf("      return *this;\n"); // select
	printf("    }\n"); // select
	printf("    void assign_to(%s& ___row) const {\n", rowClassName);
	for (size_t i = 0; i < colnum; ++i) {
		const char* colname = schema.getColumnName(i).c_str();
		printf("      ___row.%-*s = %s;\n", maxNameLen, colname, colname);
	}
	printf("    }\n"); // select

	printf("  }; // %s\n\n", className);
}

int usage(const char* prog) {
	fprintf(stderr, "usage: %s [ options ] terark-db-schema-file namespace table-name\n", prog);
	return 1;
}

int main(int argc, char* argv[]) {
	std::vector<const char*> includes;
	for (;;) {
		int opt = getopt(argc, argv, "i:");
		switch (opt) {
		case -1:
			goto GetoptDone;
		case '?':
			return usage(argv[0]);
		case 'i':
			includes.push_back(optarg);
			break;
		}
	}
GetoptDone:
	if (argc - optind < 3) {
		return usage(argv[0]);
	}
	const char* jsonFilePath = argv[optind + 0];
	const char* ns = argv[optind + 1];
	const char* tabName = argv[optind + 2];
	SchemaConfig sconf;
	try {
		sconf.loadJsonFile(jsonFilePath);
	}
	catch (const std::exception& ex) {
		fprintf(stderr, "ERROR: loadJsonFile(%s) failed: %s\n", jsonFilePath, ex.what());
		return 1;
	}
	printf(R"EOS(#pragma once
#include <terark/db/db_table.hpp>
#include <terark/io/DataIO.hpp>
#include <terark/io/MemStream.hpp>
#include <terark/io/RangeStream.hpp>
#include <boost/static_assert.hpp>

)EOS");
	for (const char* inc : includes) {
		printf("#include \"%s\"\n", inc);
	}
	printf("\n");
	printf("namespace %s {\n", ns);
	compileOneSchema(*sconf.m_rowSchema, tabName, tabName);
	for (size_t i = 0; i < sconf.m_colgroupSchemaSet->indexNum(); ++i) {
		const Schema& schema = *sconf.m_colgroupSchemaSet->getSchema(i);
		if (schema.columnNum() == 1)
			continue;
		std::string cgName = schema.m_name;
		std::transform(cgName.begin(), cgName.end(), cgName.begin(),
			[](unsigned char ch) -> char {
				if (isalnum(ch) || '_' == ch)
					return ch;
				else
					return '_';
			});
		std::string className = tabName;
		className += "_Colgroup_";
		className += cgName;
		compileOneSchema(schema, className.c_str(), tabName);
		if (i < sconf.m_indexSchemaSet->indexNum()) {
			printf("  typedef %s %s_Index_%s;\n\n", className.c_str(), tabName, cgName.c_str());
		}
	}
	printf("} // namespace %s\n", ns);
    return 0;
}

<commit_msg>terark-db-schema-compile: Add checkSchema()<commit_after>// terark-db-schema-compile.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#define TERARK_DB_SCHEMA_COMPILER
#include <terark/db/db_conf.cpp>

#if defined(_WIN32) || defined(_WIN64)
#include <getopt.c>
#endif

using namespace std;
using namespace terark;
using namespace terark::db;

int maxColnameLen(const Schema& schema) {
	const size_t colnum = schema.columnNum();
	int maxNameLen = 0;
	for (size_t i = 0; i < colnum; ++i) {
		const fstring colname = schema.getColumnName(i);
		maxNameLen = std::max(maxNameLen, colname.ilen());
	}
	return maxNameLen;
}

void compileOneSchema(const Schema& schema, const char* className,
					  const char* rowClassName) {
	const size_t colnum = schema.columnNum();
	printf("  struct %s {\n", className);
	for (size_t i = 0; i < colnum; ++i) {
		const ColumnMeta& colmeta = schema.getColumnMeta(i);
		const fstring     colname = schema.getColumnName(i);
		switch (colmeta.type) {
		case ColumnType::Any:
			assert(0); // not supported now
			break;
		case ColumnType::Nested:
			assert(0); // not supported now
			break;
		case ColumnType::Uint08:
			printf("    unsigned char %s;\n", colname.p);
			break;
		case ColumnType::Sint08:
			printf("    signed char %s;\n", colname.p);
			break;
		case ColumnType::Uint16:
			printf("    std::uint16_t %s;\n", colname.p);
			break;
		case ColumnType::Sint16:
			printf("    std::int16_t %s;\n", colname.p);
			break;
		case ColumnType::Uint32:
			printf("    std::uint32_t %s;\n", colname.p);
			break;
		case ColumnType::Sint32:
			printf("    std::int32_t %s;\n", colname.p);
			break;
		case ColumnType::Uint64:
			printf("    std::uint64_t %s;\n", colname.p);
			break;
		case ColumnType::Sint64:
			printf("    std::int64_t %s;\n", colname.p);
			break;
		case ColumnType::Uint128:
			printf("    unsigned __int128 %s;\n", colname.p);
			break;
		case ColumnType::Sint128:
			printf("    signed __int128 %s;\n", colname.p);
			break;
		case ColumnType::Float32:
			printf("    float %s;\n", colname.p);
			break;
		case ColumnType::Float64:
			printf("    double %s;\n", colname.p);
			break;
		case ColumnType::Float128:
			printf("    __float128 %s;\n", colname.p);
			break;
		case ColumnType::Decimal128:
			printf("    __decimal128 %s;\n", colname.p);
			break;
		case ColumnType::Uuid:
			printf("    terark::db::Schema::Fixed<16> %s;\n", colname.p);
			break;
		case ColumnType::Fixed:
			if (colmeta.realtype.empty()) {
				printf("    terark::db::Schema::Fixed<%d> %s;\n", int(colmeta.fixedLen), colname.p);
			}
			else {
				const char* realtype = colmeta.realtype.c_str();
				const int fixlen = int(colmeta.fixedLen);
				printf(R"EOS(
    %s %s;
 // dumpable type does not require sizeof(T)==fixlen, it only requires that
 // dump_size(T)==fixlen, but check for dump_size(T)==fixlen is cumbersome
 // and requires big changes for terark.dataio
 // so we static assert sizeof(T)==fixlen here:
    BOOST_STATIC_ASSERT(sizeof(%s) == %d);
    BOOST_STATIC_ASSERT((terark::DataIO_is_dump<terark::NativeDataInput<terark::MemIO>, %s >::value));

)EOS", realtype, colname.p, realtype, fixlen, realtype);
			}
			break;
		case ColumnType::VarSint:
			printf("    terark::var_int64_t %s;\n", colname.p);
			break;
		case ColumnType::VarUint:
			printf("    terark::var_uint64_t %s;\n", colname.p);
			break;
		case ColumnType::StrZero:
			printf("    std::string %s;\n", colname.p);
			break;
		case ColumnType::TwoStrZero:
			printf("    terark::db::Schema::TwoStrZero %s;\n", colname.p);
			break;
		case ColumnType::Binary:
			if (colmeta.realtype.empty()) {
				printf("    std::string %s;\n", colname.p);
			}
			else {
				const char* realtype = colmeta.realtype.c_str();
				printf("    %s %s;\n", realtype, colname.p);
			}
			break;
		case ColumnType::CarBin:
			if (colmeta.realtype.empty()) {
				printf("    terark::db::Schema::CarBin %s;\n", colname.p);
			}
			else {
				const char* realtype = colmeta.realtype.c_str();
				printf("    %s %s;\n", realtype, colname.p);
			}
			break;
		}
	}
	printf("\n");
	printf("    DATA_IO_LOAD_SAVE(%s,\n", className);
	for (size_t i = 0; i < colnum; ++i) {
		const ColumnMeta& colmeta = schema.getColumnMeta(i);
		const fstring     colname = schema.getColumnName(i);
		switch (colmeta.type) {
		case ColumnType::Any:
			assert(0); // not supported now
			break;
		case ColumnType::Nested:
			assert(0); // not supported now
			break;
		case ColumnType::Uint08:
		case ColumnType::Sint08:
		case ColumnType::Uint16:
		case ColumnType::Sint16:
		case ColumnType::Uint32:
		case ColumnType::Sint32:
		case ColumnType::Uint64:
		case ColumnType::Sint64:
		case ColumnType::Uint128:
		case ColumnType::Sint128:
		case ColumnType::Float32:
		case ColumnType::Float64:
		case ColumnType::Float128:
		case ColumnType::Decimal128:
		case ColumnType::Uuid:
		case ColumnType::Fixed:
		case ColumnType::VarSint:
		case ColumnType::VarUint:
			printf("      &%s\n", colname.p);
			break;
		case ColumnType::StrZero:
			if (i < colnum-1) {
				printf("      &terark::db::Schema::StrZero(%s)\n", colname.p);
			} else {
				printf("      &terark::RestAll(%s)\n", colname.p);
			}
			break;
		case ColumnType::TwoStrZero:
		case ColumnType::Binary:
		Case_Binary:
			if (i < colnum-1) {
				printf("      &%s\n", colname.p);
			} else {
				printf("      &terark::RestAll(%s)\n", colname.p);
			}
			break;
		case ColumnType::CarBin:
			if (colmeta.realtype.empty()) {
				goto Case_Binary;
			}
			if (i < colnum-1) {
				// read carbin size and check carbin size with real size
				printf("      &terark::db::Schema::CarBinPack(%s)\n", colname.p);
			} else {
				printf("      &%s\n", colname.p);
			}
			break;
		}
	}
	printf("    )\n");
	printf(
R"EOS(
    %s& decode(terark::fstring ___row) {
      terark::NativeDataInput<terark::MemIO> ___dio(___row.range());
      ___dio >> *this;
      return *this;
    }
    terark::fstring
    encode(terark::NativeDataOutput<terark::AutoGrownMemIO>& ___dio) const {
      ___dio.rewind();
      ___dio << *this;
      return ___dio.written();
    }
)EOS", className
	);
	if (fstring(className) != rowClassName) {
		int maxNameLen = maxColnameLen(schema);
		printf("    %s& select(const %s& ___row) {\n", className, rowClassName);
		for (size_t i = 0; i < colnum; ++i) {
			const char* colname = schema.getColumnName(i).c_str();
			printf("      %-*s = ___row.%s;\n", maxNameLen, colname, colname);
		}
		printf("      return *this;\n"); // select
		printf("    }\n"); // select
		printf("    void assign_to(%s& ___row) const {\n", rowClassName);
		for (size_t i = 0; i < colnum; ++i) {
			const char* colname = schema.getColumnName(i).c_str();
			printf("      ___row.%-*s = %s;\n", maxNameLen, colname, colname);
		}
		printf("    }\n"); // select
	}
	printf(
R"EOS(
    static const terark::db::Schema& getSchema() {
      using namespace terark::db;
      static Schema schema;
      // static std::mutex mtx;
      // std::unique_lock<std::mutex> lock(mtx);
      if (schema.columnNum() == 0) {
)EOS");
	for (size_t i = 0; i < colnum; ++i) {
		const char* colname = schema.getColumnName(i).c_str();
		const auto& colmeta = schema.getColumnMeta(i);
		printf(
R"EOS(        {
          ColumnMeta colmeta(ColumnType::%s);
          colmeta.fixedLen = %d;
          schema.m_columnsMeta.insert_i("%s", colmeta);
        }
)EOS", colmeta.typeNameString(), colmeta.fixedLen, colname
		);
	}
	printf(
R"EOS(      }
      return schema;
    }
)EOS"); // getSchema

	printf(
R"EOS(
    static bool
    checkSchema(const terark::db::Schema& schema, bool checkColname = false) {
      using namespace terark;
      using namespace terark::db;
      if (schema.columnNum() != %zd) {
        return false;
      }
)EOS", colnum);
	for (size_t i = 0; i < colnum; ++i) {
		const char* colname = schema.getColumnName(i).c_str();
		const auto& colmeta = schema.getColumnMeta(i);
		size_t fixlen = colmeta.fixedLen;
		printf(
R"EOS(      {
        const fstring     colname = schema.getColumnName(%zd);
        const ColumnMeta& colmeta = schema.getColumnMeta(%zd);
        if (checkColname && colname != "%s") {
          return false;
        }
        if (colmeta.type != ColumnType::%s) {
          return false;
        }
        if (colmeta.fixedLen != %zd) {
          assert(colmeta.type == ColumnType::Fixed);
          return false;
        }
      }
)EOS", i, i, colname, colmeta.typeNameString(), fixlen);
	}
	printf(
R"EOS(      return true;
    }
)EOS"); // checkSchema

	printf("  }; // %s\n\n", className);
}

int usage(const char* prog) {
	fprintf(stderr, "usage: %s [ options ] terark-db-schema-file namespace table-name\n", prog);
	return 1;
}

int main(int argc, char* argv[]) {
	std::vector<const char*> includes;
	for (;;) {
		int opt = getopt(argc, argv, "i:");
		switch (opt) {
		case -1:
			goto GetoptDone;
		case '?':
			return usage(argv[0]);
		case 'i':
			includes.push_back(optarg);
			break;
		}
	}
GetoptDone:
	if (argc - optind < 3) {
		return usage(argv[0]);
	}
	const char* jsonFilePath = argv[optind + 0];
	const char* ns = argv[optind + 1];
	const char* tabName = argv[optind + 2];
	SchemaConfig sconf;
	try {
		sconf.loadJsonFile(jsonFilePath);
	}
	catch (const std::exception& ex) {
		fprintf(stderr, "ERROR: loadJsonFile(%s) failed: %s\n", jsonFilePath, ex.what());
		return 1;
	}
	printf(R"EOS(#pragma once
#include <terark/db/db_table.hpp>
#include <terark/io/DataIO.hpp>
#include <terark/io/MemStream.hpp>
#include <terark/io/RangeStream.hpp>
#include <boost/static_assert.hpp>

)EOS");
	for (const char* inc : includes) {
		printf("#include \"%s\"\n", inc);
	}
	printf("\n");
	printf("namespace %s {\n", ns);
	compileOneSchema(*sconf.m_rowSchema, tabName, tabName);
	for (size_t i = 0; i < sconf.m_colgroupSchemaSet->indexNum(); ++i) {
		const Schema& schema = *sconf.m_colgroupSchemaSet->getSchema(i);
		if (schema.columnNum() == 1)
			continue;
		std::string cgName = schema.m_name;
		std::transform(cgName.begin(), cgName.end(), cgName.begin(),
			[](unsigned char ch) -> char {
				if (isalnum(ch) || '_' == ch)
					return ch;
				else
					return '_';
			});
		std::string className = tabName;
		className += "_Colgroup_";
		className += cgName;
		compileOneSchema(schema, className.c_str(), tabName);
		if (i < sconf.m_indexSchemaSet->indexNum()) {
			printf("  typedef %s %s_Index_%s;\n\n", className.c_str(), tabName, cgName.c_str());
		}
	}
	printf("} // namespace %s\n", ns);
    return 0;
}

<|endoftext|>


<commit_before>//=============================================================================================================
/**
* @file     main.cpp
* @author   Ruben Dörfel <ruben.doerfel@tu-ilmenau.de>;
*           Matti Hamalainen <msh@nmr.mgh.harvard.edu>
* @version  1.0
* @date     11, 2019
*
* @section  LICENSE
*
* Copyright (C) 2019, Ruben Doerrfel and Matti Hamalainen. 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 MNE-CPP authors 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.
*
*
* @brief     Example for filtering of data with realtime filtering. This example is combined with
*            ex_read_write_raw for reading and writing fiff files. So the result of the filtering can be seen
*            in MNE-Browse.
*
*/

//*************************************************************************************************************
//=============================================================================================================
// INCLUDES
//=============================================================================================================

#include <iostream>
#include <vector>
#include <math.h>

#include <fiff/fiff.h>
#include <utils/filterTools/filterdata.h>
#include <rtprocessing/rtfilter.h>

#include <utils/ioutils.h>

//*************************************************************************************************************
//=============================================================================================================
// Qt INCLUDES
//=============================================================================================================

#include <QtCore/QCoreApplication>
#include <QFile>
#include <QCommandLineParser>

//*************************************************************************************************************
//=============================================================================================================
// USED NAMESPACES
//=============================================================================================================

using namespace FIFFLIB;
using namespace UTILSLIB;
using namespace RTPROCESSINGLIB;

//*************************************************************************************************************
//=============================================================================================================
// MAIN
//=============================================================================================================

//=============================================================================================================
/**
* The function main marks the entry point of the program.
* By default, main has the storage class extern.
*
* @param [in] argc (argument count) is an integer that indicates how many arguments were entered on the command line when the program was started.
* @param [in] argv (argument vector) is an array of pointers to arrays of character objects. The array objects are null-terminated strings, representing the arguments that were entered on the command line when the program was started.
* @return the value that was set to exit() (which is 0 if exit() is called via quit()).
*/
int main(int argc, char *argv[])
{
    QElapsedTimer timer;

    QCoreApplication a(argc, argv);

    // Command Line Parser
    QCommandLineParser parser;
    parser.setApplicationDescription("Read Write Raw Example");
    parser.addHelpOption();

    QCommandLineOption inputOption("fileIn", "The input file <in>.", "in", QCoreApplication::applicationDirPath() + "/MNE-sample-data/MEG/sample/sample_audvis_raw.fif");
    QCommandLineOption outputOption("fileOut", "The output file <out>.", "out", QCoreApplication::applicationDirPath() + "/MNE-sample-data/MEG/sample/test_output.fif");

    parser.addOption(inputOption);
    parser.addOption(outputOption);

    parser.process(a);

    // Init data loading and writing
    QFile t_fileIn(parser.value(inputOption));
    QFile t_fileOut(parser.value(outputOption));

    FiffRawData raw(t_fileIn);

    // Set up pick list: MEG + STI 014 - bad channels
    bool want_meg   = true;
    bool want_eeg   = true;
    bool want_stim  = true;
    QStringList include;
    include << "STI 014";

    MatrixXi picks = raw.info.pick_types(want_meg, want_eeg, want_stim, include, raw.info.bads);
    if(picks.cols() == 0) {
        include.clear();
        include << "STI101" << "STI201" << "STI301";
        picks = raw.info.pick_types(want_meg, want_eeg, want_stim, include, raw.info.bads);
        if(picks.cols() == 0) {
            printf("channel list may need modification\n");
            return -1;
        }
    }

    RowVectorXd cals;
    FiffStream::SPtr outfid = FiffStream::start_writing_raw(t_fileOut, raw.info, cals/*, picks*/);

    // Set up the reading parameters
    fiff_int_t from = raw.first_samp;
    fiff_int_t to = raw.last_samp;

    // To read the whole file at once set quantum = to - from + 1;
    fiff_int_t quantum = to - from + 1;

    // Read and write the data
    bool first_buffer = true;

    fiff_int_t first, last;
    MatrixXd data;
    MatrixXd times;

    // initialize filter settings
    QString filter_name =  "example_cosine";
    FilterData::FilterType type = FilterData::BPF;
    double sFreq = raw.info.sfreq;                                          // get Sample freq from Data
    double centerfreq = 10/(sFreq/2.0);                                     // normed nyquist freq.
    double bandwidth = 10/(sFreq/2.0);
    double parkswidth = 1/(sFreq/2.0);

    RtFilter rtFilter;                                                      // filter object
    MatrixXd dataFiltered;                                                  // filter output

    // channel selection - in this case use every channel
    // size = number of channels; value = index channel number
    QVector<int> channelList(raw.info.nchan);
    for (int i = 0; i < raw.info.nchan; i++){
        channelList[i] = i;
    }

    for(first = from; first < to; first+=quantum) {
        last = first+quantum-1;
        if (last > to) {
            last = to;
        }

        if(!raw.read_raw_segment(data,times,first,last/*,picks*/)) {
            printf("error during read_raw_segment\n");
            return -1;
        }

        //Filtering
        printf("Filtering...");
        dataFiltered = rtFilter.filterData(data,type,centerfreq,bandwidth,parkswidth,sFreq,channelList);
        printf("[done]\n");

        //Writing
        printf("Writing...");
        if(first_buffer) {
           if(first > 0) {
               outfid->write_int(FIFF_FIRST_SAMPLE, &first);
           }
           first_buffer = false;
        }

        outfid->write_raw_buffer(dataFiltered,cals);
        printf("[done]\n");
    }

    outfid->finish_writing_raw();

    printf("Finished\n");

    return 0;
}
<commit_msg>ex_filtering: remove Timer for performance testing<commit_after>//=============================================================================================================
/**
* @file     main.cpp
* @author   Ruben Dörfel <ruben.doerfel@tu-ilmenau.de>;
*           Matti Hamalainen <msh@nmr.mgh.harvard.edu>
* @version  1.0
* @date     11, 2019
*
* @section  LICENSE
*
* Copyright (C) 2019, Ruben Doerrfel and Matti Hamalainen. 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 MNE-CPP authors 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.
*
*
* @brief     Example for filtering of data with realtime filtering. This example is combined with
*            ex_read_write_raw for reading and writing fiff files. So the result of the filtering can be seen
*            in MNE-Browse.
*
*/

//*************************************************************************************************************
//=============================================================================================================
// INCLUDES
//=============================================================================================================

#include <iostream>
#include <vector>
#include <math.h>

#include <fiff/fiff.h>
#include <utils/filterTools/filterdata.h>
#include <rtprocessing/rtfilter.h>

#include <utils/ioutils.h>

//*************************************************************************************************************
//=============================================================================================================
// Qt INCLUDES
//=============================================================================================================

#include <QtCore/QCoreApplication>
#include <QFile>
#include <QCommandLineParser>

//*************************************************************************************************************
//=============================================================================================================
// USED NAMESPACES
//=============================================================================================================

using namespace FIFFLIB;
using namespace UTILSLIB;
using namespace RTPROCESSINGLIB;

//*************************************************************************************************************
//=============================================================================================================
// MAIN
//=============================================================================================================

//=============================================================================================================
/**
* The function main marks the entry point of the program.
* By default, main has the storage class extern.
*
* @param [in] argc (argument count) is an integer that indicates how many arguments were entered on the command line when the program was started.
* @param [in] argv (argument vector) is an array of pointers to arrays of character objects. The array objects are null-terminated strings, representing the arguments that were entered on the command line when the program was started.
* @return the value that was set to exit() (which is 0 if exit() is called via quit()).
*/
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // Command Line Parser
    QCommandLineParser parser;
    parser.setApplicationDescription("Read Write Raw Example");
    parser.addHelpOption();

    QCommandLineOption inputOption("fileIn", "The input file <in>.", "in", QCoreApplication::applicationDirPath() + "/MNE-sample-data/MEG/sample/sample_audvis_raw.fif");
    QCommandLineOption outputOption("fileOut", "The output file <out>.", "out", QCoreApplication::applicationDirPath() + "/MNE-sample-data/MEG/sample/test_output.fif");

    parser.addOption(inputOption);
    parser.addOption(outputOption);

    parser.process(a);

    // Init data loading and writing
    QFile t_fileIn(parser.value(inputOption));
    QFile t_fileOut(parser.value(outputOption));

    FiffRawData raw(t_fileIn);

    // Set up pick list: MEG + STI 014 - bad channels
    bool want_meg   = true;
    bool want_eeg   = true;
    bool want_stim  = true;
    QStringList include;
    include << "STI 014";

    MatrixXi picks = raw.info.pick_types(want_meg, want_eeg, want_stim, include, raw.info.bads);
    if(picks.cols() == 0) {
        include.clear();
        include << "STI101" << "STI201" << "STI301";
        picks = raw.info.pick_types(want_meg, want_eeg, want_stim, include, raw.info.bads);
        if(picks.cols() == 0) {
            printf("channel list may need modification\n");
            return -1;
        }
    }

    RowVectorXd cals;
    FiffStream::SPtr outfid = FiffStream::start_writing_raw(t_fileOut, raw.info, cals/*, picks*/);

    // Set up the reading parameters
    fiff_int_t from = raw.first_samp;
    fiff_int_t to = raw.last_samp;

    // To read the whole file at once set quantum = to - from + 1;
    fiff_int_t quantum = to - from + 1;

    // Read and write the data
    bool first_buffer = true;

    fiff_int_t first, last;
    MatrixXd data;
    MatrixXd times;

    // initialize filter settings
    QString filter_name =  "example_cosine";
    FilterData::FilterType type = FilterData::BPF;
    double sFreq = raw.info.sfreq;                                          // get Sample freq from Data
    double centerfreq = 10/(sFreq/2.0);                                     // normed nyquist freq.
    double bandwidth = 10/(sFreq/2.0);
    double parkswidth = 1/(sFreq/2.0);

    RtFilter rtFilter;                                                      // filter object
    MatrixXd dataFiltered;                                                  // filter output

    // channel selection - in this case use every channel
    // size = number of channels; value = index channel number
    QVector<int> channelList(raw.info.nchan);
    for (int i = 0; i < raw.info.nchan; i++){
        channelList[i] = i;
    }

    for(first = from; first < to; first+=quantum) {
        last = first+quantum-1;
        if (last > to) {
            last = to;
        }

        if(!raw.read_raw_segment(data,times,first,last/*,picks*/)) {
            printf("error during read_raw_segment\n");
            return -1;
        }

        //Filtering
        printf("Filtering...");
        dataFiltered = rtFilter.filterData(data,type,centerfreq,bandwidth,parkswidth,sFreq,channelList);
        printf("[done]\n");

        //Writing
        printf("Writing...");
        if(first_buffer) {
           if(first > 0) {
               outfid->write_int(FIFF_FIRST_SAMPLE, &first);
           }
           first_buffer = false;
        }

        outfid->write_raw_buffer(dataFiltered,cals);
        printf("[done]\n");
    }

    outfid->finish_writing_raw();

    printf("Finished\n");

    return 0;
}
<|endoftext|>


<commit_before>#ifndef STAN_MATH_REV_FUN_SQUARED_DISTANCE_HPP
#define STAN_MATH_REV_FUN_SQUARED_DISTANCE_HPP

#include <stan/math/rev/meta.hpp>
#include <stan/math/rev/core.hpp>
#include <stan/math/prim/err.hpp>
#include <stan/math/prim/fun/squared_distance.hpp>
#include <stan/math/prim/fun/Eigen.hpp>
#include <stan/math/prim/fun/to_ref.hpp>
#include <stan/math/prim/fun/typedefs.hpp>
#include <vector>

namespace stan {
namespace math {

/**
 * Returns the squared distance.
 */
inline var squared_distance(const var& a, const var& b) {
  check_finite("squared_distance", "a", a);
  check_finite("squared_distance", "b", b);
  return make_callback_vari(std::pow(a.val() - b.val(), 2),
                            [a, b](const auto& vi) mutable {
                              const double diff = 2.0 * (a.val() - b.val());
                              a.adj() += vi.adj_ * diff;
                              b.adj() -= vi.adj_ * diff;
                            });
}

/**
 * Returns the squared distance.
 */
inline var squared_distance(const var& a, double b) {
  check_finite("squared_distance", "a", a);
  check_finite("squared_distance", "b", b);
  return make_callback_vari(std::pow(a.val() - b, 2),
                            [a, b](const auto& vi) mutable {
                              a.adj() += vi.adj_ * 2.0 * (a.val() - b);
                            });
}

/**
 * Returns the squared distance.
 */
inline var squared_distance(double a, const var& b) {
  return squared_distance(b, a);
}

namespace internal {

class squared_distance_vv_vari : public vari {
 protected:
  vari** v1_;
  vari** v2_;
  size_t length_;

 public:
  template <
      typename EigVecVar1, typename EigVecVar2,
      require_all_eigen_vector_vt<is_var, EigVecVar1, EigVecVar2>* = nullptr>
  squared_distance_vv_vari(const EigVecVar1& v1, const EigVecVar2& v2)
      : vari((as_column_vector_or_scalar(v1).val()
              - as_column_vector_or_scalar(v2).val())
                 .squaredNorm()),
        length_(v1.size()) {
    v1_ = reinterpret_cast<vari**>(
        ChainableStack::instance_->memalloc_.alloc(length_ * sizeof(vari*)));
    v2_ = reinterpret_cast<vari**>(
        ChainableStack::instance_->memalloc_.alloc(length_ * sizeof(vari*)));
    Eigen::Map<vector_vi>(v1_, length_) = v1.vi();
    Eigen::Map<vector_vi>(v2_, length_) = v2.vi();
  }

  virtual void chain() {
    Eigen::Map<vector_vi> v1_map(v1_, length_);
    Eigen::Map<vector_vi> v2_map(v2_, length_);
    vector_d di = 2 * adj_ * (v1_map.val() - v2_map.val());
    v1_map.adj() += di;
    v2_map.adj() -= di;
  }
};

class squared_distance_vd_vari : public vari {
 protected:
  vari** v1_;
  double* v2_;
  size_t length_;

 public:
  template <typename EigVecVar, typename EigVecArith,
            require_eigen_vector_vt<is_var, EigVecVar>* = nullptr,
            require_eigen_vector_vt<std::is_arithmetic, EigVecArith>* = nullptr>
  squared_distance_vd_vari(const EigVecVar& v1, const EigVecArith& v2)
      : vari((as_column_vector_or_scalar(v1).val()
              - as_column_vector_or_scalar(v2))
                 .squaredNorm()),
        length_(v1.size()) {
    v1_ = reinterpret_cast<vari**>(
        ChainableStack::instance_->memalloc_.alloc(length_ * sizeof(vari*)));
    v2_ = reinterpret_cast<double*>(
        ChainableStack::instance_->memalloc_.alloc(length_ * sizeof(double)));
    Eigen::Map<vector_vi>(v1_, length_) = v1.vi();
    Eigen::Map<vector_d>(v2_, length_) = v2;
  }

  virtual void chain() {
    Eigen::Map<vector_vi> v1_map(v1_, length_);
    v1_map.adj()
        += 2 * adj_ * (v1_map.val() - Eigen::Map<vector_d>(v2_, length_));
  }
};
}  // namespace internal

template <
    typename EigVecVar1, typename EigVecVar2,
    require_all_eigen_vector_vt<is_var, EigVecVar1, EigVecVar2>* = nullptr>
inline var squared_distance(const EigVecVar1& v1, const EigVecVar2& v2) {
  check_matching_sizes("squared_distance", "v1", v1, "v2", v2);
  return {new internal::squared_distance_vv_vari(to_ref(v1), to_ref(v2))};
}

template <typename EigVecVar, typename EigVecArith,
          require_eigen_vector_vt<is_var, EigVecVar>* = nullptr,
          require_eigen_vector_vt<std::is_arithmetic, EigVecArith>* = nullptr>
inline var squared_distance(const EigVecVar& v1, const EigVecArith& v2) {
  check_matching_sizes("squared_distance", "v1", v1, "v2", v2);
  return {new internal::squared_distance_vd_vari(to_ref(v1), to_ref(v2))};
}

template <typename EigVecArith, typename EigVecVar,
          require_eigen_vector_vt<std::is_arithmetic, EigVecArith>* = nullptr,
          require_eigen_vector_vt<is_var, EigVecVar>* = nullptr>
inline var squared_distance(const EigVecArith& v1, const EigVecVar& v2) {
  check_matching_sizes("squared_distance", "v1", v1, "v2", v2);
  return {new internal::squared_distance_vd_vari(to_ref(v2), to_ref(v1))};
}

/**
 * Compute the squared distance between the elements in
 * two inputs.
 *
 * This overload handles arguments where one of T1 or T2 are
 * `var_value<T>` where `T` is an Eigen type. The other type can
 * also be a `var_value` or it can be a matrix type that inherits
 * from EigenBase
 *
 * @tparam T1 type of first argument
 * @tparam T2 type of second argument
 * @param A first argument
 * @param B second argument
 * @return sum of squared difference of A and B
 */
template <typename T1, typename T2, require_all_vector_t<T1, T2>* = nullptr,
          require_any_var_vector_t<T1, T2>* = nullptr>
inline var squared_distance(const T1& A, const T2& B) {
  check_matching_sizes("squared_distance", "A", A.val(), "B", B.val());
  if (unlikely(A.size() == 0)) {
    return var(0.0);
  } else if (!is_constant<T1>::value && !is_constant<T2>::value) {
    arena_t<promote_scalar_t<var, T1>> arena_A = A;
    arena_t<promote_scalar_t<var, T2>> arena_B = B;
    arena_t<Eigen::VectorXd> res_diff(arena_A.size());
    double res_val = 0.0;
    for (size_t i = 0; i < arena_A.size(); ++i) {
      const double diff = arena_A.val().coeff(i) - arena_B.val().coeff(i);
      res_diff.coeffRef(i) = diff;
      res_val += diff * diff;
    }
    return var(make_callback_vari(
        res_val, [arena_A, arena_B, res_diff](const auto& res) mutable {
          const double res_adj = 2.0 * res.adj_;
          for (size_t i = 0; i < arena_A.size(); ++i) {
            const double diff = res_adj * res_diff.coeff(i);
            arena_A.adj().coeffRef(i) += diff;
            arena_B.adj().coeffRef(i) -= diff;
          }
        }));
  } else if (!is_constant<T1>::value) {
    arena_t<promote_scalar_t<var, T1>> arena_A = A;
    arena_t<promote_scalar_t<double, T2>> arena_B = value_of(B);
    arena_t<Eigen::VectorXd> res_diff(arena_A.size());
    double res_val = 0.0;
    for (size_t i = 0; i < arena_A.size(); ++i) {
      const double diff = arena_A.val().coeff(i) - arena_B.coeff(i);
      res_diff.coeffRef(i) = diff;
      res_val += diff * diff;
    }
    return var(make_callback_vari(
        res_val, [arena_A, arena_B, res_diff](const auto& res) mutable {
          arena_A.adj() += 2.0 * res.adj_ * res_diff;
        }));
  } else {
    arena_t<promote_scalar_t<double, T1>> arena_A = value_of(A);
    arena_t<promote_scalar_t<var, T2>> arena_B = B;
    arena_t<Eigen::VectorXd> res_diff(arena_A.size());
    double res_val = 0.0;
    for (size_t i = 0; i < arena_A.size(); ++i) {
      const double diff = arena_A.coeff(i) - arena_B.val().coeff(i);
      res_diff.coeffRef(i) = diff;
      res_val += diff * diff;
    }
    return var(make_callback_vari(
        res_val, [arena_A, arena_B, res_diff](const auto& res) mutable {
          arena_B.adj() -= 2.0 * res.adj_ * res_diff;
        }));
  }
}

}  // namespace math
}  // namespace stan
#endif
<commit_msg>Update includes (Issue #2101)<commit_after>#ifndef STAN_MATH_REV_FUN_SQUARED_DISTANCE_HPP
#define STAN_MATH_REV_FUN_SQUARED_DISTANCE_HPP

#include <stan/math/rev/meta.hpp>
#include <stan/math/rev/core.hpp>
#include <stan/math/rev/fun/value_of_rec.hpp>
#include <stan/math/prim/err.hpp>
#include <stan/math/prim/fun/squared_distance.hpp>
#include <stan/math/prim/fun/Eigen.hpp>
#include <stan/math/prim/fun/to_ref.hpp>
#include <stan/math/prim/fun/typedefs.hpp>
#include <vector>

namespace stan {
namespace math {

/**
 * Returns the squared distance.
 */
inline var squared_distance(const var& a, const var& b) {
  check_finite("squared_distance", "a", a);
  check_finite("squared_distance", "b", b);
  return make_callback_vari(std::pow(a.val() - b.val(), 2),
                            [a, b](const auto& vi) mutable {
                              const double diff = 2.0 * (a.val() - b.val());
                              a.adj() += vi.adj_ * diff;
                              b.adj() -= vi.adj_ * diff;
                            });
}

/**
 * Returns the squared distance.
 */
inline var squared_distance(const var& a, double b) {
  check_finite("squared_distance", "a", a);
  check_finite("squared_distance", "b", b);
  return make_callback_vari(std::pow(a.val() - b, 2),
                            [a, b](const auto& vi) mutable {
                              a.adj() += vi.adj_ * 2.0 * (a.val() - b);
                            });
}

/**
 * Returns the squared distance.
 */
inline var squared_distance(double a, const var& b) {
  return squared_distance(b, a);
}

namespace internal {

class squared_distance_vv_vari : public vari {
 protected:
  vari** v1_;
  vari** v2_;
  size_t length_;

 public:
  template <
      typename EigVecVar1, typename EigVecVar2,
      require_all_eigen_vector_vt<is_var, EigVecVar1, EigVecVar2>* = nullptr>
  squared_distance_vv_vari(const EigVecVar1& v1, const EigVecVar2& v2)
      : vari((as_column_vector_or_scalar(v1).val()
              - as_column_vector_or_scalar(v2).val())
                 .squaredNorm()),
        length_(v1.size()) {
    v1_ = reinterpret_cast<vari**>(
        ChainableStack::instance_->memalloc_.alloc(length_ * sizeof(vari*)));
    v2_ = reinterpret_cast<vari**>(
        ChainableStack::instance_->memalloc_.alloc(length_ * sizeof(vari*)));
    Eigen::Map<vector_vi>(v1_, length_) = v1.vi();
    Eigen::Map<vector_vi>(v2_, length_) = v2.vi();
  }

  virtual void chain() {
    Eigen::Map<vector_vi> v1_map(v1_, length_);
    Eigen::Map<vector_vi> v2_map(v2_, length_);
    vector_d di = 2 * adj_ * (v1_map.val() - v2_map.val());
    v1_map.adj() += di;
    v2_map.adj() -= di;
  }
};

class squared_distance_vd_vari : public vari {
 protected:
  vari** v1_;
  double* v2_;
  size_t length_;

 public:
  template <typename EigVecVar, typename EigVecArith,
            require_eigen_vector_vt<is_var, EigVecVar>* = nullptr,
            require_eigen_vector_vt<std::is_arithmetic, EigVecArith>* = nullptr>
  squared_distance_vd_vari(const EigVecVar& v1, const EigVecArith& v2)
      : vari((as_column_vector_or_scalar(v1).val()
              - as_column_vector_or_scalar(v2))
                 .squaredNorm()),
        length_(v1.size()) {
    v1_ = reinterpret_cast<vari**>(
        ChainableStack::instance_->memalloc_.alloc(length_ * sizeof(vari*)));
    v2_ = reinterpret_cast<double*>(
        ChainableStack::instance_->memalloc_.alloc(length_ * sizeof(double)));
    Eigen::Map<vector_vi>(v1_, length_) = v1.vi();
    Eigen::Map<vector_d>(v2_, length_) = v2;
  }

  virtual void chain() {
    Eigen::Map<vector_vi> v1_map(v1_, length_);
    v1_map.adj()
        += 2 * adj_ * (v1_map.val() - Eigen::Map<vector_d>(v2_, length_));
  }
};
}  // namespace internal

template <
    typename EigVecVar1, typename EigVecVar2,
    require_all_eigen_vector_vt<is_var, EigVecVar1, EigVecVar2>* = nullptr>
inline var squared_distance(const EigVecVar1& v1, const EigVecVar2& v2) {
  check_matching_sizes("squared_distance", "v1", v1, "v2", v2);
  return {new internal::squared_distance_vv_vari(to_ref(v1), to_ref(v2))};
}

template <typename EigVecVar, typename EigVecArith,
          require_eigen_vector_vt<is_var, EigVecVar>* = nullptr,
          require_eigen_vector_vt<std::is_arithmetic, EigVecArith>* = nullptr>
inline var squared_distance(const EigVecVar& v1, const EigVecArith& v2) {
  check_matching_sizes("squared_distance", "v1", v1, "v2", v2);
  return {new internal::squared_distance_vd_vari(to_ref(v1), to_ref(v2))};
}

template <typename EigVecArith, typename EigVecVar,
          require_eigen_vector_vt<std::is_arithmetic, EigVecArith>* = nullptr,
          require_eigen_vector_vt<is_var, EigVecVar>* = nullptr>
inline var squared_distance(const EigVecArith& v1, const EigVecVar& v2) {
  check_matching_sizes("squared_distance", "v1", v1, "v2", v2);
  return {new internal::squared_distance_vd_vari(to_ref(v2), to_ref(v1))};
}

/**
 * Compute the squared distance between the elements in
 * two inputs.
 *
 * This overload handles arguments where one of T1 or T2 are
 * `var_value<T>` where `T` is an Eigen type. The other type can
 * also be a `var_value` or it can be a matrix type that inherits
 * from EigenBase
 *
 * @tparam T1 type of first argument
 * @tparam T2 type of second argument
 * @param A first argument
 * @param B second argument
 * @return sum of squared difference of A and B
 */
template <typename T1, typename T2, require_all_vector_t<T1, T2>* = nullptr,
          require_any_var_vector_t<T1, T2>* = nullptr>
inline var squared_distance(const T1& A, const T2& B) {
  check_matching_sizes("squared_distance", "A", A.val(), "B", B.val());
  if (unlikely(A.size() == 0)) {
    return var(0.0);
  } else if (!is_constant<T1>::value && !is_constant<T2>::value) {
    arena_t<promote_scalar_t<var, T1>> arena_A = A;
    arena_t<promote_scalar_t<var, T2>> arena_B = B;
    arena_t<Eigen::VectorXd> res_diff(arena_A.size());
    double res_val = 0.0;
    for (size_t i = 0; i < arena_A.size(); ++i) {
      const double diff = arena_A.val().coeff(i) - arena_B.val().coeff(i);
      res_diff.coeffRef(i) = diff;
      res_val += diff * diff;
    }
    return var(make_callback_vari(
        res_val, [arena_A, arena_B, res_diff](const auto& res) mutable {
          const double res_adj = 2.0 * res.adj();
          for (size_t i = 0; i < arena_A.size(); ++i) {
            const double diff = res_adj * res_diff.coeff(i);
            arena_A.adj().coeffRef(i) += diff;
            arena_B.adj().coeffRef(i) -= diff;
          }
        }));
  } else if (!is_constant<T1>::value) {
    arena_t<promote_scalar_t<var, T1>> arena_A = A;
    arena_t<promote_scalar_t<double, T2>> arena_B = value_of(B);
    arena_t<Eigen::VectorXd> res_diff(arena_A.size());
    double res_val = 0.0;
    for (size_t i = 0; i < arena_A.size(); ++i) {
      const double diff = arena_A.val().coeff(i) - arena_B.coeff(i);
      res_diff.coeffRef(i) = diff;
      res_val += diff * diff;
    }
    return var(make_callback_vari(
        res_val, [arena_A, arena_B, res_diff](const auto& res) mutable {
          arena_A.adj() += 2.0 * res.adj() * res_diff;
        }));
  } else {
    arena_t<promote_scalar_t<double, T1>> arena_A = value_of(A);
    arena_t<promote_scalar_t<var, T2>> arena_B = B;
    arena_t<Eigen::VectorXd> res_diff(arena_A.size());
    double res_val = 0.0;
    for (size_t i = 0; i < arena_A.size(); ++i) {
      const double diff = arena_A.coeff(i) - arena_B.val().coeff(i);
      res_diff.coeffRef(i) = diff;
      res_val += diff * diff;
    }
    return var(make_callback_vari(
        res_val, [arena_A, arena_B, res_diff](const auto& res) mutable {
          arena_B.adj() -= 2.0 * res.adj() * res_diff;
        }));
  }
}

}  // namespace math
}  // namespace stan
#endif
<|endoftext|>


<commit_before>/* dhcpclient.hpp - dhcp client request handling
 *
 * (c) 2011-2014 Nicholas J. Kain <njkain at gmail dot com>
 * 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.
 *
 * 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.
 */

#ifndef NK_DHCPCLIENT_H
#define NK_DHCPCLIENT_H

#include <string>
#include <unordered_map>
#include <netdb.h>

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/enable_shared_from_this.hpp>

#include "dhcp.h"

// There are two hashtables, a 'new' and a 'marked for death' table.  If these
// tables are not empty, a timer with period t will wake up and delete all
// entries on the 'm4d' table and move the 'new' table to replace the 'm4d'
// table.  If an entry on the 'm4d' table is accessed, it will be moved to the
// 'new' table.  New entries will be added to the 'new' table.  If both tables
// are emptied, the timer can stop until a new entry is added.  We optimize
// the scheme by not actually performing moves: instead, we store an index
// to the 'new' table, and the 'marked for death' table is the unindexed table.
//
// This scheme requires no timestamping and will bound the lifetime of any
// object to be p < lifetime < 2p.  A further refinement would be to scale
// p to be inversely proportional to the number of entries on the 'new'
// and 'm4d' tables.  This change would cause the deletion rate to increase
// smoothly under heavy load, providing resistance to OOM DoS at the cost of
// making it so that clients will need to complete their transactions quickly.
class ClientStates {
public:
    ClientStates(boost::asio::io_service &io_service)
            : swapTimer_(io_service)
        {
        currentMap_ = 0;
        swapInterval_ = 60; // 1m
    }
    ~ClientStates() {}
    bool stateExists(uint32_t xid, const std::string &chaddr) const {
        std::string key(generateKey(xid, chaddr));
        return (map_[0].find(key) != map_[0].end()) ||
               (map_[1].find(key) != map_[1].end());
    }
    void stateAdd(uint32_t xid, const std::string &chaddr, uint8_t state)
    {
        std::string key(generateKey(xid, chaddr));
        if (!state)
            return;
        stateKill(xid, chaddr);
        map_[currentMap_][key] = state;
        if (swapTimer_.expires_from_now() <=
            boost::posix_time::time_duration(0,0,0,0))
            setTimer();
    }
    uint8_t stateGet(uint32_t xid, const std::string &chaddr) {
        std::string key(generateKey(xid, chaddr));
        auto r = map_[currentMap_].find(key);
        if (r != map_[currentMap_].end())
            return r->second;
        r = map_[!currentMap_].find(key);
        if (r != map_[!currentMap_].end()) {
            map_[!currentMap_].erase(r);
            map_[currentMap_][key] = r->second;
            return r->second;
        }
        return DHCPNULL;
    }
    void stateKill(uint32_t xid, const std::string &chaddr) {
        std::string key(generateKey(xid, chaddr));
        auto elt = map_[currentMap_].find(key);
        if (elt != map_[currentMap_].end()) {
            map_[currentMap_].erase(elt);
            return;
        }
        elt = map_[!currentMap_].find(key);
        if (elt != map_[!currentMap_].end())
            map_[!currentMap_].erase(elt);
    }
private:
    std::string generateKey(uint32_t xid, const std::string &chaddr) const {
        std::string r;
        union {
            uint8_t c[4];
            uint32_t n;
        } xia;
        xia.n = xid;
        r.push_back(xia.c[0]);
        r.push_back(xia.c[1]);
        r.push_back(xia.c[2]);
        r.push_back(xia.c[3]);
        r.append(chaddr);
        return r;
    }
    void doSwap(void) {
        int killMap = !currentMap_;
        map_[killMap].clear();
        currentMap_ = killMap;
    }
    void setTimer(void) {
        swapTimer_.expires_from_now(boost::posix_time::seconds(swapInterval_));
        swapTimer_.async_wait
            ([this](const boost::system::error_code& error)
            {
                doSwap();
                if (map_[0].size() || map_[1].size())
                    setTimer();

            });
    }
    // Key is concatenation of xid|chaddr.  Neither of these need to be stored
    // in explicit fields in the state structure.
    int currentMap_; // Either 0 or 1.
    int swapInterval_;
    boost::asio::deadline_timer swapTimer_;
    std::unordered_map<std::string, uint8_t> map_[2];
};

void init_client_states_v4(boost::asio::io_service &io_service);

class ClientListener
{
public:
    ClientListener(boost::asio::io_service &io_service,
                   const boost::asio::ip::udp::endpoint &endpoint,
                   const std::string &ifname);
private:
    void start_receive();
    uint64_t getNowTs(void) const;
    void dhcpmsg_init(struct dhcpmsg *dm, char type,
                      uint32_t xid, const std::string &chaddr) const;
    uint32_t local_ip() const;
    std::string ipStr(uint32_t ip) const;
    void send_reply(struct dhcpmsg *dm, bool broadcast);
    void reply_discover(const std::string &chaddr);
    void reply_request(const std::string &chaddr, bool is_direct);
    void reply_inform(const std::string &chaddr);
    void do_release(const std::string &chaddr);
    std::string getChaddr(const struct dhcpmsg &dm) const;
    bool validate_dhcp(void) const;
    void handle_receive(const boost::system::error_code &error,
                        std::size_t bytes_xferred);

    boost::asio::ip::udp::socket socket_;
    //boost::asio::ip::udp::socket broadcast_socket_;
    boost::asio::ip::udp::endpoint remote_endpoint_;
    std::array<uint8_t, 1024> recv_buffer_;
    struct dhcpmsg dhcpmsg_;
    boost::asio::ip::address local_ip_;
};

#endif /* NK_DHCPCLIENT_H */
<commit_msg>Remove unused headers.<commit_after>/* dhcpclient.hpp - dhcp client request handling
 *
 * (c) 2011-2014 Nicholas J. Kain <njkain at gmail dot com>
 * 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.
 *
 * 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.
 */

#ifndef NK_DHCPCLIENT_H
#define NK_DHCPCLIENT_H

#include <string>
#include <memory>
#include <unordered_map>
#include <netdb.h>

#include <boost/asio.hpp>

#include "dhcp.h"

// There are two hashtables, a 'new' and a 'marked for death' table.  If these
// tables are not empty, a timer with period t will wake up and delete all
// entries on the 'm4d' table and move the 'new' table to replace the 'm4d'
// table.  If an entry on the 'm4d' table is accessed, it will be moved to the
// 'new' table.  New entries will be added to the 'new' table.  If both tables
// are emptied, the timer can stop until a new entry is added.  We optimize
// the scheme by not actually performing moves: instead, we store an index
// to the 'new' table, and the 'marked for death' table is the unindexed table.
//
// This scheme requires no timestamping and will bound the lifetime of any
// object to be p < lifetime < 2p.  A further refinement would be to scale
// p to be inversely proportional to the number of entries on the 'new'
// and 'm4d' tables.  This change would cause the deletion rate to increase
// smoothly under heavy load, providing resistance to OOM DoS at the cost of
// making it so that clients will need to complete their transactions quickly.
class ClientStates {
public:
    ClientStates(boost::asio::io_service &io_service)
            : swapTimer_(io_service)
        {
        currentMap_ = 0;
        swapInterval_ = 60; // 1m
    }
    ~ClientStates() {}
    bool stateExists(uint32_t xid, const std::string &chaddr) const {
        std::string key(generateKey(xid, chaddr));
        return (map_[0].find(key) != map_[0].end()) ||
               (map_[1].find(key) != map_[1].end());
    }
    void stateAdd(uint32_t xid, const std::string &chaddr, uint8_t state)
    {
        std::string key(generateKey(xid, chaddr));
        if (!state)
            return;
        stateKill(xid, chaddr);
        map_[currentMap_][key] = state;
        if (swapTimer_.expires_from_now() <=
            boost::posix_time::time_duration(0,0,0,0))
            setTimer();
    }
    uint8_t stateGet(uint32_t xid, const std::string &chaddr) {
        std::string key(generateKey(xid, chaddr));
        auto r = map_[currentMap_].find(key);
        if (r != map_[currentMap_].end())
            return r->second;
        r = map_[!currentMap_].find(key);
        if (r != map_[!currentMap_].end()) {
            map_[!currentMap_].erase(r);
            map_[currentMap_][key] = r->second;
            return r->second;
        }
        return DHCPNULL;
    }
    void stateKill(uint32_t xid, const std::string &chaddr) {
        std::string key(generateKey(xid, chaddr));
        auto elt = map_[currentMap_].find(key);
        if (elt != map_[currentMap_].end()) {
            map_[currentMap_].erase(elt);
            return;
        }
        elt = map_[!currentMap_].find(key);
        if (elt != map_[!currentMap_].end())
            map_[!currentMap_].erase(elt);
    }
private:
    std::string generateKey(uint32_t xid, const std::string &chaddr) const {
        std::string r;
        union {
            uint8_t c[4];
            uint32_t n;
        } xia;
        xia.n = xid;
        r.push_back(xia.c[0]);
        r.push_back(xia.c[1]);
        r.push_back(xia.c[2]);
        r.push_back(xia.c[3]);
        r.append(chaddr);
        return r;
    }
    void doSwap(void) {
        int killMap = !currentMap_;
        map_[killMap].clear();
        currentMap_ = killMap;
    }
    void setTimer(void) {
        swapTimer_.expires_from_now(boost::posix_time::seconds(swapInterval_));
        swapTimer_.async_wait
            ([this](const boost::system::error_code& error)
            {
                doSwap();
                if (map_[0].size() || map_[1].size())
                    setTimer();

            });
    }
    // Key is concatenation of xid|chaddr.  Neither of these need to be stored
    // in explicit fields in the state structure.
    int currentMap_; // Either 0 or 1.
    int swapInterval_;
    boost::asio::deadline_timer swapTimer_;
    std::unordered_map<std::string, uint8_t> map_[2];
};

void init_client_states_v4(boost::asio::io_service &io_service);

class ClientListener
{
public:
    ClientListener(boost::asio::io_service &io_service,
                   const boost::asio::ip::udp::endpoint &endpoint,
                   const std::string &ifname);
private:
    void start_receive();
    uint64_t getNowTs(void) const;
    void dhcpmsg_init(struct dhcpmsg *dm, char type,
                      uint32_t xid, const std::string &chaddr) const;
    uint32_t local_ip() const;
    std::string ipStr(uint32_t ip) const;
    void send_reply(struct dhcpmsg *dm, bool broadcast);
    void reply_discover(const std::string &chaddr);
    void reply_request(const std::string &chaddr, bool is_direct);
    void reply_inform(const std::string &chaddr);
    void do_release(const std::string &chaddr);
    std::string getChaddr(const struct dhcpmsg &dm) const;
    bool validate_dhcp(void) const;
    void handle_receive(const boost::system::error_code &error,
                        std::size_t bytes_xferred);

    boost::asio::ip::udp::socket socket_;
    //boost::asio::ip::udp::socket broadcast_socket_;
    boost::asio::ip::udp::endpoint remote_endpoint_;
    std::array<uint8_t, 1024> recv_buffer_;
    struct dhcpmsg dhcpmsg_;
    boost::asio::ip::address local_ip_;
};

#endif /* NK_DHCPCLIENT_H */
<|endoftext|>


<commit_before>#include <iostream>

#include "vtrc-server/vtrc-application.h"
#include "vtrc-server/vtrc-listener-tcp.h"

#include "vtrc-common/vtrc-connection-iface.h"
#include "vtrc-common/vtrc-closure-holder.h"
#include "vtrc-common/vtrc-thread-pool.h"

#include "protocol/hello.pb.h"          /// hello protocol
#include "google/protobuf/descriptor.h" /// for descriptor( )->full_name( )
#include "boost/lexical_cast.hpp"

using namespace vtrc;

namespace {

class  hello_service_impl: public howto::hello_service {

    common::connection_iface *cl_;

    void send_hello(::google::protobuf::RpcController*  /*controller*/,
                    const ::howto::request_message*     request,
                    ::howto::response_message*          response,
                    ::google::protobuf::Closure*        done) /*override*/
    {
        common::closure_holder ch( done ); /// instead of done->Run( );
        std::ostringstream oss;

        oss << "Hello " << request->name( )
            << " from hello_service_impl::send_hello!\n"
            << "Your transport name is '"
            << cl_->name( ) << "'.\nHave a nice day.";

        response->set_hello( oss.str( ) );
        /// done->Run( ); /// ch will call it
    }

public:

    hello_service_impl( common::connection_iface *cl )
        :cl_(cl)
    { }

    static std::string const &service_name(  )
    {
        return howto::hello_service::descriptor( )->full_name( );
    }

};

class hello_application: public server::application {

    typedef common::rpc_service_wrapper     wrapper_type;
    typedef vtrc::shared_ptr<wrapper_type>  wrapper_sptr;

public:

    hello_application( common::thread_pool &tp )
        :server::application(tp.get_io_service( ))
    { }

    wrapper_sptr get_service_by_name( common::connection_iface* connection,
                                      const std::string &service_name )
    {
        if( service_name == hello_service_impl::service_name( ) ) {

             hello_service_impl *new_impl = new hello_service_impl(connection);

             return vtrc::make_shared<wrapper_type>( new_impl );

        }
        return wrapper_sptr( );
    }

};

} // namespace

int main( int argc, const char **argv )
{

    const char *address = "127.0.0.1";
    unsigned short port = 56560;

    if( argc > 2 ) {
        address = argv[1];
        port = boost::lexical_cast<unsigned short>( argv[2] );
    } else if( argc > 1 ) {
        port = boost::lexical_cast<unsigned short>( argv[1] );
    }

    common::thread_pool tp;
    hello_application app( tp );

    try {

        vtrc::shared_ptr<server::listener>
                tcp( server::listeners::tcp::create( app, address, port ) );

        tcp->start( );

        tp.attach( );

    } catch( const std::exception &ex ) {
        std::cerr << "Hello, world failed: " << ex.what( ) << "\n";
    }

    tp.join_all( );

    /// make valgrind happy.
    google::protobuf::ShutdownProtobufLibrary( );

    return 0;
}

<commit_msg>howto<commit_after>#include <iostream>

#include "vtrc-server/vtrc-application.h"
#include "vtrc-server/vtrc-listener-tcp.h"

#include "vtrc-common/vtrc-connection-iface.h"
#include "vtrc-common/vtrc-closure-holder.h"
#include "vtrc-common/vtrc-thread-pool.h"

#include "protocol/hello.pb.h"          /// hello protocol
#include "google/protobuf/descriptor.h" /// for descriptor( )->full_name( )
#include "boost/lexical_cast.hpp"

using namespace vtrc;

namespace {

class  hello_service_impl: public howto::hello_service {

    common::connection_iface *cl_;

    void send_hello(::google::protobuf::RpcController*  /*controller*/,
                    const ::howto::request_message*     request,
                    ::howto::response_message*          response,
                    ::google::protobuf::Closure*        done) /*override*/
    {
        common::closure_holder ch( done ); /// instead of done->Run( );
        std::ostringstream oss;

        oss << "Hello " << request->name( )
            << " from hello_service_impl::send_hello!\n"
            << "Your transport name is '"
            << cl_->name( ) << "'.\nHave a nice day.";

        response->set_hello( oss.str( ) );
        /// done->Run( ); /// ch will call it
    }

public:

    hello_service_impl( common::connection_iface *cl )
        :cl_(cl)
    { }

    static std::string const &service_name(  )
    {
        return howto::hello_service::descriptor( )->full_name( );
    }

};

class hello_application: public server::application {

    typedef common::rpc_service_wrapper     wrapper_type;
    typedef vtrc::shared_ptr<wrapper_type>  wrapper_sptr;

public:

    hello_application( common::thread_pool &tp )
        :server::application(tp.get_io_service( ))
    { }

    wrapper_sptr get_service_by_name( common::connection_iface* connection,
                                      const std::string &service_name )
    {
        if( service_name == hello_service_impl::service_name( ) ) {

             hello_service_impl *new_impl = new hello_service_impl(connection);

             return vtrc::make_shared<wrapper_type>( new_impl );

        }
        return wrapper_sptr( );
    }

};

} // namespace

int main( int argc, const char **argv )
{

    const char *address = "127.0.0.1";
    unsigned short port = 56560;

    if( argc > 2 ) {
        address = argv[1];
        port = boost::lexical_cast<unsigned short>( argv[2] );
    } else if( argc > 1 ) {
        port = boost::lexical_cast<unsigned short>( argv[1] );
    }

    common::thread_pool tp;
    hello_application app( tp );

    try {

        vtrc::shared_ptr<server::listener>
                tcp( server::listeners::tcp::create( app, address, port ) );

        tcp->start( );

        tp.attach( );

    } catch( const std::exception &ex ) {
        std::cerr << "Hello, world failed: " << ex.what( ) << "\n";
    }

    tp.join_all( );

    /// make valgrind happy.
    google::protobuf::ShutdownProtobufLibrary( );

    return 0;
}

<|endoftext|>