<commit_before>/*
 * This file is part of liblcf. Copyright (c) 2019 liblcf authors.
 * https://github.com/EasyRPG/liblcf - https://easyrpg.org
 *
 * liblcf is Free/Libre Open Source Software, released under the MIT License.
 * For the full copyright and license information, please view the COPYING
 * file that was distributed with this source code.
 */

#include <cstdarg>
#include <cstdio>
#include <istream>

#include "reader_lcf.h"

// Statics

std::string LcfReader::error_str;

LcfReader::LcfReader(std::istream& filestream, std::string encoding)
	: stream(filestream)
	, encoder(std::move(encoding))
{
	offset = filestream.tellg();
}

LcfReader::~LcfReader() {
}

size_t LcfReader::Read0(void *ptr, size_t size, size_t nmemb) {
	if (size == 0) { //avoid division by 0
		return 0;
	}
	//Read nmemb elements of size and return the number of read elements
	stream.read(reinterpret_cast<char*>(ptr), size*nmemb);
	auto bytes_read = stream.gcount();
	offset += bytes_read;
	size_t result = bytes_read / size;
#ifdef NDEBUG
	if (result != nmemb && !Eof()) {
		perror("Reading error: ");
	}
#endif
	return result;
}

void LcfReader::Read(void *ptr, size_t size, size_t nmemb) {
#ifdef NDEBUG
	Read0(ptr, size, nmemb);
#else
	if (Read0(ptr, size, nmemb) != nmemb) {
		fprintf(stderr, "Read error at %" PRIu32 ". The file is probably corrupted\n", Tell());
	}
#endif
}

template <>
void LcfReader::Read<bool>(bool& ref) {
	ref = ReadInt() > 0;
}

template <>
void LcfReader::Read<int8_t>(int8_t& ref) {
	Read(&ref, 1, 1);
}

template <>
void LcfReader::Read<uint8_t>(uint8_t& ref) {
	Read(&ref, 1, 1);
}

template <>
void LcfReader::Read<int16_t>(int16_t& ref) {
	Read(&ref, 2, 1);
	SwapByteOrder(ref);
}

template <>
void LcfReader::Read<uint32_t>(uint32_t& ref) {
	Read(&ref, 4, 1);
	SwapByteOrder(ref);
}

int LcfReader::ReadInt() {
	int value = 0;
	unsigned char temp = 0;
	int loops = 0;
	do {
		value <<= 7;
		if (Read0(&temp, 1, 1) == 0) {
			assert(value == 0);
			return 0;
		}
		value |= temp & 0x7F;

		if (loops > 5) {
			fprintf(stderr, "Invalid compressed integer at %" PRIu32 "\n", Tell());
		}
		++loops;
	} while (temp & 0x80);

	return loops > 5 ? 0 : value;
}

template <>
void LcfReader::Read<int32_t>(int32_t& ref) {
	ref = ReadInt();
}

template <>
void LcfReader::Read<double>(double& ref) {
	Read(&ref, 8, 1);
	SwapByteOrder(ref);
}

template <>
void LcfReader::Read<bool>(std::vector<bool> &buffer, size_t size) {
	buffer.clear();

	for (unsigned i = 0; i < size; ++i) {
		uint8_t val;
		Read(&val, 1, 1);
		buffer.push_back(val > 0);
	}
}

template <>
void LcfReader::Read<uint8_t>(std::vector<uint8_t> &buffer, size_t size) {
	buffer.clear();

	for (unsigned int i = 0; i < size; ++i) {
		uint8_t val;
		Read(&val, 1, 1);
		buffer.push_back(val);
	}
}

template <>
void LcfReader::Read<int16_t>(std::vector<int16_t> &buffer, size_t size) {
	buffer.clear();
	size_t items = size / 2;
	for (unsigned int i = 0; i < items; ++i) {
		int16_t val;
		Read(&val, 2, 1);
		SwapByteOrder(val);
		buffer.push_back(val);
	}
	if (size % 2 != 0) {
		Seek(1, FromCurrent);
		buffer.push_back(0);
	}
}

template <>
void LcfReader::Read<int32_t>(std::vector<int32_t> &buffer, size_t size) {
	buffer.clear();
	size_t items = size / 4;
	for (unsigned int i = 0; i < items; ++i) {
		int32_t val;
		Read(&val, 4, 1);
		SwapByteOrder(val);
		buffer.push_back(val);
	}
	if (size % 4 != 0) {
		Seek(size % 4, FromCurrent);
		buffer.push_back(0);
	}
}

template <>
void LcfReader::Read<uint32_t>(std::vector<uint32_t> &buffer, size_t size) {
	buffer.clear();
	size_t items = size / 4;
	for (unsigned int i = 0; i < items; ++i) {
		uint32_t val;
		Read(&val, 4, 1);
		SwapByteOrder(val);
		buffer.push_back(val);
	}
	if (size % 4 != 0) {
		Seek(size % 4, FromCurrent);
		buffer.push_back(0);
	}
}

void LcfReader::ReadString(std::string& ref, size_t size) {
	ref.resize(size);
	Read((size > 0 ? &ref.front(): nullptr), 1, size);
	Encode(ref);
}

bool LcfReader::IsOk() const {
	return stream.good() && encoder.IsOk();
}

bool LcfReader::Eof() const {
	return stream.eof();
}

void LcfReader::Seek(size_t pos, SeekMode mode) {
	switch (mode) {
	case LcfReader::FromStart:
		stream.seekg(pos, std::ios_base::beg);
		offset = stream.tellg();
		break;
	case LcfReader::FromCurrent:
		stream.seekg(pos, std::ios_base::cur);
		offset = stream.tellg();
		break;
	case LcfReader::FromEnd:
		stream.seekg(pos, std::ios_base::end);
		offset = stream.tellg();
		break;
	default:
		assert(false && "Invalid SeekMode");
	}
}

uint32_t LcfReader::Tell() {
	// Calling iostream tellg() results in a system call everytime and was found
	// to dominate the runtime of lcf reading. So we cache our own offset.
	// The result of this was shown to have a 30-40% improvement in LDB loading times.
	// return (uint32_t)stream.tellg();
	// This assert can be enabled to verify this method is correct. Disabled by
	// default as it will slow down debug loading considerably.
	// assert(stream.tellg() == offset);
	return offset;
}

int LcfReader::Peek() {
	return stream.peek();
}

#ifdef _DEBUG
void LcfReader::SkipDebug(const struct LcfReader::Chunk& chunk_info, const char* srcfile) {
	// Dump the Chunk Data in Debug Mode
#ifdef _WIN32
	const char* srcfilename = strrchr(srcfile, '\\');
#else
	const char* srcfilename = strrchr(srcfile, '/');
#endif
	if (srcfilename == NULL) {
		srcfilename = srcfile;
	} else {
		srcfilename++;
	}
	fprintf(stderr, "Skipped Chunk %02X (%" PRIu32 " byte) in lcf at %" PRIX32 " (%s)\n",
			chunk_info.ID, chunk_info.length, Tell(),
			srcfilename);
	for (uint32_t i = 0; i < chunk_info.length; ++i) {
		uint8_t byte;
		LcfReader::Read(byte);
		fprintf(stderr, "%02X ", byte);
		if ((i+1) % 16 == 0) {
			fprintf(stderr, "\n");
		}
		if (Eof()) {
			break;
		}
	}
	fprintf(stderr, "\n");
}
#else
void LcfReader::Skip(const struct LcfReader::Chunk& chunk_info) {
	Seek((size_t)chunk_info.length, FromCurrent);
}
#endif

void LcfReader::SetError(const char* fmt, ...) {
	va_list args;
	va_start(args, fmt);

	char str[256];
	vsprintf(str, fmt, args);

	error_str = str;
	//Output::ErrorStr((std::string)str);

	va_end(args);
}

const std::string& LcfReader::GetError() {
	return error_str;
}

void LcfReader::Encode(std::string& str) {
	encoder.Encode(str);
}

int LcfReader::IntSize(unsigned int x) {
	int result = 0;
	do {
		x >>= 7;
		result++;
	} while (x != 0);
	return result;
}

#ifdef WORDS_BIGENDIAN
void LcfReader::SwapByteOrder(uint16_t& us)
{
	us =	(us >> 8) |
			(us << 8);
}

void LcfReader::SwapByteOrder(uint32_t& ui)
{
	ui =	(ui >> 24) |
			((ui<<8) & 0x00FF0000) |
			((ui>>8) & 0x0000FF00) |
			(ui << 24);
}

void LcfReader::SwapByteOrder(double& d)
{
	uint32_t *p = reinterpret_cast<uint32_t *>(&d);
	SwapByteOrder(p[0]);
	SwapByteOrder(p[1]);
	uint32_t tmp = p[0];
	p[0] = p[1];
	p[1] = tmp;
}
#else
void LcfReader::SwapByteOrder(uint16_t& /* us */) {}
void LcfReader::SwapByteOrder(uint32_t& /* ui */) {}
void LcfReader::SwapByteOrder(double& /* d */) {}
#endif

void LcfReader::SwapByteOrder(int16_t& s)
{
	SwapByteOrder((uint16_t&) s);
}

void LcfReader::SwapByteOrder(int32_t& s)
{
	SwapByteOrder((uint32_t&) s);
}
<commit_msg>ReaderLcf: Optimize out calls to seekg() for small values<commit_after>/*
 * This file is part of liblcf. Copyright (c) 2019 liblcf authors.
 * https://github.com/EasyRPG/liblcf - https://easyrpg.org
 *
 * liblcf is Free/Libre Open Source Software, released under the MIT License.
 * For the full copyright and license information, please view the COPYING
 * file that was distributed with this source code.
 */

#include <cstdarg>
#include <cstdio>
#include <istream>

#include "reader_lcf.h"

// Statics

std::string LcfReader::error_str;

LcfReader::LcfReader(std::istream& filestream, std::string encoding)
	: stream(filestream)
	, encoder(std::move(encoding))
{
	offset = filestream.tellg();
}

LcfReader::~LcfReader() {
}

size_t LcfReader::Read0(void *ptr, size_t size, size_t nmemb) {
	if (size == 0) { //avoid division by 0
		return 0;
	}
	//Read nmemb elements of size and return the number of read elements
	stream.read(reinterpret_cast<char*>(ptr), size*nmemb);
	auto bytes_read = stream.gcount();
	offset += bytes_read;
	size_t result = bytes_read / size;
#ifdef NDEBUG
	if (result != nmemb && !Eof()) {
		perror("Reading error: ");
	}
#endif
	return result;
}

void LcfReader::Read(void *ptr, size_t size, size_t nmemb) {
#ifdef NDEBUG
	Read0(ptr, size, nmemb);
#else
	if (Read0(ptr, size, nmemb) != nmemb) {
		fprintf(stderr, "Read error at %" PRIu32 ". The file is probably corrupted\n", Tell());
	}
#endif
}

template <>
void LcfReader::Read<bool>(bool& ref) {
	ref = ReadInt() > 0;
}

template <>
void LcfReader::Read<int8_t>(int8_t& ref) {
	Read(&ref, 1, 1);
}

template <>
void LcfReader::Read<uint8_t>(uint8_t& ref) {
	Read(&ref, 1, 1);
}

template <>
void LcfReader::Read<int16_t>(int16_t& ref) {
	Read(&ref, 2, 1);
	SwapByteOrder(ref);
}

template <>
void LcfReader::Read<uint32_t>(uint32_t& ref) {
	Read(&ref, 4, 1);
	SwapByteOrder(ref);
}

int LcfReader::ReadInt() {
	int value = 0;
	unsigned char temp = 0;
	int loops = 0;
	do {
		value <<= 7;
		if (Read0(&temp, 1, 1) == 0) {
			assert(value == 0);
			return 0;
		}
		value |= temp & 0x7F;

		if (loops > 5) {
			fprintf(stderr, "Invalid compressed integer at %" PRIu32 "\n", Tell());
		}
		++loops;
	} while (temp & 0x80);

	return loops > 5 ? 0 : value;
}

template <>
void LcfReader::Read<int32_t>(int32_t& ref) {
	ref = ReadInt();
}

template <>
void LcfReader::Read<double>(double& ref) {
	Read(&ref, 8, 1);
	SwapByteOrder(ref);
}

template <>
void LcfReader::Read<bool>(std::vector<bool> &buffer, size_t size) {
	buffer.clear();

	for (unsigned i = 0; i < size; ++i) {
		uint8_t val;
		Read(&val, 1, 1);
		buffer.push_back(val > 0);
	}
}

template <>
void LcfReader::Read<uint8_t>(std::vector<uint8_t> &buffer, size_t size) {
	buffer.clear();

	for (unsigned int i = 0; i < size; ++i) {
		uint8_t val;
		Read(&val, 1, 1);
		buffer.push_back(val);
	}
}

template <>
void LcfReader::Read<int16_t>(std::vector<int16_t> &buffer, size_t size) {
	buffer.clear();
	size_t items = size / 2;
	for (unsigned int i = 0; i < items; ++i) {
		int16_t val;
		Read(&val, 2, 1);
		SwapByteOrder(val);
		buffer.push_back(val);
	}
	if (size % 2 != 0) {
		Seek(1, FromCurrent);
		buffer.push_back(0);
	}
}

template <>
void LcfReader::Read<int32_t>(std::vector<int32_t> &buffer, size_t size) {
	buffer.clear();
	size_t items = size / 4;
	for (unsigned int i = 0; i < items; ++i) {
		int32_t val;
		Read(&val, 4, 1);
		SwapByteOrder(val);
		buffer.push_back(val);
	}
	if (size % 4 != 0) {
		Seek(size % 4, FromCurrent);
		buffer.push_back(0);
	}
}

template <>
void LcfReader::Read<uint32_t>(std::vector<uint32_t> &buffer, size_t size) {
	buffer.clear();
	size_t items = size / 4;
	for (unsigned int i = 0; i < items; ++i) {
		uint32_t val;
		Read(&val, 4, 1);
		SwapByteOrder(val);
		buffer.push_back(val);
	}
	if (size % 4 != 0) {
		Seek(size % 4, FromCurrent);
		buffer.push_back(0);
	}
}

void LcfReader::ReadString(std::string& ref, size_t size) {
	ref.resize(size);
	Read((size > 0 ? &ref.front(): nullptr), 1, size);
	Encode(ref);
}

bool LcfReader::IsOk() const {
	return stream.good() && encoder.IsOk();
}

bool LcfReader::Eof() const {
	return stream.eof();
}

void LcfReader::Seek(size_t pos, SeekMode mode) {
	constexpr auto fast_seek_size = 32;
	switch (mode) {
	case LcfReader::FromStart:
		stream.seekg(pos, std::ios_base::beg);
		offset = stream.tellg();
		break;
	case LcfReader::FromCurrent:
		if (pos <= fast_seek_size) {
			// seekg() always results in a system call which is slow.
			// For small values just read and throwaway.
			char buf[fast_seek_size];
			stream.read(buf, pos);
			offset += stream.gcount();
		} else {
			stream.seekg(pos, std::ios_base::cur);
			offset = stream.tellg();
		}
		break;
	case LcfReader::FromEnd:
		stream.seekg(pos, std::ios_base::end);
		offset = stream.tellg();
		break;
	default:
		assert(false && "Invalid SeekMode");
	}
}

uint32_t LcfReader::Tell() {
	// Calling iostream tellg() results in a system call everytime and was found
	// to dominate the runtime of lcf reading. So we cache our own offset.
	// The result of this was shown to have a 30-40% improvement in LDB loading times.
	// return (uint32_t)stream.tellg();
	// This assert can be enabled to verify this method is correct. Disabled by
	// default as it will slow down debug loading considerably.
	// assert(stream.tellg() == offset);
	return offset;
}

int LcfReader::Peek() {
	return stream.peek();
}

#ifdef _DEBUG
void LcfReader::SkipDebug(const struct LcfReader::Chunk& chunk_info, const char* srcfile) {
	// Dump the Chunk Data in Debug Mode
#ifdef _WIN32
	const char* srcfilename = strrchr(srcfile, '\\');
#else
	const char* srcfilename = strrchr(srcfile, '/');
#endif
	if (srcfilename == NULL) {
		srcfilename = srcfile;
	} else {
		srcfilename++;
	}
	fprintf(stderr, "Skipped Chunk %02X (%" PRIu32 " byte) in lcf at %" PRIX32 " (%s)\n",
			chunk_info.ID, chunk_info.length, Tell(),
			srcfilename);
	for (uint32_t i = 0; i < chunk_info.length; ++i) {
		uint8_t byte;
		LcfReader::Read(byte);
		fprintf(stderr, "%02X ", byte);
		if ((i+1) % 16 == 0) {
			fprintf(stderr, "\n");
		}
		if (Eof()) {
			break;
		}
	}
	fprintf(stderr, "\n");
}
#else
void LcfReader::Skip(const struct LcfReader::Chunk& chunk_info) {
	Seek((size_t)chunk_info.length, FromCurrent);
}
#endif

void LcfReader::SetError(const char* fmt, ...) {
	va_list args;
	va_start(args, fmt);

	char str[256];
	vsprintf(str, fmt, args);

	error_str = str;
	//Output::ErrorStr((std::string)str);

	va_end(args);
}

const std::string& LcfReader::GetError() {
	return error_str;
}

void LcfReader::Encode(std::string& str) {
	encoder.Encode(str);
}

int LcfReader::IntSize(unsigned int x) {
	int result = 0;
	do {
		x >>= 7;
		result++;
	} while (x != 0);
	return result;
}

#ifdef WORDS_BIGENDIAN
void LcfReader::SwapByteOrder(uint16_t& us)
{
	us =	(us >> 8) |
			(us << 8);
}

void LcfReader::SwapByteOrder(uint32_t& ui)
{
	ui =	(ui >> 24) |
			((ui<<8) & 0x00FF0000) |
			((ui>>8) & 0x0000FF00) |
			(ui << 24);
}

void LcfReader::SwapByteOrder(double& d)
{
	uint32_t *p = reinterpret_cast<uint32_t *>(&d);
	SwapByteOrder(p[0]);
	SwapByteOrder(p[1]);
	uint32_t tmp = p[0];
	p[0] = p[1];
	p[1] = tmp;
}
#else
void LcfReader::SwapByteOrder(uint16_t& /* us */) {}
void LcfReader::SwapByteOrder(uint32_t& /* ui */) {}
void LcfReader::SwapByteOrder(double& /* d */) {}
#endif

void LcfReader::SwapByteOrder(int16_t& s)
{
	SwapByteOrder((uint16_t&) s);
}

void LcfReader::SwapByteOrder(int32_t& s)
{
	SwapByteOrder((uint32_t&) s);
}
<|endoftext|>


<commit_before>//===----------------------------------------------------------------------===//
//
//                         Peloton
//
// group_by_sql_test.cpp
//
// Identification: test/sql/group_by_sql_test.cpp
//
// Copyright (c) 2015-17, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include <memory>

#include "sql/testing_sql_util.h"
#include "catalog/catalog.h"
#include "common/harness.h"
#include "executor/create_executor.h"
#include "optimizer/optimizer.h"
#include "optimizer/simple_optimizer.h"
#include "planner/create_plan.h"
#include "planner/order_by_plan.h"

namespace peloton {
namespace test {

class GroupBySQLTests : public PelotonTest {};

TEST_F(GroupBySQLTests, EmptyTableTest) {
  auto &txn_manager = concurrency::TransactionManagerFactory::GetInstance();
  auto txn = txn_manager.BeginTransaction();
  catalog::Catalog::GetInstance()->CreateDatabase(DEFAULT_DB_NAME, txn);
  txn_manager.CommitTransaction(txn);

  // Create a table first
  TestingSQLUtil::ExecuteSQLQuery(
      "create table xxx (id int, name varchar, salary decimal);");
}
TEST_F(GroupBySQLTests, SimpleGroupByTest) {
  auto &txn_manager = concurrency::TransactionManagerFactory::GetInstance();
  auto txn = txn_manager.BeginTransaction();
  catalog::Catalog::GetInstance()->CreateDatabase(DEFAULT_DB_NAME, txn);

  // Create a table first
  // into the table
  TestingSQLUtil::ExecuteSQLQuery(
      "create table xxx (id int, name varchar, salary decimal);");

  // Insert tuples into table
  TestingSQLUtil::ExecuteSQLQuery("insert into xxx values(1, 'Mike', 1000);");
  TestingSQLUtil::ExecuteSQLQuery("insert into xxx values(2, 'Jane', 2000);");
  TestingSQLUtil::ExecuteSQLQuery("insert into xxx values(3, 'Tom', 3000);");
  TestingSQLUtil::ExecuteSQLQuery("insert into xxx values(4, 'Kelly', 4000);");
  TestingSQLUtil::ExecuteSQLQuery("insert into xxx values(5, 'Lucy', 3000);");
  TestingSQLUtil::ExecuteSQLQuery("insert into xxx values(6, 'Tim', 2000);");
  TestingSQLUtil::ShowTable(DEFAULT_DB_NAME, "xxx");

  std::vector<StatementResult> result;
  std::vector<FieldInfo> tuple_descriptor;
  std::string error_message;
  int rows_affected;
  std::unique_ptr<optimizer::AbstractOptimizer> optimizer(
      new optimizer::Optimizer());
  std::string query1("select count(id), salary from xxx group by salary;");
  LOG_DEBUG("Running Query %s", query1.c_str());
  TestingSQLUtil::ExecuteSQLQueryWithOptimizer(
      optimizer, query1, result, tuple_descriptor, rows_affected, error_message);

  //TestingSQLUtil::ExecuteSQLQuery(
  //    "select count(id), salary from xxx group by salary;", result,
   //   tuple_descriptor, rows_affected, error_message);

  // Check the return value
  EXPECT_EQ(0, rows_affected);
  EXPECT_EQ("2", TestingSQLUtil::GetResultValueAsString(result, 0));
  EXPECT_EQ("1", TestingSQLUtil::GetResultValueAsString(result, 2));
  EXPECT_EQ("2", TestingSQLUtil::GetResultValueAsString(result, 4));
  EXPECT_EQ("1", TestingSQLUtil::GetResultValueAsString(result, 6));

  // test: GROUP BY + HAVING
  std::string query2("select count(id), salary from xxx group by salary having salary>1000;");
  LOG_DEBUG("Running Query %s", query2.c_str());
  TestingSQLUtil::ExecuteSQLQueryWithOptimizer(
      optimizer, query2, result, tuple_descriptor, rows_affected, error_message);
//  TestingSQLUtil::ExecuteSQLQuery(
//      "select count(id), salary from xxx group by salary having salary>1000;",
//      result, tuple_descriptor, rows_affected, error_message);

  // Check the return value
  EXPECT_EQ(0, rows_affected);
  EXPECT_EQ("2", TestingSQLUtil::GetResultValueAsString(result, 0));
  EXPECT_EQ("1", TestingSQLUtil::GetResultValueAsString(result, 2));
  EXPECT_EQ("2", TestingSQLUtil::GetResultValueAsString(result, 4));

  // test: GROUP BY + ORDER BY
  std::string query3("select count(id), salary from xxx group by salary order by salary;");
  LOG_DEBUG("Running Query %s", query3.c_str());
  TestingSQLUtil::ExecuteSQLQueryWithOptimizer(
      optimizer, query3, result, tuple_descriptor, rows_affected, error_message);
//  TestingSQLUtil::ExecuteSQLQuery(
//      "select count(id), salary from xxx group by salary order by salary;",
//      result, tuple_descriptor, rows_affected, error_message);

  // Check the return value
  EXPECT_EQ(0, rows_affected);
  EXPECT_EQ("1", TestingSQLUtil::GetResultValueAsString(result, 0));
  EXPECT_EQ("2", TestingSQLUtil::GetResultValueAsString(result, 2));
  EXPECT_EQ("2", TestingSQLUtil::GetResultValueAsString(result, 4));
  EXPECT_EQ("1", TestingSQLUtil::GetResultValueAsString(result, 6));
  EXPECT_EQ("1000", TestingSQLUtil::GetResultValueAsString(result, 1));
  EXPECT_EQ("2000", TestingSQLUtil::GetResultValueAsString(result, 3));
  EXPECT_EQ("3000", TestingSQLUtil::GetResultValueAsString(result, 5));
  EXPECT_EQ("4000", TestingSQLUtil::GetResultValueAsString(result, 7));

  // free the database just created
  catalog::Catalog::GetInstance()->DropDatabaseWithName(DEFAULT_DB_NAME, txn);
  txn_manager.CommitTransaction(txn);
}

}  // namespace test
}  // namespace peloton
<commit_msg>Solved groupby test case failure.<commit_after>//===----------------------------------------------------------------------===//
//
//                         Peloton
//
// group_by_sql_test.cpp
//
// Identification: test/sql/group_by_sql_test.cpp
//
// Copyright (c) 2015-17, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include <memory>

#include "sql/testing_sql_util.h"
#include "catalog/catalog.h"
#include "common/harness.h"
#include "executor/create_executor.h"
#include "optimizer/optimizer.h"
#include "optimizer/simple_optimizer.h"
#include "planner/create_plan.h"
#include "planner/order_by_plan.h"

namespace peloton {
namespace test {

class GroupBySQLTests : public PelotonTest {};

TEST_F(GroupBySQLTests, EmptyTableTest) {
  auto &txn_manager = concurrency::TransactionManagerFactory::GetInstance();
  auto txn = txn_manager.BeginTransaction();
  catalog::Catalog::GetInstance()->CreateDatabase(DEFAULT_DB_NAME, txn);
  txn_manager.CommitTransaction(txn);

  // Create a table first
  TestingSQLUtil::ExecuteSQLQuery(
      "create table xxx (id int, name varchar, salary decimal);");
}
TEST_F(GroupBySQLTests, SimpleGroupByTest) {
  auto &txn_manager = concurrency::TransactionManagerFactory::GetInstance();
  auto txn = txn_manager.BeginTransaction();
  catalog::Catalog::GetInstance()->CreateDatabase(DEFAULT_DB_NAME, txn);

  // Create a table first
  // into the table
  TestingSQLUtil::ExecuteSQLQuery(
      "create table xxx (id int, name varchar, salary decimal);");

  // Insert tuples into table
  TestingSQLUtil::ExecuteSQLQuery("insert into xxx values(1, 'Mike', 1000);");
  TestingSQLUtil::ExecuteSQLQuery("insert into xxx values(2, 'Jane', 2000);");
  TestingSQLUtil::ExecuteSQLQuery("insert into xxx values(3, 'Tom', 3000);");
  TestingSQLUtil::ExecuteSQLQuery("insert into xxx values(4, 'Kelly', 4000);");
  TestingSQLUtil::ExecuteSQLQuery("insert into xxx values(5, 'Lucy', 3000);");
  TestingSQLUtil::ExecuteSQLQuery("insert into xxx values(6, 'Tim', 2000);");
  TestingSQLUtil::ShowTable(DEFAULT_DB_NAME, "xxx");

  std::vector<StatementResult> result;
  std::vector<FieldInfo> tuple_descriptor;
  std::string error_message;
  int rows_affected;
  std::unique_ptr<optimizer::AbstractOptimizer> optimizer(
      new optimizer::Optimizer());
  std::string query1("select count(id), salary from xxx group by salary;");
  LOG_DEBUG("Running Query %s", query1.c_str());
  TestingSQLUtil::ExecuteSQLQueryWithOptimizer(
      optimizer, query1, result, tuple_descriptor, rows_affected, error_message);

  //TestingSQLUtil::ExecuteSQLQuery(
  //    "select count(id), salary from xxx group by salary;", result,
   //   tuple_descriptor, rows_affected, error_message);

  // Check the return value
  EXPECT_EQ(0, rows_affected);
  EXPECT_EQ("2", TestingSQLUtil::GetResultValueAsString(result, 0));
  EXPECT_EQ("1", TestingSQLUtil::GetResultValueAsString(result, 2));
  EXPECT_EQ("2", TestingSQLUtil::GetResultValueAsString(result, 4));
  EXPECT_EQ("1", TestingSQLUtil::GetResultValueAsString(result, 6));

  // test: GROUP BY + HAVING
  std::string query2("select count(id), salary from xxx group by salary having salary>1000;");
  LOG_DEBUG("Running Query %s", query2.c_str());
  TestingSQLUtil::ExecuteSQLQueryWithOptimizer(
      optimizer, query2, result, tuple_descriptor, rows_affected, error_message);
//  TestingSQLUtil::ExecuteSQLQuery(
//      "select count(id), salary from xxx group by salary having salary>1000;",
//      result, tuple_descriptor, rows_affected, error_message);

  // Check the return value
  EXPECT_EQ(0, rows_affected);
  EXPECT_EQ("1", TestingSQLUtil::GetResultValueAsString(result, 0));
  EXPECT_EQ("2", TestingSQLUtil::GetResultValueAsString(result, 2));
  EXPECT_EQ("2", TestingSQLUtil::GetResultValueAsString(result, 4));

  // test: GROUP BY + ORDER BY
  std::string query3("select count(id), salary from xxx group by salary order by salary;");
  LOG_DEBUG("Running Query %s", query3.c_str());
  TestingSQLUtil::ExecuteSQLQueryWithOptimizer(
      optimizer, query3, result, tuple_descriptor, rows_affected, error_message);
//  TestingSQLUtil::ExecuteSQLQuery(
//      "select count(id), salary from xxx group by salary order by salary;",
//      result, tuple_descriptor, rows_affected, error_message);

  // Check the return value
  EXPECT_EQ(0, rows_affected);
  EXPECT_EQ("1", TestingSQLUtil::GetResultValueAsString(result, 0));
  EXPECT_EQ("2", TestingSQLUtil::GetResultValueAsString(result, 2));
  EXPECT_EQ("2", TestingSQLUtil::GetResultValueAsString(result, 4));
  EXPECT_EQ("1", TestingSQLUtil::GetResultValueAsString(result, 6));
  EXPECT_EQ("1000", TestingSQLUtil::GetResultValueAsString(result, 1));
  EXPECT_EQ("2000", TestingSQLUtil::GetResultValueAsString(result, 3));
  EXPECT_EQ("3000", TestingSQLUtil::GetResultValueAsString(result, 5));
  EXPECT_EQ("4000", TestingSQLUtil::GetResultValueAsString(result, 7));

  // free the database just created
  catalog::Catalog::GetInstance()->DropDatabaseWithName(DEFAULT_DB_NAME, txn);
  txn_manager.CommitTransaction(txn);
}

}  // namespace test
}  // namespace peloton
<|endoftext|>


<commit_before>#include "PWSfile.h"

#include <io.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>

bool PWSfile::FileExists(const CMyString &filename)
{
  struct _stat statbuf;
  int status;

  status = ::_tstat(filename, &statbuf);
  return (status == 0);
}

PWSfile::PWSfile(const CMyString &filename, const CMyString &passkey)
  : m_filename(filename), m_passkey(passkey), m_curversion(UNKNOWN_VERSION), m_fd(-1)
{
}

PWSfile::~PWSfile()
{
  CloseFile(); // idempotent
}

static const CMyString V2ItemName(" !!!Version 2 File Format!!! "
				  "Please upgrade to PasswordSafe 2.0"
				  " or later");

int PWSfile::WriteV2Header()
{
  CItemData header;
  // Fill out with V2-specific info
  header.SetName(V2ItemName);
  // need to fallback to V17, since the record
  // won't be readable otherwise!
  VERSION sv = m_curversion;
  m_curversion = V17;
  int status = WriteRecord(header);
  // restore after writing V17-format header
  m_curversion = sv;
  return status;
}

int PWSfile::ReadV2Header()
{
  CItemData header;
  // need to fallback to V17, since the header
  // is always written in this format
  VERSION sv = m_curversion;
  m_curversion = V17;
  int status = ReadRecord(header);
  // restore after reading V17-format header
  m_curversion = sv;
  if (status == SUCCESS) {
    const CMyString name = header.GetName();
    status = (name == V2ItemName) ? SUCCESS : WRONG_VERSION;
  }
  return status;
}

int PWSfile::OpenWriteFile(VERSION v)
{
  if (v != V17 && v != V20)
    return UNSUPPORTED_VERSION;

  m_fd = _open((LPCTSTR)m_filename,
	       _O_BINARY|_O_WRONLY|_O_SEQUENTIAL|_O_TRUNC|_O_CREAT,
	       _S_IREAD | _S_IWRITE);

  if (m_fd == -1)
    return CANT_OPEN_FILE;

  m_curversion = v;

  // Following used to verify passkey against file's passkey
  unsigned char randstuff[StuffSize];
  unsigned char randhash[20];   // HashSize
  int x;

  for (x=0; x<8; x++)
    randstuff[x] = newrand();
  randstuff[8] = randstuff[9] = '\0';
  GenRandhash(m_passkey, randstuff, randhash);

  _write(m_fd, randstuff, 8);
  _write(m_fd, randhash, 20);

  for (x=0; x<SaltLength; x++)
    m_salt[x] = newrand();

  _write(m_fd, m_salt, SaltLength);

  for (x=0; x<8; x++)
    m_ipthing[x] = newrand();
  _write(m_fd, m_ipthing, 8);

  if (v == V20) {
    int status = WriteV2Header();
    if (status != SUCCESS)
      return status;
  }

  return SUCCESS;
}

int PWSfile::OpenReadFile(VERSION v)
{
  if (v != V17 && v != V20)
    return UNSUPPORTED_VERSION;

  m_fd = _open((LPCTSTR) m_filename,
	       _O_BINARY |_O_RDONLY | _O_SEQUENTIAL,
	       S_IREAD | _S_IWRITE);

  if (m_fd == -1)
    return CANT_OPEN_FILE;
  m_curversion = v;

  int status = CheckPassword();

  if (status != SUCCESS) {
    CloseFile();
    return status;
  }

   _read(m_fd, m_salt, SaltLength);
   _read(m_fd, m_ipthing, 8);

   if (v == V20)
     status = ReadV2Header();

  return status;
}

void PWSfile::CloseFile()
{
  if (m_fd != -1) {
    _close(m_fd);
    m_fd = -1;
  }
}

PWSfile::VERSION PWSfile::GetFileVersion()
{
  VERSION v;
  int status = OpenReadFile(V20);
  CloseFile();
  switch (status) {
  case SUCCESS: v = V20; break;
  case WRONG_VERSION: v = V17; break;
  default: v = UNKNOWN_VERSION; break;
  }
  return v;
}

int PWSfile::CheckPassword()
{
  // if file was opened, leave it open,
  // else open it for check, close when done
  const bool was_open = (m_fd != -1);

  if (!was_open) {
    m_fd = _open((LPCTSTR) m_filename,
		 _O_BINARY |_O_RDONLY | _O_SEQUENTIAL,
		 S_IREAD | _S_IWRITE);

    if (m_fd == -1)
      return CANT_OPEN_FILE;
  }

  unsigned char randstuff[StuffSize];
  unsigned char randhash[20];   // HashSize

   _read(m_fd, randstuff, 8);
   randstuff[8] = randstuff[9] = '\0'; // Gross fugbix
   _read(m_fd, randhash, 20);

  if (!was_open)
    CloseFile();

  unsigned char temphash[20]; // HashSize
  GenRandhash(m_passkey, randstuff, temphash);

  if (0 != ::memcmp((char*)randhash,
		    (char*)temphash,
		    20)) {// HashSize
    return WRONG_PASSWORD;
  } else {
    return SUCCESS;
  }
}

int PWSfile::WriteCBC(unsigned char type, const CString &data)
{
  // We do a double cast because the LPCSTR cast operator is overridden by the CString class
  // to access the pointer we need,
  // but we in fact need it as an unsigned char. Grrrr.
  LPCSTR passstr = LPCSTR(m_passkey);
  LPCSTR datastr = LPCSTR(data);

  return _writecbc(m_fd, (const unsigned char *)datastr, data.GetLength(), type,
		   (const unsigned char *)passstr, m_passkey.GetLength(),
		   m_salt, SaltLength, m_ipthing);
}

int PWSfile::WriteRecord(const CItemData &item)
{
  ASSERT(m_fd != -1);
  ASSERT(m_curversion != UNKNOWN_VERSION);

  switch (m_curversion) {
  case V17: {
    // 1.x programs totally ignore the type byte, hence safe to write it
    // (no need for two WriteCBC functions)
    WriteCBC(CItemData::NAME, item.GetName());
    WriteCBC(CItemData::PASSWORD, item.GetPassword());
    WriteCBC(CItemData::NOTES, item.GetNotes());
    return SUCCESS;
  }
  break;
  case V20: {
    WriteCBC(CItemData::TITLE, item.GetTitle());
    WriteCBC(CItemData::USER, item.GetUser());
    WriteCBC(CItemData::PASSWORD, item.GetPassword());
    WriteCBC(CItemData::NOTES, item.GetNotes());
    WriteCBC(CItemData::END, _T(""));
    return SUCCESS;
  }
  default:
    ASSERT(0);
    return UNSUPPORTED_VERSION;
  }
  return SUCCESS;
}

int
PWSfile::ReadCBC(unsigned char &type, CMyString &data)
{
  // We do a double cast because the LPCSTR cast operator is overridden by the CString class
  // to access the pointer we need,
  // but we in fact need it as an unsigned char. Grrrr.
  LPCSTR passstr = LPCSTR(m_passkey);

  unsigned char *buffer = NULL;
  unsigned int buffer_len = 0;
  int retval;

  retval = _readcbc(m_fd, buffer, buffer_len, type,
		   (const unsigned char *)passstr, m_passkey.GetLength(),
		   m_salt, SaltLength, m_ipthing);
  if (buffer_len > 0) {
    CMyString str(LPCSTR(buffer), buffer_len);
    data = str;
    trashMemory(buffer, buffer_len);
    delete[] buffer;
  } else {
    data = _T("");
    // no need to delete[] buffer, since _readcbc will not allocate if
    // buffer_len is zero
  }
  return retval;
}

int PWSfile::ReadRecord(CItemData &item)
{
  ASSERT(m_fd != -1);
  ASSERT(m_curversion != UNKNOWN_VERSION);

  CMyString tempdata;
  int numread = 0;
  unsigned char type;

  switch (m_curversion) {
  case V17: {
    // type is meaningless, but why write two versions of ReadCBC?
    numread += ReadCBC(type, tempdata);
    item.SetName(tempdata);
    numread += ReadCBC(type, tempdata);
    item.SetPassword(tempdata);
    numread += ReadCBC(type, tempdata);
    item.SetNotes(tempdata);

    return (numread > 0) ? SUCCESS : END_OF_FILE;
  }
  case V20: {
    int emergencyExit = 255; // to avoid endless loop.
    int fieldLen; // zero means end of file reached
    bool endFound = false; // set to true when record end detected - happy end
    do {
      fieldLen = ReadCBC(type, tempdata);
      if (fieldLen > 0) {
	numread += fieldLen;
	switch (type) {
	case CItemData::TITLE:
	  item.SetTitle(tempdata); break;
	case CItemData::USER:
	  item.SetUser(tempdata); break;
	case CItemData::PASSWORD:
	  item.SetPassword(tempdata); break;
	case CItemData::NOTES:
	  item.SetNotes(tempdata); break;
	case CItemData::END:
	  endFound = true; break;
	  // just silently ignore fields we don't support.
	  // this is forward compatability...
	case CItemData::GUID:
	case CItemData::GROUP:
	case CItemData::CTIME:
	case CItemData::MTIME:
	case CItemData::ATIME:
	case CItemData::LTIME:
	case CItemData::POLICY:
	default:
	  // XXX Set a flag here so user can be warned that
	  // XXX we read a file format we don't fully support
	  break;
	} // switch
      } // if (fieldLen > 0)
    } while (!endFound && fieldLen > 0 && --emergencyExit > 0);
    return (numread > 0) ? SUCCESS : END_OF_FILE;
  }
  default:
    ASSERT(0);
    return UNSUPPORTED_VERSION;
  }
}

<commit_msg>Testing complete. Added exact version string in v2 header password field.<commit_after>#include "PWSfile.h"

#include <io.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>

bool PWSfile::FileExists(const CMyString &filename)
{
  struct _stat statbuf;
  int status;

  status = ::_tstat(filename, &statbuf);
  return (status == 0);
}

PWSfile::PWSfile(const CMyString &filename, const CMyString &passkey)
  : m_filename(filename), m_passkey(passkey), m_curversion(UNKNOWN_VERSION), m_fd(-1)
{
}

PWSfile::~PWSfile()
{
  CloseFile(); // idempotent
}

// Used to warn pre-2.0 users, and to identify the database as 2.x:
static const CMyString V2ItemName(" !!!Version 2 File Format!!! "
				  "Please upgrade to PasswordSafe 2.0"
				  " or later");
// Used to specify the exact version
static const CMyString VersionString("pre-2.0");

int PWSfile::WriteV2Header()
{
  CItemData header;
  // Fill out with V2-specific info
  header.SetName(V2ItemName);
  header.SetPassword(VersionString);
  // need to fallback to V17, since the record
  // won't be readable otherwise!
  VERSION sv = m_curversion;
  m_curversion = V17;
  int status = WriteRecord(header);
  // restore after writing V17-format header
  m_curversion = sv;
  return status;
}

int PWSfile::ReadV2Header()
{
  CItemData header;
  // need to fallback to V17, since the header
  // is always written in this format
  VERSION sv = m_curversion;
  m_curversion = V17;
  int status = ReadRecord(header);
  // restore after reading V17-format header
  m_curversion = sv;
  if (status == SUCCESS) {
    const CMyString name = header.GetName();
    // XXX Need to compare header.GetPassword() against VersionString
    // XXX as well, for inter-2.x version checks
    status = (name == V2ItemName) ? SUCCESS : WRONG_VERSION;
  }
  return status;
}

int PWSfile::OpenWriteFile(VERSION v)
{
  if (v != V17 && v != V20)
    return UNSUPPORTED_VERSION;

  m_fd = _open((LPCTSTR)m_filename,
	       _O_BINARY|_O_WRONLY|_O_SEQUENTIAL|_O_TRUNC|_O_CREAT,
	       _S_IREAD | _S_IWRITE);

  if (m_fd == -1)
    return CANT_OPEN_FILE;

  m_curversion = v;

  // Following used to verify passkey against file's passkey
  unsigned char randstuff[StuffSize];
  unsigned char randhash[20];   // HashSize
  int x;

  for (x=0; x<8; x++)
    randstuff[x] = newrand();
  randstuff[8] = randstuff[9] = '\0';
  GenRandhash(m_passkey, randstuff, randhash);

  _write(m_fd, randstuff, 8);
  _write(m_fd, randhash, 20);

  for (x=0; x<SaltLength; x++)
    m_salt[x] = newrand();

  _write(m_fd, m_salt, SaltLength);

  for (x=0; x<8; x++)
    m_ipthing[x] = newrand();
  _write(m_fd, m_ipthing, 8);

  if (v == V20) {
    int status = WriteV2Header();
    if (status != SUCCESS)
      return status;
  }

  return SUCCESS;
}

int PWSfile::OpenReadFile(VERSION v)
{
  if (v != V17 && v != V20)
    return UNSUPPORTED_VERSION;

  m_fd = _open((LPCTSTR) m_filename,
	       _O_BINARY |_O_RDONLY | _O_SEQUENTIAL,
	       S_IREAD | _S_IWRITE);

  if (m_fd == -1)
    return CANT_OPEN_FILE;
  m_curversion = v;

  int status = CheckPassword();

  if (status != SUCCESS) {
    CloseFile();
    return status;
  }

   _read(m_fd, m_salt, SaltLength);
   _read(m_fd, m_ipthing, 8);

   if (v == V20)
     status = ReadV2Header();

  return status;
}

void PWSfile::CloseFile()
{
  if (m_fd != -1) {
    _close(m_fd);
    m_fd = -1;
  }
}

PWSfile::VERSION PWSfile::GetFileVersion()
{
  VERSION v;
  int status = OpenReadFile(V20);
  CloseFile();
  switch (status) {
  case SUCCESS: v = V20; break;
  case WRONG_VERSION: v = V17; break;
  default: v = UNKNOWN_VERSION; break;
  }
  return v;
}

int PWSfile::CheckPassword()
{
  // if file was opened, leave it open,
  // else open it for check, close when done
  const bool was_open = (m_fd != -1);

  if (!was_open) {
    m_fd = _open((LPCTSTR) m_filename,
		 _O_BINARY |_O_RDONLY | _O_SEQUENTIAL,
		 S_IREAD | _S_IWRITE);

    if (m_fd == -1)
      return CANT_OPEN_FILE;
  }

  unsigned char randstuff[StuffSize];
  unsigned char randhash[20];   // HashSize

   _read(m_fd, randstuff, 8);
   randstuff[8] = randstuff[9] = '\0'; // Gross fugbix
   _read(m_fd, randhash, 20);

  if (!was_open)
    CloseFile();

  unsigned char temphash[20]; // HashSize
  GenRandhash(m_passkey, randstuff, temphash);

  if (0 != ::memcmp((char*)randhash,
		    (char*)temphash,
		    20)) {// HashSize
    return WRONG_PASSWORD;
  } else {
    return SUCCESS;
  }
}

int PWSfile::WriteCBC(unsigned char type, const CString &data)
{
  // We do a double cast because the LPCSTR cast operator is overridden by the CString class
  // to access the pointer we need,
  // but we in fact need it as an unsigned char. Grrrr.
  LPCSTR passstr = LPCSTR(m_passkey);
  LPCSTR datastr = LPCSTR(data);

  return _writecbc(m_fd, (const unsigned char *)datastr, data.GetLength(), type,
		   (const unsigned char *)passstr, m_passkey.GetLength(),
		   m_salt, SaltLength, m_ipthing);
}

int PWSfile::WriteRecord(const CItemData &item)
{
  ASSERT(m_fd != -1);
  ASSERT(m_curversion != UNKNOWN_VERSION);

  switch (m_curversion) {
  case V17: {
    // 1.x programs totally ignore the type byte, hence safe to write it
    // (no need for two WriteCBC functions)
    WriteCBC(CItemData::NAME, item.GetName());
    WriteCBC(CItemData::PASSWORD, item.GetPassword());
    WriteCBC(CItemData::NOTES, item.GetNotes());
    return SUCCESS;
  }
  break;
  case V20: {
    WriteCBC(CItemData::TITLE, item.GetTitle());
    WriteCBC(CItemData::USER, item.GetUser());
    WriteCBC(CItemData::PASSWORD, item.GetPassword());
    WriteCBC(CItemData::NOTES, item.GetNotes());
    WriteCBC(CItemData::END, _T(""));
    return SUCCESS;
  }
  default:
    ASSERT(0);
    return UNSUPPORTED_VERSION;
  }
  return SUCCESS;
}

int
PWSfile::ReadCBC(unsigned char &type, CMyString &data)
{
  // We do a double cast because the LPCSTR cast operator is overridden by the CString class
  // to access the pointer we need,
  // but we in fact need it as an unsigned char. Grrrr.
  LPCSTR passstr = LPCSTR(m_passkey);

  unsigned char *buffer = NULL;
  unsigned int buffer_len = 0;
  int retval;

  retval = _readcbc(m_fd, buffer, buffer_len, type,
		   (const unsigned char *)passstr, m_passkey.GetLength(),
		   m_salt, SaltLength, m_ipthing);
  if (buffer_len > 0) {
    CMyString str(LPCSTR(buffer), buffer_len);
    data = str;
    trashMemory(buffer, buffer_len);
    delete[] buffer;
  } else {
    data = _T("");
    // no need to delete[] buffer, since _readcbc will not allocate if
    // buffer_len is zero
  }
  return retval;
}

int PWSfile::ReadRecord(CItemData &item)
{
  ASSERT(m_fd != -1);
  ASSERT(m_curversion != UNKNOWN_VERSION);

  CMyString tempdata;
  int numread = 0;
  unsigned char type;

  switch (m_curversion) {
  case V17: {
    // type is meaningless, but why write two versions of ReadCBC?
    numread += ReadCBC(type, tempdata);
    item.SetName(tempdata);
    numread += ReadCBC(type, tempdata);
    item.SetPassword(tempdata);
    numread += ReadCBC(type, tempdata);
    item.SetNotes(tempdata);

    return (numread > 0) ? SUCCESS : END_OF_FILE;
  }
  case V20: {
    int emergencyExit = 255; // to avoid endless loop.
    int fieldLen; // zero means end of file reached
    bool endFound = false; // set to true when record end detected - happy end
    do {
      fieldLen = ReadCBC(type, tempdata);
      if (fieldLen > 0) {
	numread += fieldLen;
	switch (type) {
	case CItemData::TITLE:
	  item.SetTitle(tempdata); break;
	case CItemData::USER:
	  item.SetUser(tempdata); break;
	case CItemData::PASSWORD:
	  item.SetPassword(tempdata); break;
	case CItemData::NOTES:
	  item.SetNotes(tempdata); break;
	case CItemData::END:
	  endFound = true; break;
	  // just silently ignore fields we don't support.
	  // this is forward compatability...
	case CItemData::GUID:
	case CItemData::GROUP:
	case CItemData::CTIME:
	case CItemData::MTIME:
	case CItemData::ATIME:
	case CItemData::LTIME:
	case CItemData::POLICY:
	default:
	  // XXX Set a flag here so user can be warned that
	  // XXX we read a file format we don't fully support
	  break;
	} // switch
      } // if (fieldLen > 0)
    } while (!endFound && fieldLen > 0 && --emergencyExit > 0);
    return (numread > 0) ? SUCCESS : END_OF_FILE;
  }
  default:
    ASSERT(0);
    return UNSUPPORTED_VERSION;
  }
}

<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2014-2016 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include <deque>

#include "catch.hpp"

#define DLL_SVM_SUPPORT

#include "dll/rbm/conv_rbm.hpp"
#include "dll/dbn.hpp"
#include "dll/pooling/mp_layer.hpp"
#include "dll/pooling/avgp_layer.hpp"

#include "mnist/mnist_reader.hpp"
#include "mnist/mnist_utils.hpp"

TEST_CASE("conv_dbn/mnist_9", "max_pooling") {
    typedef dll::dbn_desc<
        dll::dbn_layers<
            dll::conv_rbm_desc<1, 28, 28, 40, 15, 17, dll::momentum, dll::batch_size<25>>::layer_t,
            dll::conv_rbm_desc<40, 14, 12, 40, 7, 3, dll::momentum, dll::batch_size<25>>::layer_t,
            dll::mp_layer_3d_desc<40, 8, 10, 2, 2, 1>::layer_t>>::dbn_t dbn_t;

    auto dataset = mnist::read_dataset_direct<std::vector, etl::fast_dyn_matrix<double, 1, 28, 28>>(200);

    REQUIRE(!dataset.training_images.empty());

    mnist::binarize_dataset(dataset);

    auto dbn = std::make_unique<dbn_t>();

    dbn->pretrain(dataset.training_images, 20);

    auto output = dbn->activation_probabilities(dataset.training_images.front());

    REQUIRE(dbn->output_size() == 800);
    REQUIRE(output.size() == 800);

    auto result = dbn->svm_train(dataset.training_images, dataset.training_labels);

    REQUIRE(result);

    auto test_error = dll::test_set(dbn, dataset.training_images, dataset.training_labels, dll::svm_predictor());
    std::cout << "test_error:" << test_error << std::endl;
    REQUIRE(test_error < 0.1);
}

TEST_CASE("conv_dbn/mnist_10", "max_pooling") {
    typedef dll::dbn_desc<
        dll::dbn_layers<
            dll::conv_rbm_desc<1, 28, 28, 40, 9, 8, dll::momentum, dll::batch_size<25>>::layer_t,
            dll::mp_layer_3d_desc<40, 20, 21, 2, 2, 3>::layer_t,
            dll::conv_rbm_desc<20, 10, 7, 40, 3, 3, dll::momentum, dll::batch_size<25>>::layer_t,
            dll::mp_layer_3d_desc<40, 8, 5, 2, 1, 1>::layer_t>>::dbn_t dbn_t;

    auto dataset = mnist::read_dataset_direct<std::vector, etl::fast_dyn_matrix<double, 1, 28, 28>>(200);

    REQUIRE(!dataset.training_images.empty());

    mnist::binarize_dataset(dataset);

    auto dbn = std::make_unique<dbn_t>();

    dbn->pretrain(dataset.training_images, 20);

    REQUIRE(dbn->output_size() == 800);

    auto output = dbn->activation_probabilities(dataset.training_images.front());

    REQUIRE(output.size() == 800);

    auto result = dbn->svm_train(dataset.training_images, dataset.training_labels);

    REQUIRE(result);

    auto test_error = dll::test_set(dbn, dataset.training_images, dataset.training_labels, dll::svm_predictor());
    std::cout << "test_error:" << test_error << std::endl;
    REQUIRE(test_error < 1.0);
}

TEST_CASE("conv_dbn/mnist_11", "avg_pooling") {
    typedef dll::dbn_desc<
        dll::dbn_layers<
            dll::conv_rbm_desc<1, 28, 28, 40, 15, 17, dll::momentum, dll::batch_size<25>>::layer_t,
            dll::conv_rbm_desc<40, 14, 12, 40, 7, 3, dll::momentum, dll::batch_size<25>>::layer_t,
            dll::avgp_layer_3d_desc<40, 8, 10, 2, 2, 1>::layer_t>>::dbn_t dbn_t;

    auto dataset = mnist::read_dataset_direct<std::vector, etl::fast_dyn_matrix<double, 1, 28, 28>>(200);

    REQUIRE(!dataset.training_images.empty());

    mnist::binarize_dataset(dataset);

    auto dbn = std::make_unique<dbn_t>();

    REQUIRE(dbn->output_size() == 800);

    dbn->pretrain(dataset.training_images, 20);

    auto output = dbn->activation_probabilities(dataset.training_images.front());

    REQUIRE(output.size() == 800);

    auto result = dbn->svm_train(dataset.training_images, dataset.training_labels);

    REQUIRE(result);

    auto test_error = dll::test_set(dbn, dataset.training_images, dataset.training_labels, dll::svm_predictor());
    std::cout << "test_error:" << test_error << std::endl;
    REQUIRE(test_error < 0.1);
}

TEST_CASE("conv_dbn/mnist_12", "avgp_pooling") {
    typedef dll::dbn_desc<
        dll::dbn_layers<
            dll::conv_rbm_desc<1, 28, 28, 40, 9, 8, dll::momentum, dll::batch_size<25>>::layer_t,
            dll::avgp_layer_3d_desc<40, 20, 21, 2, 2, 3>::layer_t,
            dll::conv_rbm_desc<20, 10, 7, 40, 3, 3, dll::momentum, dll::batch_size<25>>::layer_t,
            dll::avgp_layer_3d_desc<40, 8, 5, 2, 1, 1>::layer_t>>::dbn_t dbn_t;

    auto dataset = mnist::read_dataset_direct<std::vector, etl::fast_dyn_matrix<double, 1, 28, 28>>(200);

    REQUIRE(!dataset.training_images.empty());

    mnist::binarize_dataset(dataset);

    auto dbn = std::make_unique<dbn_t>();

    REQUIRE(dbn->output_size() == 800);

    dbn->pretrain(dataset.training_images, 20);

    auto output = dbn->activation_probabilities(dataset.training_images.front());

    REQUIRE(output.size() == 800);

    auto result = dbn->svm_train(dataset.training_images, dataset.training_labels);

    REQUIRE(result);

    auto test_error = dll::test_set(dbn, dataset.training_images, dataset.training_labels, dll::svm_predictor());
    std::cout << "test_error:" << test_error << std::endl;
    REQUIRE(test_error < 1.0);
}

TEST_CASE("conv_dbn/mnist_13", "nop_layers") {
    typedef dll::dbn_desc<
        dll::dbn_layers<
            dll::conv_rbm_desc<1, 28, 28, 40, 15, 17, dll::momentum, dll::batch_size<25>>::layer_t,
            dll::conv_rbm_desc<40, 14, 12, 40, 7, 3, dll::momentum, dll::batch_size<25>>::layer_t,
            dll::mp_layer_3d_desc<40, 8, 10, 1, 1, 1>::layer_t,
            dll::avgp_layer_3d_desc<40, 8, 10, 1, 1, 1>::layer_t
        >>::dbn_t dbn_t;

    auto dataset = mnist::read_dataset_direct<std::vector, etl::fast_dyn_matrix<double, 1, 28, 28>>(200);

    REQUIRE(!dataset.training_images.empty());

    mnist::binarize_dataset(dataset);

    auto dbn = std::make_unique<dbn_t>();

    REQUIRE(dbn->output_size() == 3200);

    dbn->pretrain(dataset.training_images, 2);

    auto output = dbn->activation_probabilities(dataset.training_images.front());

    REQUIRE(output.size() == 3200);

    auto result = dbn->svm_train(dataset.training_images, dataset.training_labels);

    REQUIRE(result);

    auto test_error = dll::test_set(dbn, dataset.training_images, dataset.training_labels, dll::svm_predictor());
    std::cout << "test_error:" << test_error << std::endl;
    REQUIRE(test_error < 0.9);
}
<commit_msg>Fix the default type<commit_after>//=======================================================================
// Copyright (c) 2014-2016 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include <deque>

#include "catch.hpp"

#define DLL_SVM_SUPPORT

#include "dll/rbm/conv_rbm.hpp"
#include "dll/dbn.hpp"
#include "dll/pooling/mp_layer.hpp"
#include "dll/pooling/avgp_layer.hpp"

#include "mnist/mnist_reader.hpp"
#include "mnist/mnist_utils.hpp"

TEST_CASE("conv_dbn/mnist_9", "max_pooling") {
    typedef dll::dbn_desc<
        dll::dbn_layers<
            dll::conv_rbm_desc<1, 28, 28, 40, 15, 17, dll::momentum, dll::batch_size<25>>::layer_t,
            dll::conv_rbm_desc<40, 14, 12, 40, 7, 3, dll::momentum, dll::batch_size<25>>::layer_t,
            dll::mp_layer_3d_desc<40, 8, 10, 2, 2, 1>::layer_t>>::dbn_t dbn_t;

    auto dataset = mnist::read_dataset_direct<std::vector, etl::fast_dyn_matrix<float, 1, 28, 28>>(200);

    REQUIRE(!dataset.training_images.empty());

    mnist::binarize_dataset(dataset);

    auto dbn = std::make_unique<dbn_t>();

    dbn->pretrain(dataset.training_images, 20);

    auto output = dbn->activation_probabilities(dataset.training_images.front());

    REQUIRE(dbn->output_size() == 800);
    REQUIRE(output.size() == 800);

    auto result = dbn->svm_train(dataset.training_images, dataset.training_labels);

    REQUIRE(result);

    auto test_error = dll::test_set(dbn, dataset.training_images, dataset.training_labels, dll::svm_predictor());
    std::cout << "test_error:" << test_error << std::endl;
    REQUIRE(test_error < 0.1);
}

TEST_CASE("conv_dbn/mnist_10", "max_pooling") {
    typedef dll::dbn_desc<
        dll::dbn_layers<
            dll::conv_rbm_desc<1, 28, 28, 40, 9, 8, dll::momentum, dll::batch_size<25>>::layer_t,
            dll::mp_layer_3d_desc<40, 20, 21, 2, 2, 3>::layer_t,
            dll::conv_rbm_desc<20, 10, 7, 40, 3, 3, dll::momentum, dll::batch_size<25>>::layer_t,
            dll::mp_layer_3d_desc<40, 8, 5, 2, 1, 1>::layer_t>>::dbn_t dbn_t;

    auto dataset = mnist::read_dataset_direct<std::vector, etl::fast_dyn_matrix<float, 1, 28, 28>>(200);

    REQUIRE(!dataset.training_images.empty());

    mnist::binarize_dataset(dataset);

    auto dbn = std::make_unique<dbn_t>();

    dbn->pretrain(dataset.training_images, 20);

    REQUIRE(dbn->output_size() == 800);

    auto output = dbn->activation_probabilities(dataset.training_images.front());

    REQUIRE(output.size() == 800);

    auto result = dbn->svm_train(dataset.training_images, dataset.training_labels);

    REQUIRE(result);

    auto test_error = dll::test_set(dbn, dataset.training_images, dataset.training_labels, dll::svm_predictor());
    std::cout << "test_error:" << test_error << std::endl;
    REQUIRE(test_error < 1.0);
}

TEST_CASE("conv_dbn/mnist_11", "avg_pooling") {
    typedef dll::dbn_desc<
        dll::dbn_layers<
            dll::conv_rbm_desc<1, 28, 28, 40, 15, 17, dll::momentum, dll::batch_size<25>>::layer_t,
            dll::conv_rbm_desc<40, 14, 12, 40, 7, 3, dll::momentum, dll::batch_size<25>>::layer_t,
            dll::avgp_layer_3d_desc<40, 8, 10, 2, 2, 1>::layer_t>>::dbn_t dbn_t;

    auto dataset = mnist::read_dataset_direct<std::vector, etl::fast_dyn_matrix<float, 1, 28, 28>>(200);

    REQUIRE(!dataset.training_images.empty());

    mnist::binarize_dataset(dataset);

    auto dbn = std::make_unique<dbn_t>();

    REQUIRE(dbn->output_size() == 800);

    dbn->pretrain(dataset.training_images, 20);

    auto output = dbn->activation_probabilities(dataset.training_images.front());

    REQUIRE(output.size() == 800);

    auto result = dbn->svm_train(dataset.training_images, dataset.training_labels);

    REQUIRE(result);

    auto test_error = dll::test_set(dbn, dataset.training_images, dataset.training_labels, dll::svm_predictor());
    std::cout << "test_error:" << test_error << std::endl;
    REQUIRE(test_error < 0.1);
}

TEST_CASE("conv_dbn/mnist_12", "avgp_pooling") {
    typedef dll::dbn_desc<
        dll::dbn_layers<
            dll::conv_rbm_desc<1, 28, 28, 40, 9, 8, dll::momentum, dll::batch_size<25>>::layer_t,
            dll::avgp_layer_3d_desc<40, 20, 21, 2, 2, 3>::layer_t,
            dll::conv_rbm_desc<20, 10, 7, 40, 3, 3, dll::momentum, dll::batch_size<25>>::layer_t,
            dll::avgp_layer_3d_desc<40, 8, 5, 2, 1, 1>::layer_t>>::dbn_t dbn_t;

    auto dataset = mnist::read_dataset_direct<std::vector, etl::fast_dyn_matrix<float, 1, 28, 28>>(200);

    REQUIRE(!dataset.training_images.empty());

    mnist::binarize_dataset(dataset);

    auto dbn = std::make_unique<dbn_t>();

    REQUIRE(dbn->output_size() == 800);

    dbn->pretrain(dataset.training_images, 20);

    auto output = dbn->activation_probabilities(dataset.training_images.front());

    REQUIRE(output.size() == 800);

    auto result = dbn->svm_train(dataset.training_images, dataset.training_labels);

    REQUIRE(result);

    auto test_error = dll::test_set(dbn, dataset.training_images, dataset.training_labels, dll::svm_predictor());
    std::cout << "test_error:" << test_error << std::endl;
    REQUIRE(test_error < 1.0);
}

TEST_CASE("conv_dbn/mnist_13", "nop_layers") {
    typedef dll::dbn_desc<
        dll::dbn_layers<
            dll::conv_rbm_desc<1, 28, 28, 40, 15, 17, dll::momentum, dll::batch_size<25>>::layer_t,
            dll::conv_rbm_desc<40, 14, 12, 40, 7, 3, dll::momentum, dll::batch_size<25>>::layer_t,
            dll::mp_layer_3d_desc<40, 8, 10, 1, 1, 1>::layer_t,
            dll::avgp_layer_3d_desc<40, 8, 10, 1, 1, 1>::layer_t
        >>::dbn_t dbn_t;

    auto dataset = mnist::read_dataset_direct<std::vector, etl::fast_dyn_matrix<float, 1, 28, 28>>(200);

    REQUIRE(!dataset.training_images.empty());

    mnist::binarize_dataset(dataset);

    auto dbn = std::make_unique<dbn_t>();

    REQUIRE(dbn->output_size() == 3200);

    dbn->pretrain(dataset.training_images, 2);

    auto output = dbn->activation_probabilities(dataset.training_images.front());

    REQUIRE(output.size() == 3200);

    auto result = dbn->svm_train(dataset.training_images, dataset.training_labels);

    REQUIRE(result);

    auto test_error = dll::test_set(dbn, dataset.training_images, dataset.training_labels, dll::svm_predictor());
    std::cout << "test_error:" << test_error << std::endl;
    REQUIRE(test_error < 0.9);
}
<|endoftext|>


<commit_before>/*
 *   Copyright (C) 2014 Pelagicore AB
 *   All rights reserved.
 */
#include <glibmm.h>
#include <dbus-c++/dbus.h>
#include <dbus-c++/glib-integration.h>

#include <signal.h>
#include <unistd.h>
#include "CommandLineParser.h"
#include "log.h"
#include "paminterface.h"
#include "pelagicontain.h"
#include "pelagicontaintodbusadapter.h"
#include "dbusmainloop.h"
#include "generators.h" /* used for gen_ct_name */

#include <sys/stat.h>
#include "systemcallinterface.h"

#ifdef ENABLE_PULSEGATEWAY
#include "pulsegateway.h"
#endif

#ifdef ENABLE_NETWORKGATEWAY
#include "networkgateway.h"
#endif

#ifdef ENABLE_DBUSGATEWAY
#include "dbusgateway.h"
#endif

#ifdef ENABLE_DEVICENODEGATEWAY
#include "devicenodegateway.h"
#endif

LOG_DEFINE_APP_IDS("PCON", "Pelagicontain");
LOG_DECLARE_DEFAULT_CONTEXT(Pelagicontain_DefaultLogContext, "PCON", "Main context");

#ifndef CONFIG
    #error Must define CONFIG; path to configuration file (/etc/pelagicontain?)
#endif

/* These has to be global in order to be reachable from the signal handler */
static Pelagicontain *pelagicontain;
static pid_t pcPid;
static std::string containerDir;

/**
 * Remove the dirs created by main when we cleanup
 */
void removeDirs()
{
    std::string gatewayDir = containerDir + "/gateways";
    if (rmdir(gatewayDir.c_str()) == -1) {
        log_error("Cannot delete dir %s, %s",
                  gatewayDir.c_str(),
                  strerror(errno));
    }

    if (rmdir(containerDir.c_str()) == -1) {
        log_error("Cannot delete dir %s, %s",
                  containerDir.c_str(),
                  strerror(errno));
    }
}

void signalHandler(int signum)
{
    log_debug() << "caught signal " << signum;
    if (!pcPid) {
        if (pelagicontain) {
            // pelagicontain might not have been initialized (preloaded), so we can't just
            // run shutdownContainer. But in the case it is initialized we DO want to run
            // it. Unfortunately, there is currently no way to check that.
            // pelagicontain->shutdownContainer();
            delete pelagicontain;
            removeDirs();
        }
        exit(signum);
    } else {
        // But if pcPid is set, then it is definately initialized
        // This will shutdown pelagicontain and make it exit the main loop
        // back to main() which will take care of the rest of the cleanup
        pelagicontain->shutdown();
    }
}

int main(int argc, char **argv)
{
    // Register signalHandler with signals
    signal(SIGINT, signalHandler);
    signal(SIGTERM, signalHandler);

    const char *summary = "Pelagicore container utility. "
                          "Requires an absolute path to the container root, "
                          "the command to run inside the container and "
                          "an alphanumerical cookie string as first, second and"
                          "third argument respectively";
    const char *paramsDescription = "[container root directory (abs path)] "
                                    "[command] [cookie]";

    pelagicore::CommandLineParser commandLineParser(summary,
                                                    paramsDescription,
                                                    PACKAGE_VERSION,
                                                    "");

    std::string containerRoot;
    std::string containedCommand;
    std::string cookie;
    const char* configFilePath = CONFIG;
    commandLineParser.addOption(configFilePath,
                                "with-config-file",
                                'c',
                                "Config file");

    if (commandLineParser.parse(argc, argv)) {
        return -1;
    }

    if (argc < 4) {
        log_error("Invalid arguments");
        commandLineParser.printHelp();
        return -1;
    } else {
        containerRoot = std::string(argv[1]);
        containedCommand = std::string(argv[2]);
        cookie = std::string(argv[3]);
    }

    if (containerRoot.c_str()[0] != '/') {
        log_error("Path to container root must be absolute");
        commandLineParser.printHelp();
        return -1;
    }

    std::string containerName = Generator::gen_ct_name();
    std::string containerConfig(configFilePath);

    // Create gateway directory for container in containerRoot/gateways.
    // This dir will contain various sockets etc acting as gateways
    // in/out of the container.
    containerDir = containerRoot + "/" + containerName;
    std::string gatewayDir = containerDir + "/gateways";
    if (mkdir(containerDir.c_str(), S_IRWXU) == -1) {
        log_error("Could not create container directory %s, %s.",
                  containerDir.c_str(),
                  strerror(errno));
        return -1;
    }
    if (mkdir(gatewayDir.c_str(), S_IRWXU) == -1) {
        log_error("Could not create gateway directory %s, %s.",
                  gatewayDir.c_str(),
                  strerror(errno));
        return -1;
    }

    // Make sure path ends in '/' since it might not always be checked
    if (containerRoot.back() != '/') {
        containerRoot += "/";
    }

    Container container(containerName,
                        containerConfig,
                        containerRoot,
                        containedCommand);

    if (!container.initialize()) {
        log_error() << "Could not setup container for preloading";
        removeDirs();
        return -1;
    }

    Glib::RefPtr<Glib::MainLoop> ml = Glib::MainLoop::create();

    { // Create a new scope so that we can do a clean up after dtors
        DBus::Glib::BusDispatcher dispatcher;
        DBus::default_dispatcher = &dispatcher;
        dispatcher.attach(ml->get_context()->gobj());
        DBus::Connection bus = DBus::Connection::SessionBus();

        /* Pelagicontain needs an interface to the mainloop so it can
         * exit it when we are to clean up and shut down
         */
        DBusMainloop mainloopInterface(ml);

        /* The request_name call does not return anything but raises an
         * exception if the name cannot be requested.
         */
        std::string name = "com.pelagicore.Pelagicontain" + cookie;
        bus.request_name(name.c_str());

        /* If we can't communicate with PAM then there is nothing we can
         * do really, better to just exit.
         */
        bool pamRunning = bus.has_name("com.pelagicore.PAM");
        if (!pamRunning) {
            log_error() << "PAM not running, exiting";
            removeDirs();
            exit(-1);
        }

        PAMInterface pamInterface(bus);
        ControllerInterface controllerInterface(gatewayDir);
        SystemcallInterface systemcallInterface;
        pelagicontain = new Pelagicontain(&pamInterface,
                                          &mainloopInterface,
                                          &controllerInterface,
                                          cookie);

        std::string objectPath = "/com/pelagicore/Pelagicontain";

        PelagicontainToDBusAdapter pcAdapter(bus, objectPath, *pelagicontain);

#ifdef ENABLE_NETWORKGATEWAY
        pelagicontain->addGateway(new NetworkGateway(controllerInterface,
                                                    systemcallInterface));
#endif

#ifdef ENABLE_PULSEGATEWAY
        pelagicontain->addGateway(new PulseGateway(gatewayDir, containerName,
                                                  controllerInterface));
#endif

#ifdef ENABLE_DEVICENODEGATEWAY
        pelagicontain->addGateway(new DeviceNodeGateway(controllerInterface));
#endif

#ifdef ENABLE_DBUSGATEWAY
        pelagicontain->addGateway(new DBusGateway(controllerInterface,
                                                 systemcallInterface,
                                                 DBusGateway::SessionProxy,
                                                 gatewayDir,
                                                 containerName));

        pelagicontain->addGateway(new DBusGateway(controllerInterface,
                                                 systemcallInterface,
                                                 DBusGateway::SystemProxy,
                                                 gatewayDir,
                                                 containerName));
#endif

        pcPid = pelagicontain->preload(&container);

        if (!pcPid) {
            // Fatal failure, only do necessary cleanup
            log_error() << "Could not start container, will shut down";
        } else {
            log_debug() << "Started container with PID " << pcPid;
            // setup IPC between Pelagicontain and Controller
            bool connected = pelagicontain->establishConnection();
            if (connected) {
                ml->run();
                // When we return here Pelagicontain has exited the mainloop
                log_debug("Exited mainloop");
            } else {
                // Fatal failure, only do necessary cleanup
                log_error() << "Got no connection from Controller";
                pelagicontain->shutdownContainer();
            }
        }
    }

    delete pelagicontain;
    removeDirs();

    log_debug() << "Goodbye.";
}
<commit_msg>main.cpp: return instead of exit<commit_after>/*
 *   Copyright (C) 2014 Pelagicore AB
 *   All rights reserved.
 */
#include <glibmm.h>
#include <dbus-c++/dbus.h>
#include <dbus-c++/glib-integration.h>

#include <signal.h>
#include <unistd.h>
#include "CommandLineParser.h"
#include "log.h"
#include "paminterface.h"
#include "pelagicontain.h"
#include "pelagicontaintodbusadapter.h"
#include "dbusmainloop.h"
#include "generators.h" /* used for gen_ct_name */

#include <sys/stat.h>
#include "systemcallinterface.h"

#ifdef ENABLE_PULSEGATEWAY
#include "pulsegateway.h"
#endif

#ifdef ENABLE_NETWORKGATEWAY
#include "networkgateway.h"
#endif

#ifdef ENABLE_DBUSGATEWAY
#include "dbusgateway.h"
#endif

#ifdef ENABLE_DEVICENODEGATEWAY
#include "devicenodegateway.h"
#endif

LOG_DEFINE_APP_IDS("PCON", "Pelagicontain");
LOG_DECLARE_DEFAULT_CONTEXT(Pelagicontain_DefaultLogContext, "PCON", "Main context");

#ifndef CONFIG
    #error Must define CONFIG; path to configuration file (/etc/pelagicontain?)
#endif

/* These has to be global in order to be reachable from the signal handler */
static Pelagicontain *pelagicontain;
static pid_t pcPid;
static std::string containerDir;

/**
 * Remove the dirs created by main when we cleanup
 */
void removeDirs()
{
    std::string gatewayDir = containerDir + "/gateways";
    if (rmdir(gatewayDir.c_str()) == -1) {
        log_error("Cannot delete dir %s, %s",
                  gatewayDir.c_str(),
                  strerror(errno));
    }

    if (rmdir(containerDir.c_str()) == -1) {
        log_error("Cannot delete dir %s, %s",
                  containerDir.c_str(),
                  strerror(errno));
    }
}

void signalHandler(int signum)
{
    log_debug() << "caught signal " << signum;
    if (!pcPid) {
        if (pelagicontain) {
            // pelagicontain might not have been initialized (preloaded), so we can't just
            // run shutdownContainer. But in the case it is initialized we DO want to run
            // it. Unfortunately, there is currently no way to check that.
            // pelagicontain->shutdownContainer();
            delete pelagicontain;
            removeDirs();
        }
        exit(signum);
    } else {
        // But if pcPid is set, then it is definately initialized
        // This will shutdown pelagicontain and make it exit the main loop
        // back to main() which will take care of the rest of the cleanup
        pelagicontain->shutdown();
    }
}

int main(int argc, char **argv)
{
    // Register signalHandler with signals
    signal(SIGINT, signalHandler);
    signal(SIGTERM, signalHandler);

    const char *summary = "Pelagicore container utility. "
                          "Requires an absolute path to the container root, "
                          "the command to run inside the container and "
                          "an alphanumerical cookie string as first, second and"
                          "third argument respectively";
    const char *paramsDescription = "[container root directory (abs path)] "
                                    "[command] [cookie]";

    pelagicore::CommandLineParser commandLineParser(summary,
                                                    paramsDescription,
                                                    PACKAGE_VERSION,
                                                    "");

    std::string containerRoot;
    std::string containedCommand;
    std::string cookie;
    const char* configFilePath = CONFIG;
    commandLineParser.addOption(configFilePath,
                                "with-config-file",
                                'c',
                                "Config file");

    if (commandLineParser.parse(argc, argv)) {
        return -1;
    }

    if (argc < 4) {
        log_error("Invalid arguments");
        commandLineParser.printHelp();
        return -1;
    } else {
        containerRoot = std::string(argv[1]);
        containedCommand = std::string(argv[2]);
        cookie = std::string(argv[3]);
    }

    if (containerRoot.c_str()[0] != '/') {
        log_error("Path to container root must be absolute");
        commandLineParser.printHelp();
        return -1;
    }

    std::string containerName = Generator::gen_ct_name();
    std::string containerConfig(configFilePath);

    // Create gateway directory for container in containerRoot/gateways.
    // This dir will contain various sockets etc acting as gateways
    // in/out of the container.
    containerDir = containerRoot + "/" + containerName;
    std::string gatewayDir = containerDir + "/gateways";
    if (mkdir(containerDir.c_str(), S_IRWXU) == -1) {
        log_error("Could not create container directory %s, %s.",
                  containerDir.c_str(),
                  strerror(errno));
        return -1;
    }
    if (mkdir(gatewayDir.c_str(), S_IRWXU) == -1) {
        log_error("Could not create gateway directory %s, %s.",
                  gatewayDir.c_str(),
                  strerror(errno));
        return -1;
    }

    // Make sure path ends in '/' since it might not always be checked
    if (containerRoot.back() != '/') {
        containerRoot += "/";
    }

    Container container(containerName,
                        containerConfig,
                        containerRoot,
                        containedCommand);

    if (!container.initialize()) {
        log_error() << "Could not setup container for preloading";
        removeDirs();
        return -1;
    }

    Glib::RefPtr<Glib::MainLoop> ml = Glib::MainLoop::create();

    { // Create a new scope so that we can do a clean up after dtors
        DBus::Glib::BusDispatcher dispatcher;
        DBus::default_dispatcher = &dispatcher;
        dispatcher.attach(ml->get_context()->gobj());
        DBus::Connection bus = DBus::Connection::SessionBus();

        /* Pelagicontain needs an interface to the mainloop so it can
         * exit it when we are to clean up and shut down
         */
        DBusMainloop mainloopInterface(ml);

        /* The request_name call does not return anything but raises an
         * exception if the name cannot be requested.
         */
        std::string name = "com.pelagicore.Pelagicontain" + cookie;
        bus.request_name(name.c_str());

        /* If we can't communicate with PAM then there is nothing we can
         * do really, better to just exit.
         */
        bool pamRunning = bus.has_name("com.pelagicore.PAM");
        if (!pamRunning) {
            log_error() << "PAM not running, exiting";
            removeDirs();
            return -1;
        }

        PAMInterface pamInterface(bus);
        ControllerInterface controllerInterface(gatewayDir);
        SystemcallInterface systemcallInterface;
        pelagicontain = new Pelagicontain(&pamInterface,
                                          &mainloopInterface,
                                          &controllerInterface,
                                          cookie);

        std::string objectPath = "/com/pelagicore/Pelagicontain";

        PelagicontainToDBusAdapter pcAdapter(bus, objectPath, *pelagicontain);

#ifdef ENABLE_NETWORKGATEWAY
        pelagicontain->addGateway(new NetworkGateway(controllerInterface,
                                                    systemcallInterface));
#endif

#ifdef ENABLE_PULSEGATEWAY
        pelagicontain->addGateway(new PulseGateway(gatewayDir, containerName,
                                                  controllerInterface));
#endif

#ifdef ENABLE_DEVICENODEGATEWAY
        pelagicontain->addGateway(new DeviceNodeGateway(controllerInterface));
#endif

#ifdef ENABLE_DBUSGATEWAY
        pelagicontain->addGateway(new DBusGateway(controllerInterface,
                                                 systemcallInterface,
                                                 DBusGateway::SessionProxy,
                                                 gatewayDir,
                                                 containerName));

        pelagicontain->addGateway(new DBusGateway(controllerInterface,
                                                 systemcallInterface,
                                                 DBusGateway::SystemProxy,
                                                 gatewayDir,
                                                 containerName));
#endif

        pcPid = pelagicontain->preload(&container);

        if (!pcPid) {
            // Fatal failure, only do necessary cleanup
            log_error() << "Could not start container, will shut down";
        } else {
            log_debug() << "Started container with PID " << pcPid;
            // setup IPC between Pelagicontain and Controller
            bool connected = pelagicontain->establishConnection();
            if (connected) {
                ml->run();
                // When we return here Pelagicontain has exited the mainloop
                log_debug("Exited mainloop");
            } else {
                // Fatal failure, only do necessary cleanup
                log_error() << "Got no connection from Controller";
                pelagicontain->shutdownContainer();
            }
        }
    }

    delete pelagicontain;
    removeDirs();

    log_debug() << "Goodbye.";
}
<|endoftext|>


<commit_before>namespace treap {
    mt19937 rnd = []() {
        random_device rd;
        return mt19937(rd());
    }();

    template <typename Key, typename F>
    struct Node {
        Node* l;
        Node* r;
        uint32_t y;

        Key x;
        F sum;

        Node(): l(nullptr), r(nullptr), y(rnd()), x(), sum() {}
        Node(const Key& x): l(nullptr), r(nullptr), y(rnd()), x(x), sum(x) {}
        Node(Key&& x): l(nullptr), r(nullptr), y(rnd()), x(x), sum(x) {}

        Node* update() {
            sum = F(x);
            if (l) sum = l->sum + sum;
            if (r) sum = sum + r->sum;
            return this;
        }

        Node* setL(Node* l) {
            this->l = l;
            return update();
        }

        Node* setR(Node* r) {
            this->r = r;
            return update();
        }
    };

    template <typename T>
    T* merge(T* l, T* r) {
        if (!l || !r) return l ? l : r;
        if (l->y > r->y) return l->setR(merge(l->r, r));
        else return r->setL(merge(l, r->l));
    }

    template <typename T, typename Key>
    pair<T*, T*> split(T* t, const Key& x) {
        if (!t) return make_pair(t, t);
        if (t->x < x) {
            auto tmp = split(t->r, x);
            return make_pair(t->setR(tmp.first), tmp.second);
        } else {
            auto tmp = split(t->l, x);
            return make_pair(tmp.first, t->setL(tmp.second));
        }
    }

    template <typename T>
    T* insertOne(T* t, T* e) {
        if (!t) return e;
        if (t->x > e->x) {
            return t->setL(insertOne(t->l, e));
        } else {
            return t->setR(insertOne(t->r, e));
        }
    }

    template <typename T, typename Key>
    size_t count(T* t, const Key& x, bool l = false, bool r = false) {
        if (!t) return 0;
        if (l && r) return t->sum.sz;
        if (t->x == x) {
            return 1 + count(t->l, x, l, true) + count(t->r, x, true, r);
        }
        if (t->x > x) {
            return count(t->l, x, l, false);
        } else {
            return count(t->r, x, false, r);
        }
    }

    template <typename T>
    T* insertOne(T* t, T* e) {
        if (!t) return e;
        if (e->y >= t->y) {
            T *a, *b;
            tie(a, b) = split(t, e->x);
            return e->setL(a)->setR(b);
        } else {
            if (t->x > e->x) {
                return t->setL(insertOne(t->l, e));
            } else {
                return t->setR(insertOne(t->r, e));
            }
        }
    }

    template <typename T, typename C>
    void walk(T* t, const C& callback) {
        if (!t) return;
        walk(t->l, callback);
        callback(*t);
        walk(t->r, callback);
    }
}
<commit_msg>fix fix<commit_after>namespace treap {
    mt19937 rnd = []() {
        random_device rd;
        return mt19937(rd());
    }();

    template <typename Key, typename F>
    struct Node {
        Node* l;
        Node* r;
        uint32_t y;

        Key x;
        F sum;

        Node(): l(nullptr), r(nullptr), y(rnd()), x(), sum() {}
        Node(const Key& x): l(nullptr), r(nullptr), y(rnd()), x(x), sum(x) {}
        Node(Key&& x): l(nullptr), r(nullptr), y(rnd()), x(x), sum(x) {}

        Node* update() {
            sum = F(x);
            if (l) sum = l->sum + sum;
            if (r) sum = sum + r->sum;
            return this;
        }

        Node* setL(Node* l) {
            this->l = l;
            return update();
        }

        Node* setR(Node* r) {
            this->r = r;
            return update();
        }
    };

    template <typename T>
    T* merge(T* l, T* r) {
        if (!l || !r) return l ? l : r;
        if (l->y > r->y) return l->setR(merge(l->r, r));
        else return r->setL(merge(l, r->l));
    }

    template <typename T, typename Key>
    pair<T*, T*> split(T* t, const Key& x) {
        if (!t) return make_pair(t, t);
        if (t->x < x) {
            auto tmp = split(t->r, x);
            return make_pair(t->setR(tmp.first), tmp.second);
        } else {
            auto tmp = split(t->l, x);
            return make_pair(tmp.first, t->setL(tmp.second));
        }
    }

    template <typename T>
    T* insertOne(T* t, T* e) {
        if (!t) return e;
        if (e->y >= t->y) {
            T *a, *b;
            tie(a, b) = split(t, e->x);
            return e->setL(a)->setR(b);
        } else {
            if (t->x > e->x) {
                return t->setL(insertOne(t->l, e));
            } else {
                return t->setR(insertOne(t->r, e));
            }
        }
    }

    template <typename T, typename Key>
    size_t count(T* t, const Key& x, bool l = false, bool r = false) {
        if (!t) return 0;
        if (l && r) return t->sum.sz;
        if (t->x == x) {
            return 1 + count(t->l, x, l, true) + count(t->r, x, true, r);
        }
        if (t->x > x) {
            return count(t->l, x, l, false);
        } else {
            return count(t->r, x, false, r);
        }
    }

    template <typename T, typename Key>
    T* remove(T* t, const Key& x) {
        if (!t) return t;
        if (t->x == x) return merge(t->l, t->r);
        if (t->x < x) {
            return t->setR(remove(t->r, x));
        } else {
            return t->setL(remove(t->l, x));
        }
    }

    template <typename T, typename C>
    void walk(T* t, const C& callback) {
        if (!t) return;
        walk(t->l, callback);
        callback(*t);
        walk(t->r, callback);
    }
}
<|endoftext|>


<commit_before>#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <boost/lexical_cast.hpp>
#include "packet.h"

#define USAGE "Usage:\r\nc [tux machine number] [probability of packet corruption in int form] [probability of packet loss in int form]\r\n"
#define BUFSIZE 121
#define FILENAME "Testfile"
#define TEST_FILENAME "Testfile2"
#define PORT 10038
#define PAKSIZE 128
#define ACK 0
#define NAK 1

using namespace std;

bool gremlin(Packet * pack, int corruptProb, int lossProb);
bool init(int argc, char** argv);
bool loadFile();
bool sendFile();
bool getFile();
char * recvPkt();
bool isvpack(unsigned char * p);
Packet createPacket(int index);
bool sendPacket();
bool isAck();
void handleAck();
void handleNak(int& x);

bool seqNum;
int s;
int probCorrupt;
int probLoss;
string hs;
short int port;
char * file;
int length;
struct sockaddr_in a;
struct sockaddr_in sa;
socklen_t salen;
string fstr;
bool dropPck;
Packet p;
unsigned char b[BUFSIZE];

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

  if(!init(argc, argv)) return -1;

  getFile();

  return 0;
}

bool init(int argc, char** argv) {

  s = 0;

  if(argc != 4) {
    cout << USAGE << endl;
    return false;
  }

  char * probCorruptStr = argv[2];
  probCorrupt = boost::lexical_cast<int>(probCorruptStr);
  char * probLossStr = argv[3];
  probLoss = boost::lexical_cast<int>(probLossStr);

  hs = string("131.204.14.") + argv[1]; /* Needs to be updated? Might be a string like "tux175.engr.auburn.edu." */
  port = 10038; /* Can be any port within 10038-10041, inclusive. */

  /*if(!loadFile()) {
    cout << "Loading file failed. (filename FILENAME)" << endl;
    return false;
  }*/

  if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
    cout << "Socket creation failed. (socket s)" << endl;
    return false;
  }

  memset((char *)&a, 0, sizeof(a));
  a.sin_family = AF_INET;
  a.sin_addr.s_addr = htonl(INADDR_ANY); //why does this always give us 0?
  a.sin_port = htons(0);

  if (bind(s, (struct sockaddr *)&a, sizeof(a)) < 0){
    cout << "Socket binding failed. (socket s, address a)" << endl;
    return false;
  }

  memset((char *)&sa, 0, sizeof(sa));
  sa.sin_family = AF_INET;
  sa.sin_port = htons(port);
  inet_pton(AF_INET, hs.c_str(), &(sa.sin_addr));

  cout << endl;

  cout << "Server address (inet mode): " << inet_ntoa(sa.sin_addr) << endl;
  cout << "Port: " << ntohs(sa.sin_port) << endl;

  cout << endl << endl;

  /*fstr = string(file);

  cout << "File: " << endl << fstr << endl << endl;*/

  seqNum = true;
  dropPck = false;
  return true;
}

bool loadFile() {

  ifstream is (FILENAME, ifstream::binary);

  if(is) {
    is.seekg(0, is.end);
    length = is.tellg();
    is.seekg(0, is.beg);

    file = new char[length];

    cout << "Reading " << length << " characters..." << endl;
    is.read(file, length);

    if(!is) { cout << "File reading failed. (filename " << FILENAME << "). Only " << is.gcount() << " could be read."; return false; }
    is.close();
  }
  return true;
}

bool sendFile() {

  for(int x = 0; x <= length / BUFSIZE; x++) {
    p = createPacket(x);
    if(!sendPacket()) continue;

    if(isAck()) {
      handleAck();
    } else {
      handleNak(x);
    }

    memset(b, 0, BUFSIZE);
  }
  return true;
}

Packet createPacket(int index){
    cout << endl;
    cout << "=== TRANSMISSION START" << endl;
    string mstr = fstr.substr(index * BUFSIZE, BUFSIZE);
    if(index * BUFSIZE + BUFSIZE > length) {
      mstr[length - (index * BUFSIZE)] = '\0';
    }
    return Packet (seqNum, mstr.c_str());
}

bool sendPacket(){
    int pc = probCorrupt; int pl = probLoss;
    if((dropPck = gremlin(&p, pc, pl)) == false){
      if(sendto(s, p.str(), BUFSIZE + 7, 0, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
        cout << "Package sending failed. (socket s, server address sa, message m)" << endl;
        return false;
      }
      return true;
    } else return false;
}
bool isAck() {
    recvfrom(s, b, BUFSIZE + 7, 0, (struct sockaddr *)&sa, &salen);

    cout << endl << "=== SERVER RESPONSE TEST" << endl;
    cout << "Data: " << b << endl;
    if(b[6] == '0') return true;
    else return false;
}
void handleAck() {

}
void handleNak(int& x) {

      char * sns = new char[2];
      memcpy(sns, &b[0], 1);
      sns[1] = '\0';

      char * css = new char[5];
      memcpy(css, &b[1], 5);

      char * db = new char[BUFSIZE + 1];
      memcpy(db, &b[2], BUFSIZE);
      db[BUFSIZE] = '\0';

      cout << "Sequence number: " << sns << endl;
      cout << "Checksum: " << css << endl;

      Packet pk (0, db);
      pk.setSequenceNum(boost::lexical_cast<int>(sns));
      pk.setCheckSum(boost::lexical_cast<int>(css));

      if(!pk.chksm()) x--;
      else x = (x - 2 > 0) ? x - 2 : 0;
}

bool gremlin(Packet * pack, int corruptProb, int lossProb){
  bool dropPacket = false;
  int r = rand() % 100;

  cout << "Corruption probability: " << corruptProb << endl;
  cout << "Random number: " << r << endl;

  if(r <= (lossProb)){
    dropPacket = true;
    cout << "Dropped!" << endl;
  }
  else if(r <= (corruptProb)){
    cout << "Corrupted!" << endl;
    pack->loadDataBuffer((char*)"GREMLIN LOL");
  }
  else seqNum = (seqNum) ? false : true;
  cout << "Seq. num: " << pack->getSequenceNum() << endl;
  cout << "Checksum: " << pack->getCheckSum() << endl;
  cout << "Message: "  << pack->getDataBuffer() << endl;

  return dropPacket;
}

bool isvpack(unsigned char * p) {
  cout << endl << "=== IS VALID PACKET TESTING" << endl;

  char * sns = new char[2];
  memcpy(sns, &p[0], 1);
  sns[1] = '\0';

  char * css = new char[6];
  memcpy(css, &p[1], 6);

  char * db = new char[121 + 1];
  memcpy(db, &p[2], 121);
  db[121] = '\0';

  cout << "Seq. num: " << sns << endl;
  cout << "Checksum: " << css << endl;
  cout << "Message: " << db << endl;

  int sn = boost::lexical_cast<int>(sns);
  int cs = boost::lexical_cast<int>(css);

  Packet pk (0, db);
  pk.setSequenceNum(sn);

  // change to validate based on checksum and sequence number

  if(sn == seqNum) return false;
  if(cs != pk.generateCheckSum()) return false;
  return true;
}

bool getFile(){
  /* Loop forever, waiting for messages from a client. */
  cout << "Waiting on port " << PORT << "..." << endl;

  ofstream file("Dumpfile");

  bool isSeqNumSet = false;
  for (;;) {
    unsigned char packet[PAKSIZE + 1];
    unsigned char dataPull[PAKSIZE - 7 + 1];
    rlen = recvfrom(s, packet, PAKSIZE, 0, (struct sockaddr *)&sa, &salen);
    if(!isSeqNumSet) {
      isSeqNumSet = true;
      char * str = new char[1];
      memcpy(str, &packet[0], 1);
      seqNum = boost::lexical_cast<int>(str);
    }
    for(int x = 0; x < PAKSIZE - 7; x++) {
      dataPull[x] = packet[x + 7];
    }
    dataPull[PAKSIZE - 7] = '\0';
    packet[PAKSIZE] = '\0';
    if (rlen > 0) {
      char * css = new char[6];
      memcpy(css, &packet[1], 5);
      css[5] = '\0';
      cout << endl << endl << "=== RECEIPT" << endl;
      cout << "Seq. num: " << packet[0] << endl;
      cout << "Checksum: " << css << endl;
      cout << "Received message: " << dataPull << endl;
      cout << "Sent response: ";
      if(isvpack(packet)) {
        ack = ACK;
        seqNum = (seqNum) ? false : true;
        file << dataPull;
      } else {
        ack = NAK;
      }
      cout << ((ack == ACK) ? "ACK" : "NAK") << endl;
      Packet p ((seqNum) ? false : true, reinterpret_cast<const char *>(dataPull));
      p.setCheckSum(boost::lexical_cast<int>(css));
      p.setAckNack(ack);

      if(sendto(s, p.str(), PAKSIZE, 0, (struct sockaddr *)&sa, salen) < 0) {
        cout << "Acknowledgement failed. (socket s, acknowledgement message ack, client address ca, client address length calen)" << endl;
        return 0;
      }
      delete css;
    }
  }
  file.close();
  return true;
}
<commit_msg>Fix copy/paste bugs 2<commit_after>#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <boost/lexical_cast.hpp>
#include "packet.h"

#define USAGE "Usage:\r\nc [tux machine number] [probability of packet corruption in int form] [probability of packet loss in int form]\r\n"
#define BUFSIZE 121
#define FILENAME "Testfile"
#define TEST_FILENAME "Testfile2"
#define PORT 10038
#define PAKSIZE 128
#define ACK 0
#define NAK 1

using namespace std;

bool gremlin(Packet * pack, int corruptProb, int lossProb);
bool init(int argc, char** argv);
bool loadFile();
bool sendFile();
bool getFile();
char * recvPkt();
bool isvpack(unsigned char * p);
Packet createPacket(int index);
bool sendPacket();
bool isAck();
void handleAck();
void handleNak(int& x);

bool seqNum;
int s;
int probCorrupt;
int probLoss;
string hs;
short int port;
char * file;
int length;
struct sockaddr_in a;
struct sockaddr_in sa;
socklen_t salen;
string fstr;
bool dropPck;
Packet p;
unsigned char b[BUFSIZE];

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

  if(!init(argc, argv)) return -1;

  getFile();

  return 0;
}

bool init(int argc, char** argv) {

  s = 0;

  if(argc != 4) {
    cout << USAGE << endl;
    return false;
  }

  char * probCorruptStr = argv[2];
  probCorrupt = boost::lexical_cast<int>(probCorruptStr);
  char * probLossStr = argv[3];
  probLoss = boost::lexical_cast<int>(probLossStr);

  hs = string("131.204.14.") + argv[1]; /* Needs to be updated? Might be a string like "tux175.engr.auburn.edu." */
  port = 10038; /* Can be any port within 10038-10041, inclusive. */

  /*if(!loadFile()) {
    cout << "Loading file failed. (filename FILENAME)" << endl;
    return false;
  }*/

  if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
    cout << "Socket creation failed. (socket s)" << endl;
    return false;
  }

  memset((char *)&a, 0, sizeof(a));
  a.sin_family = AF_INET;
  a.sin_addr.s_addr = htonl(INADDR_ANY); //why does this always give us 0?
  a.sin_port = htons(0);

  if (bind(s, (struct sockaddr *)&a, sizeof(a)) < 0){
    cout << "Socket binding failed. (socket s, address a)" << endl;
    return false;
  }

  memset((char *)&sa, 0, sizeof(sa));
  sa.sin_family = AF_INET;
  sa.sin_port = htons(port);
  inet_pton(AF_INET, hs.c_str(), &(sa.sin_addr));

  cout << endl;

  cout << "Server address (inet mode): " << inet_ntoa(sa.sin_addr) << endl;
  cout << "Port: " << ntohs(sa.sin_port) << endl;

  cout << endl << endl;

  /*fstr = string(file);

  cout << "File: " << endl << fstr << endl << endl;*/

  seqNum = true;
  dropPck = false;
  return true;
}

bool loadFile() {

  ifstream is (FILENAME, ifstream::binary);

  if(is) {
    is.seekg(0, is.end);
    length = is.tellg();
    is.seekg(0, is.beg);

    file = new char[length];

    cout << "Reading " << length << " characters..." << endl;
    is.read(file, length);

    if(!is) { cout << "File reading failed. (filename " << FILENAME << "). Only " << is.gcount() << " could be read."; return false; }
    is.close();
  }
  return true;
}

bool sendFile() {

  for(int x = 0; x <= length / BUFSIZE; x++) {
    p = createPacket(x);
    if(!sendPacket()) continue;

    if(isAck()) {
      handleAck();
    } else {
      handleNak(x);
    }

    memset(b, 0, BUFSIZE);
  }
  return true;
}

Packet createPacket(int index){
    cout << endl;
    cout << "=== TRANSMISSION START" << endl;
    string mstr = fstr.substr(index * BUFSIZE, BUFSIZE);
    if(index * BUFSIZE + BUFSIZE > length) {
      mstr[length - (index * BUFSIZE)] = '\0';
    }
    return Packet (seqNum, mstr.c_str());
}

bool sendPacket(){
    int pc = probCorrupt; int pl = probLoss;
    if((dropPck = gremlin(&p, pc, pl)) == false){
      if(sendto(s, p.str(), BUFSIZE + 7, 0, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
        cout << "Package sending failed. (socket s, server address sa, message m)" << endl;
        return false;
      }
      return true;
    } else return false;
}
bool isAck() {
    recvfrom(s, b, BUFSIZE + 7, 0, (struct sockaddr *)&sa, &salen);

    cout << endl << "=== SERVER RESPONSE TEST" << endl;
    cout << "Data: " << b << endl;
    if(b[6] == '0') return true;
    else return false;
}
void handleAck() {

}
void handleNak(int& x) {

      char * sns = new char[2];
      memcpy(sns, &b[0], 1);
      sns[1] = '\0';

      char * css = new char[5];
      memcpy(css, &b[1], 5);

      char * db = new char[BUFSIZE + 1];
      memcpy(db, &b[2], BUFSIZE);
      db[BUFSIZE] = '\0';

      cout << "Sequence number: " << sns << endl;
      cout << "Checksum: " << css << endl;

      Packet pk (0, db);
      pk.setSequenceNum(boost::lexical_cast<int>(sns));
      pk.setCheckSum(boost::lexical_cast<int>(css));

      if(!pk.chksm()) x--;
      else x = (x - 2 > 0) ? x - 2 : 0;
}

bool gremlin(Packet * pack, int corruptProb, int lossProb){
  bool dropPacket = false;
  int r = rand() % 100;

  cout << "Corruption probability: " << corruptProb << endl;
  cout << "Random number: " << r << endl;

  if(r <= (lossProb)){
    dropPacket = true;
    cout << "Dropped!" << endl;
  }
  else if(r <= (corruptProb)){
    cout << "Corrupted!" << endl;
    pack->loadDataBuffer((char*)"GREMLIN LOL");
  }
  else seqNum = (seqNum) ? false : true;
  cout << "Seq. num: " << pack->getSequenceNum() << endl;
  cout << "Checksum: " << pack->getCheckSum() << endl;
  cout << "Message: "  << pack->getDataBuffer() << endl;

  return dropPacket;
}

bool isvpack(unsigned char * p) {
  cout << endl << "=== IS VALID PACKET TESTING" << endl;

  char * sns = new char[2];
  memcpy(sns, &p[0], 1);
  sns[1] = '\0';

  char * css = new char[6];
  memcpy(css, &p[1], 6);

  char * db = new char[121 + 1];
  memcpy(db, &p[2], 121);
  db[121] = '\0';

  cout << "Seq. num: " << sns << endl;
  cout << "Checksum: " << css << endl;
  cout << "Message: " << db << endl;

  int sn = boost::lexical_cast<int>(sns);
  int cs = boost::lexical_cast<int>(css);

  Packet pk (0, db);
  pk.setSequenceNum(sn);

  // change to validate based on checksum and sequence number

  if(sn == seqNum) return false;
  if(cs != pk.generateCheckSum()) return false;
  return true;
}

bool getFile(){
  /* Loop forever, waiting for messages from a client. */
  cout << "Waiting on port " << PORT << "..." << endl;

  ofstream file("Dumpfile");

  int rlen;
  int ack;

  bool isSeqNumSet = false;
  for (;;) {
    unsigned char packet[PAKSIZE + 1];
    unsigned char dataPull[PAKSIZE - 7 + 1];
    rlen = recvfrom(s, packet, PAKSIZE, 0, (struct sockaddr *)&sa, &salen);
    if(!isSeqNumSet) {
      isSeqNumSet = true;
      char * str = new char[1];
      memcpy(str, &packet[0], 1);
      seqNum = boost::lexical_cast<int>(str);
    }
    for(int x = 0; x < PAKSIZE - 7; x++) {
      dataPull[x] = packet[x + 7];
    }
    dataPull[PAKSIZE - 7] = '\0';
    packet[PAKSIZE] = '\0';
    if (rlen > 0) {
      char * css = new char[6];
      memcpy(css, &packet[1], 5);
      css[5] = '\0';
      cout << endl << endl << "=== RECEIPT" << endl;
      cout << "Seq. num: " << packet[0] << endl;
      cout << "Checksum: " << css << endl;
      cout << "Received message: " << dataPull << endl;
      cout << "Sent response: ";
      if(isvpack(packet)) {
        ack = ACK;
        seqNum = (seqNum) ? false : true;
        file << dataPull;
      } else {
        ack = NAK;
      }
      cout << ((ack == ACK) ? "ACK" : "NAK") << endl;
      Packet p ((seqNum) ? false : true, reinterpret_cast<const char *>(dataPull));
      p.setCheckSum(boost::lexical_cast<int>(css));
      p.setAckNack(ack);

      if(sendto(s, p.str(), PAKSIZE, 0, (struct sockaddr *)&sa, salen) < 0) {
        cout << "Acknowledgement failed. (socket s, acknowledgement message ack, client address ca, client address length calen)" << endl;
        return 0;
      }
      delete css;
    }
  }
  file.close();
  return true;
}
<|endoftext|>