<commit_before>/*
 * Copyright (C) 2015 deipi.com LLC and contributors. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include "test_storage.h"

#include "../src/log.h"
#include "../src/storage.h"
#include "../src/utils.h"

#pragma pack(push, 1)
struct StorageBinBadHeader1 {
	// uint8_t magic;
	uint32_t aux;
	uint8_t flags;  // required
	uint32_t size;  // required

	inline void init(void* /*param*/, uint32_t size_, uint8_t flags_) {
		// magic = STORAGE_BIN_HEADER_MAGIC;
		size = size_;
		flags = (0 & ~STORAGE_FLAG_MASK) | flags_;
	}

	inline void validate(void* /*param*/) {
		// if (magic != STORAGE_BIN_HEADER_MAGIC) {
		// 	throw MSG_StorageCorruptVolume("Bad bin header magic number");
		// }
		if (flags & STORAGE_FLAG_DELETED) {
			throw MSG_StorageNotFound("Bin deleted");
		}
	}
};

struct StorageBinBadHeader2 {
	// uint8_t magic;
	uint8_t flags;  // required
	uint64_t size;  // required

	inline void init(void* /*param*/, uint32_t size_, uint8_t flags_) {
		// magic = STORAGE_BIN_HEADER_MAGIC;
		size = size_;
		flags = (0 & ~STORAGE_FLAG_MASK) | flags_;
	}

	inline void validate(void* /*param*/) {
		// if (magic != STORAGE_BIN_HEADER_MAGIC) {
		// 	throw MSG_StorageCorruptVolume("Bad bin header magic number");
		// }
		if (flags & STORAGE_FLAG_DELETED) {
			throw MSG_StorageNotFound("Bin deleted");
		}
	}
};

struct StorageBinBadHeader3 {
	// uint8_t magic;
	char aux[16];
	uint8_t flags;  // required
	uint32_t size;  // required

	inline void init(void* /*param*/, uint32_t size_, uint8_t flags_) {
		// magic = STORAGE_BIN_HEADER_MAGIC;
		size = size_;
		flags = (0 & ~STORAGE_FLAG_MASK) | flags_;
	}

	inline void validate(void* /*param*/) {
		// if (magic != STORAGE_BIN_HEADER_MAGIC) {
		// 	throw MSG_StorageCorruptVolume("Bad bin header magic number");
		// }
		if (flags & STORAGE_FLAG_DELETED) {
			throw MSG_StorageNotFound("Bin deleted");
		}
	}
};

struct StorageBinFooterChecksum {
	uint32_t checksum;
	// uint8_t magic;

	inline void init(void* /*param*/, uint32_t  checksum_) {
		// magic = STORAGE_BIN_FOOTER_MAGIC;
		checksum = checksum_;
	}

	inline void validate(void* /*param*/, uint32_t checksum_) {
		// if (magic != STORAGE_BIN_FOOTER_MAGIC) {
		// 	throw MSG_StorageCorruptVolume("Bad bin footer magic number");
		// }
		if (checksum != checksum_) {
			throw MSG_StorageCorruptVolume("Bad bin checksum");
		}
	}
};
#pragma pack(pop)

const std::string volume_name("examples/volume0");

static const std::vector<std::string> small_files({
	"examples/compressor/Small_File1.txt",
	"examples/compressor/Small_File2.txt",
	"examples/compressor/Small_File3.txt",
	"examples/compressor/Small_File4.txt"
});

static const std::vector<std::string> big_files({
	"examples/compressor/Big_File1.jpg",
	"examples/compressor/Big_File2.pdf",
	"examples/compressor/Big_File3.pdf",
	"examples/compressor/Big_File4.pdf",
	"examples/compressor/Big_File5.pdf"
});

int test_storage_data(int flags) {
	Storage<StorageHeader, StorageBinHeader, StorageBinFooterChecksum> _storage(nullptr);
	_storage.open(volume_name, STORAGE_CREATE_OR_OPEN | flags);

	std::string data;
	int cont_write = 0;
	for (int i = 0; i < 5120; ++i) {
		_storage.write(data);
		data.append(1, random_int('\x00', '\xff'));
		++cont_write;
	}
	_storage.close();

	_storage.open(volume_name, STORAGE_CREATE_OR_OPEN | flags);
	for (int i = 5120; i < 10240; ++i) {
		_storage.write(data);
		data.append(1, random_int('\x00', '\xff'));
		++cont_write;
	}

	int cont_read = 0;
	try {
		while (true) {
			size_t r;
			char buf[LZ4_BLOCK_SIZE];
			while ((r = _storage.read(buf, sizeof(buf))));
			++cont_read;
		}
	} catch (const StorageException& er) {
		L_ERR(nullptr, "Read: [%d] %s\n", cont_read, er.get_context());
	} catch (const LZ4Exception& er) {
		L_ERR(nullptr, "Read: [%d] %s\n", cont_read, er.get_context());
	} catch (const std::exception& er) {
		L_ERR(nullptr, "Read: [%d] %s\n", cont_read, er.what());
	}

	unlink(volume_name.c_str());

	return cont_read != cont_write;
}

int test_storage_file(int flags) {
	Storage<StorageHeader, StorageBinHeader, StorageBinFooterChecksum> _storage(nullptr);
	_storage.open(volume_name, STORAGE_CREATE_OR_OPEN | flags);

	int cont_write = 0;
	for (const auto& filename : small_files) {
		_storage.write_file(filename);
		++cont_write;
	}

	for (const auto& filename : big_files) {
		_storage.write_file(filename);
		++cont_write;
	}
	_storage.close();

	_storage.open(volume_name, STORAGE_CREATE_OR_OPEN | flags);
	for (const auto& filename : small_files) {
		_storage.write_file(filename);
		++cont_write;
	}

	for (const auto& filename : big_files) {
		_storage.write_file(filename);
		++cont_write;
	}

	int cont_read = 0;
	try {
		while (true) {
			size_t r;
			char buf[LZ4_BLOCK_SIZE];
			while ((r = _storage.read(buf, sizeof(buf))));
			++cont_read;
		}
	} catch (const StorageException& er) {
		L_ERR(nullptr, "Read: [%d] %s\n", cont_read, er.get_context());
	} catch (const LZ4Exception& er) {
		L_ERR(nullptr, "Read: [%d] %s\n", cont_read, er.get_context());
	} catch (const std::exception& er) {
		L_ERR(nullptr, "Read: [%d] %s\n", cont_read, er.what());
	}

	unlink(volume_name.c_str());

	return cont_read != cont_write;
}

int test_storage_bad_headers() {
	int res = 0;

	try {
		Storage<StorageHeader, StorageBinBadHeader1, StorageBinFooterChecksum> _storage(nullptr);
		res = 1;
	} catch (const std::exception& e) {
		L_ERR(nullptr, "Bad header (1): %s", e.what());
	}

	try {
		Storage<StorageHeader, StorageBinBadHeader2, StorageBinFooterChecksum> _storage(nullptr);
		res = 1;
	} catch (const std::exception& e) {
		L_ERR(nullptr, "Bad header (2): %s", e.what());
	}

	try {
		Storage<StorageHeader, StorageBinBadHeader3, StorageBinFooterChecksum> _storage(nullptr);
		res = 1;
	} catch (const std::exception& e) {
		L_ERR(nullptr, "Bad header (3): %s", e.what());
	}

	return res;
}

int test_storage_exception_write(int flags) {
	std::atomic_bool finish(false);
	Storage<StorageHeader, StorageBinHeader, StorageBinFooterChecksum> _storage(nullptr);

	_storage.open(volume_name, STORAGE_CREATE_OR_OPEN | flags);

	auto write_storage = std::thread([&]() {
		std::string data;
		for (int i = 0; i < 5120; ++i) {
			try {
				_storage.write(data);
			} catch (const StorageException& er) {
				_storage.open(volume_name, STORAGE_CREATE_OR_OPEN | flags);
			}
			data.append(1, random_int(0, 255));
		}
		finish.store(true);
	});

	auto interrupt_storage = std::thread([&]() {
		while (true) {
			std::this_thread::sleep_for(std::chrono::milliseconds(random_int(10, 20)));
			if (!finish.load()) {
				_storage.close();
			} else {
				return;
			}
		}
	});

	write_storage.detach();
	interrupt_storage.join();

	_storage.close();
	_storage.open(volume_name, STORAGE_CREATE_OR_OPEN | flags);
	int cont_read = 0;
	try {
		while (true) {
			size_t r;
			char buf[LZ4_BLOCK_SIZE];
			while ((r = _storage.read(buf, sizeof(buf))));
			++cont_read;
		}
	} catch (const StorageEOF& er) {
		L_ERR(nullptr, "Read: [%d] %s\n", cont_read, er.get_context());
		unlink(volume_name.c_str());
		return 0;
	} catch (const std::exception& er) {
		L_ERR(nullptr, "Read: [%d] %s\n", cont_read, er.what());
		unlink(volume_name.c_str());
		return 1;
	}
}

int test_storage_exception_write_file(int flags) {
	std::atomic_bool finish(false);
	Storage<StorageHeader, StorageBinHeader, StorageBinFooterChecksum> _storage(nullptr);

	_storage.open(volume_name, STORAGE_CREATE_OR_OPEN | flags);

	auto write_storage = std::thread([&]() {
		for (const auto& filename : small_files) {
			try {
				_storage.write_file(filename);
			} catch (const StorageException& er) {
				_storage.open(volume_name, STORAGE_CREATE_OR_OPEN | flags);
			}
		}

		for (const auto& filename : big_files) {
			try {
				_storage.write_file(filename);
			} catch (const StorageException& er) {
				_storage.open(volume_name, STORAGE_CREATE_OR_OPEN | flags);
			}
		}

		for (const auto& filename : small_files) {
			try {
				_storage.write_file(filename);
			} catch (const StorageException& er) {
				_storage.open(volume_name, STORAGE_CREATE_OR_OPEN | flags);
			}
		}

		finish.store(true);
	});

	auto interrupt_storage = std::thread([&]() {
		while (true) {
			std::this_thread::sleep_for(std::chrono::milliseconds(random_int(10, 20)));
			if (!finish.load()) {
				_storage.close();
			} else {
				return;
			}
		}
	});

	write_storage.detach();
	interrupt_storage.join();

	_storage.close();
	_storage.open(volume_name, STORAGE_CREATE_OR_OPEN | flags);
	int cont_read = 0;
	try {
		while (true) {
			size_t r;
			char buf[LZ4_BLOCK_SIZE];
			while ((r = _storage.read(buf, sizeof(buf))));
			++cont_read;
		}
	} catch (const StorageEOF& er) {
		L_ERR(nullptr, "Read: [%d] %s\n", cont_read, er.get_context());
		unlink(volume_name.c_str());
		return 0;
	} catch (const std::exception& er) {
		L_ERR(nullptr, "Read: [%d] %s\n", cont_read, er.what());
		unlink(volume_name.c_str());
		return 1;
	}
}
<commit_msg>Avoid race condition in storage tests<commit_after>/*
 * Copyright (C) 2015 deipi.com LLC and contributors. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include "test_storage.h"

#include "../src/log.h"
#include "../src/storage.h"
#include "../src/utils.h"

#pragma pack(push, 1)
struct StorageBinBadHeader1 {
	// uint8_t magic;
	uint32_t aux;
	uint8_t flags;  // required
	uint32_t size;  // required

	inline void init(void* /*param*/, uint32_t size_, uint8_t flags_) {
		// magic = STORAGE_BIN_HEADER_MAGIC;
		size = size_;
		flags = (0 & ~STORAGE_FLAG_MASK) | flags_;
	}

	inline void validate(void* /*param*/) {
		// if (magic != STORAGE_BIN_HEADER_MAGIC) {
		// 	throw MSG_StorageCorruptVolume("Bad bin header magic number");
		// }
		if (flags & STORAGE_FLAG_DELETED) {
			throw MSG_StorageNotFound("Bin deleted");
		}
	}
};

struct StorageBinBadHeader2 {
	// uint8_t magic;
	uint8_t flags;  // required
	uint64_t size;  // required

	inline void init(void* /*param*/, uint32_t size_, uint8_t flags_) {
		// magic = STORAGE_BIN_HEADER_MAGIC;
		size = size_;
		flags = (0 & ~STORAGE_FLAG_MASK) | flags_;
	}

	inline void validate(void* /*param*/) {
		// if (magic != STORAGE_BIN_HEADER_MAGIC) {
		// 	throw MSG_StorageCorruptVolume("Bad bin header magic number");
		// }
		if (flags & STORAGE_FLAG_DELETED) {
			throw MSG_StorageNotFound("Bin deleted");
		}
	}
};

struct StorageBinBadHeader3 {
	// uint8_t magic;
	char aux[16];
	uint8_t flags;  // required
	uint32_t size;  // required

	inline void init(void* /*param*/, uint32_t size_, uint8_t flags_) {
		// magic = STORAGE_BIN_HEADER_MAGIC;
		size = size_;
		flags = (0 & ~STORAGE_FLAG_MASK) | flags_;
	}

	inline void validate(void* /*param*/) {
		// if (magic != STORAGE_BIN_HEADER_MAGIC) {
		// 	throw MSG_StorageCorruptVolume("Bad bin header magic number");
		// }
		if (flags & STORAGE_FLAG_DELETED) {
			throw MSG_StorageNotFound("Bin deleted");
		}
	}
};

struct StorageBinFooterChecksum {
	uint32_t checksum;
	// uint8_t magic;

	inline void init(void* /*param*/, uint32_t  checksum_) {
		// magic = STORAGE_BIN_FOOTER_MAGIC;
		checksum = checksum_;
	}

	inline void validate(void* /*param*/, uint32_t checksum_) {
		// if (magic != STORAGE_BIN_FOOTER_MAGIC) {
		// 	throw MSG_StorageCorruptVolume("Bad bin footer magic number");
		// }
		if (checksum != checksum_) {
			throw MSG_StorageCorruptVolume("Bad bin checksum");
		}
	}
};
#pragma pack(pop)

const std::string volume_name("examples/volume0");

static const std::vector<std::string> small_files({
	"examples/compressor/Small_File1.txt",
	"examples/compressor/Small_File2.txt",
	"examples/compressor/Small_File3.txt",
	"examples/compressor/Small_File4.txt"
});

static const std::vector<std::string> big_files({
	"examples/compressor/Big_File1.jpg",
	"examples/compressor/Big_File2.pdf",
	"examples/compressor/Big_File3.pdf",
	"examples/compressor/Big_File4.pdf",
	"examples/compressor/Big_File5.pdf"
});

int test_storage_data(int flags) {
	Storage<StorageHeader, StorageBinHeader, StorageBinFooterChecksum> _storage(nullptr);
	_storage.open(volume_name, STORAGE_CREATE_OR_OPEN | flags);

	std::string data;
	int cont_write = 0;
	for (int i = 0; i < 5120; ++i) {
		_storage.write(data);
		data.append(1, random_int('\x00', '\xff'));
		++cont_write;
	}
	_storage.close();

	_storage.open(volume_name, STORAGE_CREATE_OR_OPEN | flags);
	for (int i = 5120; i < 10240; ++i) {
		_storage.write(data);
		data.append(1, random_int('\x00', '\xff'));
		++cont_write;
	}

	int cont_read = 0;
	try {
		while (true) {
			size_t r;
			char buf[LZ4_BLOCK_SIZE];
			while ((r = _storage.read(buf, sizeof(buf))));
			++cont_read;
		}
	} catch (const StorageException& er) {
		L_ERR(nullptr, "Read: [%d] %s\n", cont_read, er.get_context());
	} catch (const LZ4Exception& er) {
		L_ERR(nullptr, "Read: [%d] %s\n", cont_read, er.get_context());
	} catch (const std::exception& er) {
		L_ERR(nullptr, "Read: [%d] %s\n", cont_read, er.what());
	}

	unlink(volume_name.c_str());

	return cont_read != cont_write;
}

int test_storage_file(int flags) {
	Storage<StorageHeader, StorageBinHeader, StorageBinFooterChecksum> _storage(nullptr);
	_storage.open(volume_name, STORAGE_CREATE_OR_OPEN | flags);

	int cont_write = 0;
	for (const auto& filename : small_files) {
		_storage.write_file(filename);
		++cont_write;
	}

	for (const auto& filename : big_files) {
		_storage.write_file(filename);
		++cont_write;
	}
	_storage.close();

	_storage.open(volume_name, STORAGE_CREATE_OR_OPEN | flags);
	for (const auto& filename : small_files) {
		_storage.write_file(filename);
		++cont_write;
	}

	for (const auto& filename : big_files) {
		_storage.write_file(filename);
		++cont_write;
	}

	int cont_read = 0;
	try {
		while (true) {
			size_t r;
			char buf[LZ4_BLOCK_SIZE];
			while ((r = _storage.read(buf, sizeof(buf))));
			++cont_read;
		}
	} catch (const StorageException& er) {
		L_ERR(nullptr, "Read: [%d] %s\n", cont_read, er.get_context());
	} catch (const LZ4Exception& er) {
		L_ERR(nullptr, "Read: [%d] %s\n", cont_read, er.get_context());
	} catch (const std::exception& er) {
		L_ERR(nullptr, "Read: [%d] %s\n", cont_read, er.what());
	}

	unlink(volume_name.c_str());

	return cont_read != cont_write;
}

int test_storage_bad_headers() {
	int res = 0;

	try {
		Storage<StorageHeader, StorageBinBadHeader1, StorageBinFooterChecksum> _storage(nullptr);
		res = 1;
	} catch (const std::exception& e) {
		L_ERR(nullptr, "Bad header (1): %s", e.what());
	}

	try {
		Storage<StorageHeader, StorageBinBadHeader2, StorageBinFooterChecksum> _storage(nullptr);
		res = 1;
	} catch (const std::exception& e) {
		L_ERR(nullptr, "Bad header (2): %s", e.what());
	}

	try {
		Storage<StorageHeader, StorageBinBadHeader3, StorageBinFooterChecksum> _storage(nullptr);
		res = 1;
	} catch (const std::exception& e) {
		L_ERR(nullptr, "Bad header (3): %s", e.what());
	}

	return res;
}

int test_storage_exception_write(int flags) {
	std::atomic_bool finish(false);
	std::mutex mtx;
	Storage<StorageHeader, StorageBinHeader, StorageBinFooterChecksum> _storage(nullptr);

	_storage.open(volume_name, STORAGE_CREATE_OR_OPEN | flags);

	auto write_storage = std::thread([&]() {
		std::string data;
		for (int i = 0; i < 5120; ++i) {
			std::unique_lock<std::mutex> lk(mtx);
			try {
				_storage.write(data);
				lk.unlock();
			} catch (const StorageException& er) {
				_storage.open(volume_name, STORAGE_CREATE_OR_OPEN | flags);
				lk.unlock();
			}
			lk.lock();
			data.append(1, random_int(0, 255));
			lk.unlock();
		}
		finish.store(true);
	});

	auto interrupt_storage = std::thread([&]() {
		while (true) {
			std::unique_lock<std::mutex> lk(mtx);
			uint64_t ran = random_int(10, 20);
			lk.unlock();
			std::this_thread::sleep_for(std::chrono::milliseconds(ran));
			if (!finish.load()) {
				std::unique_lock<std::mutex> lk(mtx);
				_storage.close();
				lk.unlock();
			} else {
				return;
			}
		}
	});

	write_storage.detach();
	interrupt_storage.join();

	_storage.close();
	_storage.open(volume_name, STORAGE_CREATE_OR_OPEN | flags);
	int cont_read = 0;
	try {
		while (true) {
			size_t r;
			char buf[LZ4_BLOCK_SIZE];
			while ((r = _storage.read(buf, sizeof(buf))));
			++cont_read;
		}
	} catch (const StorageEOF& er) {
		L_ERR(nullptr, "Read: [%d] %s\n", cont_read, er.get_context());
		unlink(volume_name.c_str());
		return 0;
	} catch (const std::exception& er) {
		L_ERR(nullptr, "Read: [%d] %s\n", cont_read, er.what());
		unlink(volume_name.c_str());
		return 1;
	}
}

int test_storage_exception_write_file(int flags) {
	std::atomic_bool finish(false);
	std::mutex mtx;
	Storage<StorageHeader, StorageBinHeader, StorageBinFooterChecksum> _storage(nullptr);

	_storage.open(volume_name, STORAGE_CREATE_OR_OPEN | flags);

	auto write_storage = std::thread([&]() {
		for (const auto& filename : small_files) {
			std::unique_lock<std::mutex> lk(mtx);
			try {
				_storage.write_file(filename);
				lk.unlock();
			} catch (const StorageException& er) {
				_storage.open(volume_name, STORAGE_CREATE_OR_OPEN | flags);
				lk.unlock();
			}
		}

		for (const auto& filename : big_files) {
			std::unique_lock<std::mutex> lk(mtx);
			try {
				_storage.write_file(filename);
				lk.unlock();
			} catch (const StorageException& er) {
				_storage.open(volume_name, STORAGE_CREATE_OR_OPEN | flags);
				lk.unlock();
			}
		}

		for (const auto& filename : small_files) {
			std::unique_lock<std::mutex> lk(mtx);
			try {
				_storage.write_file(filename);
				lk.unlock();
			} catch (const StorageException& er) {
				_storage.open(volume_name, STORAGE_CREATE_OR_OPEN | flags);
				lk.unlock();
			}
		}

		finish.store(true);
	});

	auto interrupt_storage = std::thread([&]() {
		while (true) {
			std::unique_lock<std::mutex> lk(mtx);
			uint64_t ran = random_int(10, 20);
			lk.unlock();
			std::this_thread::sleep_for(std::chrono::milliseconds(ran));
			if (!finish.load()) {
				std::unique_lock<std::mutex> lk(mtx);
				_storage.close();
				lk.unlock();
			} else {
				return;
			}
		}
	});

	write_storage.detach();
	interrupt_storage.join();

	_storage.close();
	_storage.open(volume_name, STORAGE_CREATE_OR_OPEN | flags);
	int cont_read = 0;
	try {
		while (true) {
			size_t r;
			char buf[LZ4_BLOCK_SIZE];
			while ((r = _storage.read(buf, sizeof(buf))));
			++cont_read;
		}
	} catch (const StorageEOF& er) {
		L_ERR(nullptr, "Read: [%d] %s\n", cont_read, er.get_context());
		unlink(volume_name.c_str());
		return 0;
	} catch (const std::exception& er) {
		L_ERR(nullptr, "Read: [%d] %s\n", cont_read, er.what());
		unlink(volume_name.c_str());
		return 1;
	}
}
<|endoftext|>


<commit_before>/*
   Copyright (c) 2009-2017, Intel Corporation
   All rights reserved.

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

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

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

#include <cstdlib>
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
#include <sstream>
#include <exception>
#include <stdexcept>
#include <grp.h>
#include <stdio.h>
#include <stdlib.h>

#include "../daemon/common.h"
#include "client.h"

namespace PCMDaemon {

	Client::Client()
	: pollIntervalMs_(0), shmIdLocation_(DEFAULT_SHM_ID_LOCATION), shmAttached_(false), lastUpdatedClientTsc_(0)
	{}

	void Client::setSharedMemoryIdLocation(const std::string& location)
	{
		if(shmAttached_)
		{
			throw std::runtime_error("Shared memory segment already attached. You must call this method before the .connect() method.");
		}
		shmIdLocation_ = location;
	}

	void Client::setPollInterval(int pollMs)
	{
		pollIntervalMs_ = pollMs;
	}

	void Client::connect()
	{
		setupSharedMemory();

		//Set last updated timestamp to avoid a detected change
		//when the client starts
		lastUpdatedClientTsc_ = sharedPCMState_->lastUpdateTscEnd;
	}

	PCMDaemon::SharedPCMState& Client::read()
	{
		if(pollIntervalMs_ <= 0)
		{
			throw std::runtime_error("The poll interval is not set or is negative.");
		}

		if(!shmAttached_)
		{
			throw std::runtime_error("Not attached to shared memory segment. Call .connect() method.");
		}

		while(true)
		{
			// Check client version matches daemon version
			if(strlen(sharedPCMState_->version) > 0 && strcmp(sharedPCMState_->version, VERSION) != 0)
			{
				std::cout << sharedPCMState_->lastUpdateTscEnd << " " << lastUpdatedClientTsc_ << std::endl;
				std::stringstream ss;
				ss << "Out of date PCM daemon client. Client version: " << VERSION << " Daemon version: " << sharedPCMState_->version;

				throw std::runtime_error(ss.str());
			}

			if(countersHaveUpdated())
			{
				//There is new data
				lastUpdatedClientTsc_ = sharedPCMState_->lastUpdateTscEnd;

				return *sharedPCMState_;
			}
			else
			{
				//Nothing has changed since we last checked
				usleep(pollIntervalMs_ * 1000);
			}
		}
	}

	bool Client::countersHaveUpdated()
	{
		return lastUpdatedClientTsc_ != sharedPCMState_->lastUpdateTscEnd;
	}

	void Client::setupSharedMemory()
	{
		int sharedMemoryId;
		FILE *fp = fopen (shmIdLocation_.c_str(), "r");
		if (fp <= 0)
		{
			std::cerr << "Failed to open to shared memory key location: " << shmIdLocation_ << std::endl;
			exit(EXIT_FAILURE);
		}
		int maxCharsToRead = 11;
		char readBuffer[maxCharsToRead];
		fread(&readBuffer, maxCharsToRead, 1, fp);
		fclose (fp);

		sharedMemoryId = atoi(readBuffer);

		sharedPCMState_ = (PCMDaemon::SharedPCMState*)shmat(sharedMemoryId, NULL, 0);
		if (sharedPCMState_ == (void *)-1)
		{
			std::stringstream ss;
			ss << "Failed to attach shared memory segment (errno=" << errno << ")";

			throw std::runtime_error(ss.str());
		}

		shmAttached_ = true;
	}

}
<commit_msg>Replace endl with \n to get rid of many unnecessary flushes<commit_after>/*
   Copyright (c) 2009-2017, Intel Corporation
   All rights reserved.

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

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

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

#include <cstdlib>
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
#include <sstream>
#include <exception>
#include <stdexcept>
#include <grp.h>
#include <stdio.h>
#include <stdlib.h>

#include "../daemon/common.h"
#include "client.h"

namespace PCMDaemon {

	Client::Client()
	: pollIntervalMs_(0), shmIdLocation_(DEFAULT_SHM_ID_LOCATION), shmAttached_(false), lastUpdatedClientTsc_(0)
	{}

	void Client::setSharedMemoryIdLocation(const std::string& location)
	{
		if(shmAttached_)
		{
			throw std::runtime_error("Shared memory segment already attached. You must call this method before the .connect() method.");
		}
		shmIdLocation_ = location;
	}

	void Client::setPollInterval(int pollMs)
	{
		pollIntervalMs_ = pollMs;
	}

	void Client::connect()
	{
		setupSharedMemory();

		//Set last updated timestamp to avoid a detected change
		//when the client starts
		lastUpdatedClientTsc_ = sharedPCMState_->lastUpdateTscEnd;
	}

	PCMDaemon::SharedPCMState& Client::read()
	{
		if(pollIntervalMs_ <= 0)
		{
			throw std::runtime_error("The poll interval is not set or is negative.");
		}

		if(!shmAttached_)
		{
			throw std::runtime_error("Not attached to shared memory segment. Call .connect() method.");
		}

		while(true)
		{
			// Check client version matches daemon version
			if(strlen(sharedPCMState_->version) > 0 && strcmp(sharedPCMState_->version, VERSION) != 0)
			{
				std::cout << sharedPCMState_->lastUpdateTscEnd << " " << lastUpdatedClientTsc_ << "\n";
				std::stringstream ss;
				ss << "Out of date PCM daemon client. Client version: " << VERSION << " Daemon version: " << sharedPCMState_->version;

				throw std::runtime_error(ss.str());
			}

			if(countersHaveUpdated())
			{
				//There is new data
				lastUpdatedClientTsc_ = sharedPCMState_->lastUpdateTscEnd;

				return *sharedPCMState_;
			}
			else
			{
				//Nothing has changed since we last checked
				usleep(pollIntervalMs_ * 1000);
			}
		}
	}

	bool Client::countersHaveUpdated()
	{
		return lastUpdatedClientTsc_ != sharedPCMState_->lastUpdateTscEnd;
	}

	void Client::setupSharedMemory()
	{
		int sharedMemoryId;
		FILE *fp = fopen (shmIdLocation_.c_str(), "r");
		if (fp <= 0)
		{
			std::cerr << "Failed to open to shared memory key location: " << shmIdLocation_ << "\n";
			exit(EXIT_FAILURE);
		}
		int maxCharsToRead = 11;
		char readBuffer[maxCharsToRead];
		fread(&readBuffer, maxCharsToRead, 1, fp);
		fclose (fp);

		sharedMemoryId = atoi(readBuffer);

		sharedPCMState_ = (PCMDaemon::SharedPCMState*)shmat(sharedMemoryId, NULL, 0);
		if (sharedPCMState_ == (void *)-1)
		{
			std::stringstream ss;
			ss << "Failed to attach shared memory segment (errno=" << errno << ")";

			throw std::runtime_error(ss.str());
		}

		shmAttached_ = true;
	}

}
<|endoftext|>


<commit_before>// This file is part of the "libxzero" project
//   (c) 2009-2015 Christian Parpart <https://github.com/christianparpart>
//   (c) 2014-2015 Paul Asmuth <https://github.com/paulasmuth>
//
// libxzero is free software: you can redistribute it and/or modify it under
// the terms of the GNU Affero General Public License v3.0.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

#include <xzero/io/File.h>
#include <xzero/Buffer.h>
#include <xzero/logging.h>
#include <xzero/sysconfig.h>

#include <ctime>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>

#if 1
#define TRACE(level, msg...) logTrace("File", msg)
#else
#define TRACE(level, msg...) do {} while (0)
#endif

namespace xzero {

File::File(const std::string& path, const std::string& mimetype)
    : path_(path),
      mimetype_(mimetype),
      errno_(0),
      lastModified_() {
  TRACE(2, "($0).ctor", path_);
}

File::~File() {
  TRACE(2, "($0).dtor", path_);
}

std::string File::filename() const {
  size_t n = path_.rfind('/');
  return n != std::string::npos ? path_.substr(n + 1) : path_;
}

const std::string& File::lastModified() const {
  // build Last-Modified response header value on-demand
  if (lastModified_.empty()) {
    time_t modificationTime = mtime();
    struct tm tm;
    if (gmtime_r(&modificationTime, &tm)) {
      char buf[256];

      if (std::strftime(buf, sizeof(buf), "%a, %d %b %Y %T GMT", &tm) != 0) {
        lastModified_ = buf;
      }
    }
  }

  return lastModified_;
}

int File::to_posix(OpenFlags oflags) {
  int flags = 0;

#if defined(O_LARGEFILE)
  flags |= O_LARGEFILE;
#endif

  if ((oflags & ReadWrite) == ReadWrite)
    flags |= O_RDWR;
  else if (oflags & Read)
    flags |= O_RDONLY;
  else if (oflags & Write)
    flags |= O_WRONLY;

  if (oflags & Create)
    flags |= O_CREAT;

  if (oflags & CreateNew)
    flags |= O_CREAT | O_EXCL;

  if (oflags & Truncate)
    flags |= O_TRUNC;

  if (oflags & Append)
    flags |= O_APPEND;

#if defined(O_CLOEXEC)
  if (!(oflags & Share))
    flags |= O_CLOEXEC;
#endif

#if defined(O_NONBLOCK)
  if (oflags & NonBlocking)
    flags |= O_NONBLOCK;
#endif
  return flags;
}

} // namespace xzero
<commit_msg>File::to_posix() supports O_TMPFILE now, too<commit_after>// This file is part of the "libxzero" project
//   (c) 2009-2015 Christian Parpart <https://github.com/christianparpart>
//   (c) 2014-2015 Paul Asmuth <https://github.com/paulasmuth>
//
// libxzero is free software: you can redistribute it and/or modify it under
// the terms of the GNU Affero General Public License v3.0.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

#include <xzero/io/File.h>
#include <xzero/Buffer.h>
#include <xzero/logging.h>
#include <xzero/sysconfig.h>

#include <ctime>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>

#if 1
#define TRACE(level, msg...) logTrace("File", msg)
#else
#define TRACE(level, msg...) do {} while (0)
#endif

namespace xzero {

File::File(const std::string& path, const std::string& mimetype)
    : path_(path),
      mimetype_(mimetype),
      errno_(0),
      lastModified_() {
  TRACE(2, "($0).ctor", path_);
}

File::~File() {
  TRACE(2, "($0).dtor", path_);
}

std::string File::filename() const {
  size_t n = path_.rfind('/');
  return n != std::string::npos ? path_.substr(n + 1) : path_;
}

const std::string& File::lastModified() const {
  // build Last-Modified response header value on-demand
  if (lastModified_.empty()) {
    time_t modificationTime = mtime();
    struct tm tm;
    if (gmtime_r(&modificationTime, &tm)) {
      char buf[256];

      if (std::strftime(buf, sizeof(buf), "%a, %d %b %Y %T GMT", &tm) != 0) {
        lastModified_ = buf;
      }
    }
  }

  return lastModified_;
}

int File::to_posix(OpenFlags oflags) {
  int flags = 0;

#if defined(O_LARGEFILE)
  flags |= O_LARGEFILE;
#endif

  if ((oflags & ReadWrite) == ReadWrite)
    flags |= O_RDWR;
  else if (oflags & Read)
    flags |= O_RDONLY;
  else if (oflags & Write)
    flags |= O_WRONLY;

  if (oflags & Create)
    flags |= O_CREAT;

  if (oflags & CreateNew)
    flags |= O_CREAT | O_EXCL;

  if (oflags & Truncate)
    flags |= O_TRUNC;

  if (oflags & Append)
    flags |= O_APPEND;

#if defined(O_CLOEXEC)
  if (!(oflags & Share))
    flags |= O_CLOEXEC;
#endif

#if defined(O_NONBLOCK)
  if (oflags & NonBlocking)
    flags |= O_NONBLOCK;
#endif

#if defined(O_TMPFILE)
  if (!(oflags & TempFile))
    flags |= O_TMPFILE;
#endif

  return flags;
}

} // namespace xzero
<|endoftext|>


<commit_before>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015-2016 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <sstream>

#include <os>
#include <acorn>
#include <memdisk>

#include <profile>

#include <fs/disk.hpp>
#include <rtc>
#include <routes>
#include <dashboard>

using namespace std;
using namespace acorn;

using UserBucket     = bucket::Bucket<User>;
using SquirrelBucket = bucket::Bucket<Squirrel>;

std::shared_ptr<UserBucket>     users;
std::shared_ptr<SquirrelBucket> squirrels;

std::unique_ptr<server::Server> server_;
std::unique_ptr<dashboard::Dashboard> dashboard_;

////// DISK //////
// instantiate disk with filesystem
//#include <filesystem>
fs::Disk_ptr disk;

Statistics stats;
RTC::timestamp_t STARTED_AT;

#include <time.h>

// Get current date/time, format is YYYY-MM-DD.HH:mm:ss
const std::string currentDateTime() {
    time_t     now = time(0);
    struct tm  tstruct;
    char       buf[80];
    tstruct = *localtime(&now);
    // Visit http://en.cppreference.com/w/cpp/chrono/c/strftime
    // for more information about date/time format
    strftime(buf, sizeof(buf), "%Y-%m-%d.%X", &tstruct);

    return buf;
}

void recursive_fs_dump(vector<fs::Dirent> entries, int depth = 1);

void Service::start(const std::string&) {

  disk = fs::new_shared_memdisk();

  // mount the main partition in the Master Boot Record
  disk->mount([](fs::error_t err) {

      if (err)  panic("Could not mount filesystem, retreating...\n");

      /** IP STACK SETUP **/
      // Bring up IPv4 stack on network interface 0
      auto& stack = net::Inet4::ifconfig<0>(5.0,
      [](bool timeout) {
        printf("DHCP Resolution %s.\n", timeout?"failed":"succeeded");
      });
      // config
      stack.network_config({ 10,0,0,42 },     // IP
                           { 255,255,255,0 }, // Netmask
                           { 10,0,0,1 },      // Gateway
                           { 8,8,8,8 });      // DNS

      // only works with synchrone disks (memdisk)
      recursive_fs_dump(*disk->fs().ls("/").entries);

      /** STATS SETUP **/
      // TODO: Make use of Statman
      server::Connection::on_connection([](){
        stats.bump_connection_count();
      });

      server::Response::on_sent([](size_t n) {
        stats.bump_data_sent(n)
             .bump_response_sent();
      });

      server::Request::on_recv([](size_t n) {
        stats.bump_data_received(n)
          .bump_request_received();
      });

      /** BUCKET SETUP */

      // create squirrel bucket
      squirrels = std::make_shared<SquirrelBucket>();
      // set member name to be unique
      squirrels->add_index<std::string>("name",
      [](const Squirrel& s)->const auto&
      {
        return s.get_name();
      }, SquirrelBucket::UNIQUE);

      // seed squirrels
      auto first_key = squirrels->spawn("Andreas"s, 28U, "Code Monkey"s).key;
      squirrels->spawn("Alf"s, 6U, "Script kiddie"s);

      // A test to see if constraint is working (squirrel).
      // TODO: Unit test bucket and remove this
      bool exception_thrown = false;
      try {
        Squirrel dupe_name("Andreas", 0, "Tester");
        squirrels->capture(dupe_name);
      } catch(bucket::ConstraintUnique) {
        exception_thrown = true;
      }
      assert(exception_thrown);

      // A test to see if field search is working
      assert(squirrels->look_for("name", "Andreas"s).key == first_key);

      // setup users bucket
      users = std::make_shared<UserBucket>();

      users->spawn();
      users->spawn();

      /** ROUTES SETUP **/

      server::Router router;

      // setup Squirrel routes
      router.use("/api/squirrels", routes::Squirrels{squirrels});
      // setup User routes
      router.use("/api/users", routes::Users{users});

      /*----------[START TEST OF] CookieJar and CookieParser----------*/
      auto lang_api_handler = [](server::Request_ptr req, auto res, const std::string& lang) {
        if (req->has_attribute<CookieJar>()) {
          auto req_cookies = req->get_attribute<CookieJar>();

          { // Print all the request-cookies
            const auto& all_cookies = req_cookies->get_cookies();
            for (const auto& c : all_cookies) {
              printf("Cookie: %s=%s\n", c.first.c_str(), c.second.c_str());
            }
          }

          const auto& value = req_cookies->cookie_value("lang");

          if (value == "") {
            printf("%s\n", "Cookie with name 'lang' not found! Creating it.");
            res->cookie("lang", lang);
          } else if (value not_eq lang) {
            printf("%s\n", "Cookie with name 'lang' found, but with wrong value. Updating cookie.");
            res->update_cookie("lang", "", "", lang);
          } else {
            printf("%s %s %s\n", "Wanted cookie already exists (name 'lang' and value '", lang.c_str() ,"')!");
            res->send(true);
          }

        } else {
          printf("%s\n", "Request has no cookies! Creating cookie.");
          res->cookie("lang", lang);
        }
      };

      router.on_get("/api/english", [&lang_api_handler](server::Request_ptr req, auto res) {
        lang_api_handler(req, res, "en-US");
      });

      router.on_get("/api/norwegian", [&lang_api_handler](server::Request_ptr req, auto res) {
        lang_api_handler(req, res, "nb-NO");
      });
      /*----------[END TEST OF] CookieJar and CookieParser----------*/

      // Temporary route for polling http stats
      // TODO: Refactor to use Statsman and maybe integrate with dashboard
      router.on_get("/api/stats", [](auto, auto res) {
        using namespace rapidjson;
        StringBuffer sb;
        Writer<StringBuffer> writer(sb);
        stats.set_active_clients(server_->active_clients())
             .set_memory_usage(OS::heap_usage())
             .serialize(writer);
        res->send_json(sb.GetString());
      });

      /** DASHBOARD SETUP **/
      dashboard_ = std::make_unique<dashboard::Dashboard>(8192);
      // Add singleton component
      dashboard_->add(dashboard::Memmap::instance());
      dashboard_->add(dashboard::StackSampler::instance());
      dashboard_->add(dashboard::Status::instance());
      // Construct component
      dashboard_->construct<dashboard::Statman>(Statman::get());
      dashboard_->construct<dashboard::TCP>(stack.tcp());

      // Add Dashboard routes to "/api/dashboard"
      router.use("/api/dashboard", dashboard_->router());

      // Fallback route - serve index.html if route is not found
      router.on_get(".*", [](auto, auto res) {
        #ifdef VERBOSE_WEBSERVER
        printf("[@GET:*] Fallback route - try to serve index.html\n");
        #endif
        disk->fs().stat("/public/index.html", [res](auto err, const auto& entry) {
          if(err) {
            res->send_code(http::Not_Found);
          } else {
            // Serve index.html
            #ifdef VERBOSE_WEBSERVER
            printf("[@GET:*] (Fallback) Responding with index.html. \n");
            #endif
            res->send_file({disk, entry});
          }
        });
      });

      INFO("Router", "Registered routes:\n%s", router.to_string().c_str());

      /** SERVER SETUP **/

      // initialize server
      server_ = std::make_unique<server::Server>(stack);
      // set routes and start listening
      server_->set_routes(router).listen(80);

      /** MIDDLEWARE SETUP **/

      /* // example of how to inject a custom middleware closure
      // add a middleware as lambda
      acorn->use([](auto req, auto res, auto next){
        hw::PIT::on_timeout(0.050, [next]{
          printf("<MW:lambda> EleGiggle (50ms delay)\n");
          (*next)();
        });
      });
      */

      // custom middleware to serve static files
      auto opt = {"index.html", "index.htm"};
      //server::Middleware_ptr waitress = std::make_shared<Waitress>(disk, "", opt); // original
      server::Middleware_ptr waitress = std::make_shared<middleware::Waitress>(disk, "/public", opt); // WIP
      server_->use(waitress);

      // custom middleware to serve a webpage for a directory
      server::Middleware_ptr director = std::make_shared<middleware::Director>(disk, "/public/static");
      server_->use("/static", director);

      server::Middleware_ptr parsley = std::make_shared<middleware::Parsley>();
      server_->use(parsley);

      server::Middleware_ptr cookie_parser = std::make_shared<middleware::CookieParser>();
      server_->use(cookie_parser);

      // Print TCP information every 1 min
      Timers::periodic(30s, 1min, [](auto){
        printf("@onTimeout [%s]\n%s\n",
          currentDateTime().c_str(), server_->ip_stack().tcp().status().c_str());
      });

    }); // < disk
}

void recursive_fs_dump(vector<fs::Dirent> entries, int depth) {
  auto& filesys = disk->fs();
  int indent = (depth * 3);
  for (auto entry : entries) {

    // Print directories
    if (entry.is_dir()) {
      // Normal dirs
      if (entry.name() != "."  and entry.name() != "..") {
        printf(" %*s-[ %s ]\n", indent, "+", entry.name().c_str());
        filesys.ls(entry, [depth](auto, auto entries) {
          recursive_fs_dump(*entries, depth + 1);
        });
      } else {
        printf(" %*s  %s \n", indent, "+", entry.name().c_str());
      }

    }else {
      // Print files / symlinks etc.
      //printf(" %*s  \n", indent, "|");
      printf(" %*s-> %s \n", indent, "+", entry.name().c_str());
    }
  }
  printf(" %*s \n", indent, " ");
  //printf(" %*s \n", indent, "o");

}
<commit_msg>Service.cpp dashboard: CPU usage added<commit_after>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015-2016 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <sstream>

#include <os>
#include <acorn>
#include <memdisk>

#include <profile>

#include <fs/disk.hpp>
#include <rtc>
#include <routes>
#include <dashboard>

using namespace std;
using namespace acorn;

using UserBucket     = bucket::Bucket<User>;
using SquirrelBucket = bucket::Bucket<Squirrel>;

std::shared_ptr<UserBucket>     users;
std::shared_ptr<SquirrelBucket> squirrels;

std::unique_ptr<server::Server> server_;
std::unique_ptr<dashboard::Dashboard> dashboard_;

////// DISK //////
// instantiate disk with filesystem
//#include <filesystem>
fs::Disk_ptr disk;

Statistics stats;
RTC::timestamp_t STARTED_AT;

#include <time.h>

// Get current date/time, format is YYYY-MM-DD.HH:mm:ss
const std::string currentDateTime() {
    time_t     now = time(0);
    struct tm  tstruct;
    char       buf[80];
    tstruct = *localtime(&now);
    // Visit http://en.cppreference.com/w/cpp/chrono/c/strftime
    // for more information about date/time format
    strftime(buf, sizeof(buf), "%Y-%m-%d.%X", &tstruct);

    return buf;
}

void recursive_fs_dump(vector<fs::Dirent> entries, int depth = 1);

void Service::start(const std::string&) {

  disk = fs::new_shared_memdisk();

  // mount the main partition in the Master Boot Record
  disk->mount([](fs::error_t err) {

      if (err)  panic("Could not mount filesystem, retreating...\n");

      /** IP STACK SETUP **/
      // Bring up IPv4 stack on network interface 0
      auto& stack = net::Inet4::ifconfig<0>(5.0,
      [](bool timeout) {
        printf("DHCP Resolution %s.\n", timeout?"failed":"succeeded");
      });
      // config
      stack.network_config({ 10,0,0,42 },     // IP
                           { 255,255,255,0 }, // Netmask
                           { 10,0,0,1 },      // Gateway
                           { 8,8,8,8 });      // DNS

      // only works with synchrone disks (memdisk)
      recursive_fs_dump(*disk->fs().ls("/").entries);

      /** STATS SETUP **/
      // TODO: Make use of Statman
      server::Connection::on_connection([](){
        stats.bump_connection_count();
      });

      server::Response::on_sent([](size_t n) {
        stats.bump_data_sent(n)
             .bump_response_sent();
      });

      server::Request::on_recv([](size_t n) {
        stats.bump_data_received(n)
          .bump_request_received();
      });

      /** BUCKET SETUP */

      // create squirrel bucket
      squirrels = std::make_shared<SquirrelBucket>();
      // set member name to be unique
      squirrels->add_index<std::string>("name",
      [](const Squirrel& s)->const auto&
      {
        return s.get_name();
      }, SquirrelBucket::UNIQUE);

      // seed squirrels
      auto first_key = squirrels->spawn("Andreas"s, 28U, "Code Monkey"s).key;
      squirrels->spawn("Alf"s, 6U, "Script kiddie"s);

      // A test to see if constraint is working (squirrel).
      // TODO: Unit test bucket and remove this
      bool exception_thrown = false;
      try {
        Squirrel dupe_name("Andreas", 0, "Tester");
        squirrels->capture(dupe_name);
      } catch(bucket::ConstraintUnique) {
        exception_thrown = true;
      }
      assert(exception_thrown);

      // A test to see if field search is working
      assert(squirrels->look_for("name", "Andreas"s).key == first_key);

      // setup users bucket
      users = std::make_shared<UserBucket>();

      users->spawn();
      users->spawn();

      /** ROUTES SETUP **/

      server::Router router;

      // setup Squirrel routes
      router.use("/api/squirrels", routes::Squirrels{squirrels});
      // setup User routes
      router.use("/api/users", routes::Users{users});

      /*----------[START TEST OF] CookieJar and CookieParser----------*/
      auto lang_api_handler = [](server::Request_ptr req, auto res, const std::string& lang) {
        if (req->has_attribute<CookieJar>()) {
          auto req_cookies = req->get_attribute<CookieJar>();

          { // Print all the request-cookies
            const auto& all_cookies = req_cookies->get_cookies();
            for (const auto& c : all_cookies) {
              printf("Cookie: %s=%s\n", c.first.c_str(), c.second.c_str());
            }
          }

          const auto& value = req_cookies->cookie_value("lang");

          if (value == "") {
            printf("%s\n", "Cookie with name 'lang' not found! Creating it.");
            res->cookie("lang", lang);
          } else if (value not_eq lang) {
            printf("%s\n", "Cookie with name 'lang' found, but with wrong value. Updating cookie.");
            res->update_cookie("lang", "", "", lang);
          } else {
            printf("%s %s %s\n", "Wanted cookie already exists (name 'lang' and value '", lang.c_str() ,"')!");
            res->send(true);
          }

        } else {
          printf("%s\n", "Request has no cookies! Creating cookie.");
          res->cookie("lang", lang);
        }
      };

      router.on_get("/api/english", [&lang_api_handler](server::Request_ptr req, auto res) {
        lang_api_handler(req, res, "en-US");
      });

      router.on_get("/api/norwegian", [&lang_api_handler](server::Request_ptr req, auto res) {
        lang_api_handler(req, res, "nb-NO");
      });
      /*----------[END TEST OF] CookieJar and CookieParser----------*/

      // Temporary route for polling http stats
      // TODO: Refactor to use Statsman and maybe integrate with dashboard
      router.on_get("/api/stats", [](auto, auto res) {
        using namespace rapidjson;
        StringBuffer sb;
        Writer<StringBuffer> writer(sb);
        stats.set_active_clients(server_->active_clients())
             .set_memory_usage(OS::heap_usage())
             .serialize(writer);
        res->send_json(sb.GetString());
      });

      /** DASHBOARD SETUP **/
      dashboard_ = std::make_unique<dashboard::Dashboard>(8192);
      // Add singleton component
      dashboard_->add(dashboard::Memmap::instance());
      dashboard_->add(dashboard::StackSampler::instance());
      dashboard_->add(dashboard::Status::instance());
      // Construct component
      dashboard_->construct<dashboard::Statman>(Statman::get());
      dashboard_->construct<dashboard::TCP>(stack.tcp());
      dashboard_->construct<dashboard::CPUsage>(IRQ_manager::get(), 100ms, 2s);

      // Add Dashboard routes to "/api/dashboard"
      router.use("/api/dashboard", dashboard_->router());

      // Fallback route - serve index.html if route is not found
      router.on_get(".*", [](auto, auto res) {
        #ifdef VERBOSE_WEBSERVER
        printf("[@GET:*] Fallback route - try to serve index.html\n");
        #endif
        disk->fs().stat("/public/index.html", [res](auto err, const auto& entry) {
          if(err) {
            res->send_code(http::Not_Found);
          } else {
            // Serve index.html
            #ifdef VERBOSE_WEBSERVER
            printf("[@GET:*] (Fallback) Responding with index.html. \n");
            #endif
            res->send_file({disk, entry});
          }
        });
      });

      INFO("Router", "Registered routes:\n%s", router.to_string().c_str());

      /** SERVER SETUP **/

      // initialize server
      server_ = std::make_unique<server::Server>(stack);
      // set routes and start listening
      server_->set_routes(router).listen(80);

      /** MIDDLEWARE SETUP **/

      /* // example of how to inject a custom middleware closure
      // add a middleware as lambda
      acorn->use([](auto req, auto res, auto next){
        hw::PIT::on_timeout(0.050, [next]{
          printf("<MW:lambda> EleGiggle (50ms delay)\n");
          (*next)();
        });
      });
      */

      // custom middleware to serve static files
      auto opt = {"index.html", "index.htm"};
      //server::Middleware_ptr waitress = std::make_shared<Waitress>(disk, "", opt); // original
      server::Middleware_ptr waitress = std::make_shared<middleware::Waitress>(disk, "/public", opt); // WIP
      server_->use(waitress);

      // custom middleware to serve a webpage for a directory
      server::Middleware_ptr director = std::make_shared<middleware::Director>(disk, "/public/static");
      server_->use("/static", director);

      server::Middleware_ptr parsley = std::make_shared<middleware::Parsley>();
      server_->use(parsley);

      server::Middleware_ptr cookie_parser = std::make_shared<middleware::CookieParser>();
      server_->use(cookie_parser);

      // Print TCP information every 1 min
      Timers::periodic(30s, 1min, [](auto){
        printf("@onTimeout [%s]\n%s\n",
          currentDateTime().c_str(), server_->ip_stack().tcp().status().c_str());
      });

    }); // < disk
}

void recursive_fs_dump(vector<fs::Dirent> entries, int depth) {
  auto& filesys = disk->fs();
  int indent = (depth * 3);
  for (auto entry : entries) {

    // Print directories
    if (entry.is_dir()) {
      // Normal dirs
      if (entry.name() != "."  and entry.name() != "..") {
        printf(" %*s-[ %s ]\n", indent, "+", entry.name().c_str());
        filesys.ls(entry, [depth](auto, auto entries) {
          recursive_fs_dump(*entries, depth + 1);
        });
      } else {
        printf(" %*s  %s \n", indent, "+", entry.name().c_str());
      }

    }else {
      // Print files / symlinks etc.
      //printf(" %*s  \n", indent, "|");
      printf(" %*s-> %s \n", indent, "+", entry.name().c_str());
    }
  }
  printf(" %*s \n", indent, " ");
  //printf(" %*s \n", indent, "o");

}
<|endoftext|>


<commit_before>#ifndef COFFEE_MILL_COMMON_SNAPSHOT_HPP
#define COFFEE_MILL_COMMON_SNAPSHOT_HPP
#include <mill/common/Attribute.hpp>
#include <mill/common/BoundaryCondition.hpp>
#include <mill/util/scalar_type_of.hpp>
#include <vector>
#include <memory>

namespace mill
{

template<typename vectorT>
class Snapshot
{
  public:
    using vector_type    = vectorT;
    using real_type      = scalar_type_of_t<vector_type>;
    using attribute_type = Attribute<vector_type>;
    using attribute_container_type = std::map<std::string, attribute_type>;
    // {position, {name:attributes, ...}}
    using value_type     = std::pair<vector_type, attribute_container_type>;
    using particle_type  = value_type;
    using container_type = std::vector<value_type>;
    using iterator       = typename container_type::iterator;
    using const_iterator = typename container_type::const_iterator;
    using boundary_type  = std::unique_ptr<BoundaryCondition<vector_type>>;

  public:

    Snapshot() = default;
    ~Snapshot() = default;
    Snapshot(Snapshot const&) = default;
    Snapshot(Snapshot &&)     = default;
    Snapshot& operator=(Snapshot const&) = default;
    Snapshot& operator=(Snapshot &&)     = default;

    Snapshot(std::size_t N): particles_(N) {}

    Snapshot(attribute_type attr): attributes_(std::move(attr)) {}
    Snapshot(container_type ps)  : particles_(std::move(ps))    {}
    Snapshot(const std::vector<vector_type>& ps): particles_(ps.size())
    {
        std::transform(ps.begin(), ps.end(), particles_.begin(),
                [](const vector_type& v){
                    return std::make_pair(v, attribute_container_type{});
                });
    }

    void clear() {attributes_.clear(); particles_.clear(); return;}
    void empty() const noexcept
    {
        return attributes_.empty() && particles_.empty();
    }
    std::size_t size() const noexcept
    {
        return particles_.size();
    }

    value_type&       operator[](std::size_t i)       noexcept {return particles_[i];}
    value_type const& operator[](std::size_t i) const noexcept {return particles_[i];}
    value_type&       at(std::size_t i)       {return particles_.at(i);}
    value_type const& at(std::size_t i) const {return particles_.at(i);}

    attribute_type& operator[](const std::string& name) {return attributes_[name];}

    attribute_type&       at(const std::string& name)       {return attributes_.at(name);}
    attribute_type const& at(const std::string& name) const {return attributes_.at(name);}

    iterator        begin()       noexcept {return particles_.begin();}
    iterator        end()         noexcept {return particles_.end();}
    const_iterator  begin() const noexcept {return particles_.begin();}
    const_iterator  end()   const noexcept {return particles_.end();}
    const_iterator cbegin() const noexcept {return particles_.begin();}
    const_iterator cend()   const noexcept {return particles_.end();}

    attribute_container_type &      attributes()       noexcept {return attributes_;}
    attribute_container_type const& attributes() const noexcept {return attributes_;}
    container_type &      particles()       noexcept {return particles_;}
    container_type const& particles() const noexcept {return particles_;}
    boundary_type &      boundary()       noexcept {return boundary_;}
    boundary_type const& boundary() const noexcept {return boundary_;}

  private:
    attribute_container_type attributes_;
    container_type           particles_;
    boundary_type            boundary_;
};

} // mill
#endif // COFFEE_MILL_COMMON_SNAPSHOT_HPP
<commit_msg>:recycle: use Particle instead of pair<pos, attr><commit_after>#ifndef COFFEE_MILL_COMMON_SNAPSHOT_HPP
#define COFFEE_MILL_COMMON_SNAPSHOT_HPP
#include <mill/common/Particle.hpp>
#include <mill/common/BoundaryCondition.hpp>
#include <mill/util/scalar_type_of.hpp>
#include <vector>
#include <memory>

namespace mill
{

template<typename vectorT>
class Snapshot
{
  public:
    using vector_type    = vectorT;
    using real_type      = scalar_type_of_t<vector_type>;
    using attribute_type = Attribute<vector_type>;
    using attribute_container_type = std::map<std::string, attribute_type>;
    // {position, {name:attributes, ...}}
    using particle_type  = Particle<vector_type>;
    using value_type     = particle_type;
    using container_type = std::vector<value_type>;
    using iterator       = typename container_type::iterator;
    using const_iterator = typename container_type::const_iterator;
    using boundary_type  = std::unique_ptr<BoundaryCondition<vector_type>>;

  public:

    Snapshot() = default;
    ~Snapshot() = default;
    Snapshot(Snapshot const&) = default;
    Snapshot(Snapshot &&)     = default;
    Snapshot& operator=(Snapshot const&) = default;
    Snapshot& operator=(Snapshot &&)     = default;

    Snapshot(std::size_t N): particles_(N) {}

    Snapshot(attribute_type attr): attributes_(std::move(attr)) {}
    Snapshot(container_type ps)  : particles_(std::move(ps))    {}
    Snapshot(const std::vector<vector_type>& ps): particles_(ps.size())
    {
        std::transform(ps.begin(), ps.end(), particles_.begin(),
                [](const vector_type& v){
                    return std::make_pair(v, attribute_container_type{});
                });
    }

    void clear() {attributes_.clear(); particles_.clear(); return;}
    void empty() const noexcept
    {
        return attributes_.empty() && particles_.empty();
    }
    std::size_t size() const noexcept
    {
        return particles_.size();
    }

    particle_type&       operator[](std::size_t i)       noexcept {return particles_[i];}
    particle_type const& operator[](std::size_t i) const noexcept {return particles_[i];}
    particle_type&       at(std::size_t i)       {return particles_.at(i);}
    particle_type const& at(std::size_t i) const {return particles_.at(i);}

    attribute_type& operator[](const std::string& name) {return attributes_[name];}

    attribute_type&       at(const std::string& name)       {return attributes_.at(name);}
    attribute_type const& at(const std::string& name) const {return attributes_.at(name);}

    iterator        begin()       noexcept {return particles_.begin();}
    iterator        end()         noexcept {return particles_.end();}
    const_iterator  begin() const noexcept {return particles_.begin();}
    const_iterator  end()   const noexcept {return particles_.end();}
    const_iterator cbegin() const noexcept {return particles_.begin();}
    const_iterator cend()   const noexcept {return particles_.end();}

    attribute_container_type &      attributes()       noexcept {return attributes_;}
    attribute_container_type const& attributes() const noexcept {return attributes_;}
    container_type &      particles()       noexcept {return particles_;}
    container_type const& particles() const noexcept {return particles_;}
    boundary_type &      boundary()       noexcept {return boundary_;}
    boundary_type const& boundary() const noexcept {return boundary_;}

  private:
    attribute_container_type attributes_;
    container_type           particles_;
    boundary_type            boundary_;
};

} // mill
#endif // COFFEE_MILL_COMMON_SNAPSHOT_HPP
<|endoftext|>


<commit_before>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015-2016 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <sstream>

#include <os>
#include <acorn>
#include <memdisk>

#include <profile>

#include <fs/disk.hpp>
#include <rtc>
#include <routes>
#include <dashboard>
#include <logger/logger.hpp>

using namespace std;
using namespace acorn;

using UserBucket     = bucket::Bucket<User>;
using SquirrelBucket = bucket::Bucket<Squirrel>;

std::shared_ptr<UserBucket>     users;
std::shared_ptr<SquirrelBucket> squirrels;

std::unique_ptr<server::Server> server_;
std::unique_ptr<dashboard::Dashboard> dashboard_;
std::unique_ptr<Logger> logger_;

////// DISK //////
// instantiate disk with filesystem
//#include <filesystem>
fs::Disk_ptr disk;

Statistics stats;
RTC::timestamp_t STARTED_AT;

#include <time.h>

// Get current date/time, format is YYYY-MM-DD.HH:mm:ss
const std::string currentDateTime() {
    time_t     now = time(0);
    struct tm  tstruct;
    char       buf[80];
    tstruct = *localtime(&now);
    // Visit http://en.cppreference.com/w/cpp/chrono/c/strftime
    // for more information about date/time format
    strftime(buf, sizeof(buf), "%Y-%m-%d.%X", &tstruct);

    return buf;
}

void recursive_fs_dump(vector<fs::Dirent> entries, int depth = 1);

void Service::start(const std::string&) {

  /** SETUP LOGGER */
  char* buffer = (char*)malloc(1024*16);
  static gsl::span<char> spanerino{buffer, 1024*16};
  logger_ = std::make_unique<Logger>(spanerino);
  logger_->flush();
  logger_->log("LUL\n");

  printf("Going dark in 3 ... 2 ... 1 .\n");
  OS::set_rsprint([] (const char* data, size_t len) {
    OS::default_rsprint(data, len);
    logger_->log({data, len});
  });

  disk = fs::new_shared_memdisk();

  // mount the main partition in the Master Boot Record
  disk->mount([](fs::error_t err) {

      if (err)  panic("Could not mount filesystem, retreating...\n");

      /** IP STACK SETUP **/
      // Bring up IPv4 stack on network interface 0
      auto& stack = net::Inet4::ifconfig<0>(5.0,
      [](bool timeout) {
        printf("DHCP Resolution %s.\n", timeout?"failed":"succeeded");
      });
      // config
      stack.network_config({ 10,0,0,42 },     // IP
                           { 255,255,255,0 }, // Netmask
                           { 10,0,0,1 },      // Gateway
                           { 8,8,8,8 });      // DNS

      // only works with synchrone disks (memdisk)
      recursive_fs_dump(*disk->fs().ls("/").entries);

      /** BUCKET SETUP */

      // create squirrel bucket
      squirrels = std::make_shared<SquirrelBucket>();
      // set member name to be unique
      squirrels->add_index<std::string>("name",
      [](const Squirrel& s)->const auto&
      {
        return s.get_name();
      }, SquirrelBucket::UNIQUE);

      // seed squirrels
      squirrels->spawn("Andreas"s, 28U, "Code Monkey"s);
      squirrels->spawn("Alf"s, 6U, "Script kiddie"s);

      // setup users bucket
      users = std::make_shared<UserBucket>();

      users->spawn();
      users->spawn();

      /** ROUTES SETUP **/

      server::Router router;

      // setup Squirrel routes
      router.use("/api/squirrels", routes::Squirrels{squirrels});
      // setup User routes
      router.use("/api/users", routes::Users{users});

      /** DASHBOARD SETUP **/
      dashboard_ = std::make_unique<dashboard::Dashboard>(8192);
      // Add singleton component
      dashboard_->add(dashboard::Memmap::instance());
      dashboard_->add(dashboard::StackSampler::instance());
      dashboard_->add(dashboard::Status::instance());
      // Construct component
      dashboard_->construct<dashboard::Statman>(Statman::get());
      dashboard_->construct<dashboard::TCP>(stack.tcp());
      dashboard_->construct<dashboard::CPUsage>(IRQ_manager::get(), 0ms, 500ms);
      dashboard_->construct<dashboard::Logger>(*logger_, static_cast<size_t>(50));

      // Add Dashboard routes to "/api/dashboard"
      router.use("/api/dashboard", dashboard_->router());

      // Fallback route - serve index.html if route is not found
      router.on_get(".*", [](auto, auto res) {
        #ifdef VERBOSE_WEBSERVER
        printf("[@GET:*] Fallback route - try to serve index.html\n");
        #endif
        disk->fs().cstat("/public/index.html", [res](auto err, const auto& entry) {
          if(err) {
            res->send_code(http::Not_Found);
          } else {
            // Serve index.html
            #ifdef VERBOSE_WEBSERVER
            printf("[@GET:*] (Fallback) Responding with index.html. \n");
            #endif
            res->send_file({disk, entry});
          }
        });
      });

      INFO("Router", "Registered routes:\n%s", router.to_string().c_str());

      /** SERVER SETUP **/

      // initialize server
      server_ = std::make_unique<server::Server>(stack);
      // set routes and start listening
      server_->set_routes(router).listen(80);

      /** MIDDLEWARE SETUP **/

      /* // example of how to inject a custom middleware closure
      // add a middleware as lambda
      acorn->use([](auto req, auto res, auto next){
        hw::PIT::on_timeout(0.050, [next]{
          printf("<MW:lambda> EleGiggle (50ms delay)\n");
          (*next)();
        });
      });
      */

      // custom middleware to serve static files
      auto opt = {"index.html", "index.htm"};
      //server::Middleware_ptr waitress = std::make_shared<Waitress>(disk, "", opt); // original
      server::Middleware_ptr waitress = std::make_shared<middleware::Waitress>(disk, "/public", opt); // WIP
      server_->use(waitress);

      // custom middleware to serve a webpage for a directory
      server::Middleware_ptr director = std::make_shared<middleware::Director>(disk, "/public/static");
      server_->use("/static", director);

      server::Middleware_ptr parsley = std::make_shared<middleware::Parsley>();
      server_->use(parsley);

      server::Middleware_ptr cookie_parser = std::make_shared<middleware::CookieParser>();
      server_->use(cookie_parser);

      // Print TCP information every 1 min
      Timers::periodic(30s, 1min, [](auto){
        printf("@onTimeout [%s]\n%s\n",
          currentDateTime().c_str(), server_->ip_stack().tcp().status().c_str());
      });

    }); // < disk
}

void recursive_fs_dump(vector<fs::Dirent> entries, int depth) {
  auto& filesys = disk->fs();
  int indent = (depth * 3);
  for (auto entry : entries) {

    // Print directories
    if (entry.is_dir()) {
      // Normal dirs
      if (entry.name() != "."  and entry.name() != "..") {
        printf(" %*s-[ %s ]\n", indent, "+", entry.name().c_str());
        filesys.ls(entry, [depth](auto, auto entries) {
          recursive_fs_dump(*entries, depth + 1);
        });
      } else {
        printf(" %*s  %s \n", indent, "+", entry.name().c_str());
      }

    }else {
      // Print files / symlinks etc.
      //printf(" %*s  \n", indent, "|");
      printf(" %*s-> %s \n", indent, "+", entry.name().c_str());
    }
  }
  printf(" %*s \n", indent, " ");
  //printf(" %*s \n", indent, "o");

}
<commit_msg>Removed example of middleware using lambda<commit_after>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015-2016 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <sstream>

#include <os>
#include <acorn>
#include <memdisk>

#include <profile>

#include <fs/disk.hpp>
#include <rtc>
#include <routes>
#include <dashboard>
#include <logger/logger.hpp>

using namespace std;
using namespace acorn;

using UserBucket     = bucket::Bucket<User>;
using SquirrelBucket = bucket::Bucket<Squirrel>;

std::shared_ptr<UserBucket>     users;
std::shared_ptr<SquirrelBucket> squirrels;

std::unique_ptr<server::Server> server_;
std::unique_ptr<dashboard::Dashboard> dashboard_;
std::unique_ptr<Logger> logger_;

////// DISK //////
// instantiate disk with filesystem
//#include <filesystem>
fs::Disk_ptr disk;

Statistics stats;
RTC::timestamp_t STARTED_AT;

#include <time.h>

// Get current date/time, format is YYYY-MM-DD.HH:mm:ss
const std::string currentDateTime() {
    time_t     now = time(0);
    struct tm  tstruct;
    char       buf[80];
    tstruct = *localtime(&now);
    // Visit http://en.cppreference.com/w/cpp/chrono/c/strftime
    // for more information about date/time format
    strftime(buf, sizeof(buf), "%Y-%m-%d.%X", &tstruct);

    return buf;
}

void recursive_fs_dump(vector<fs::Dirent> entries, int depth = 1);

void Service::start(const std::string&) {

  /** SETUP LOGGER */
  char* buffer = (char*)malloc(1024*16);
  static gsl::span<char> spanerino{buffer, 1024*16};
  logger_ = std::make_unique<Logger>(spanerino);
  logger_->flush();
  logger_->log("LUL\n");

  printf("Going dark in 3 ... 2 ... 1 .\n");
  OS::set_rsprint([] (const char* data, size_t len) {
    OS::default_rsprint(data, len);
    logger_->log({data, len});
  });

  disk = fs::new_shared_memdisk();

  // mount the main partition in the Master Boot Record
  disk->mount([](fs::error_t err) {

      if (err)  panic("Could not mount filesystem, retreating...\n");

      /** IP STACK SETUP **/
      // Bring up IPv4 stack on network interface 0
      auto& stack = net::Inet4::ifconfig<0>(5.0,
      [](bool timeout) {
        printf("DHCP Resolution %s.\n", timeout?"failed":"succeeded");
      });
      // config
      stack.network_config({ 10,0,0,42 },     // IP
                           { 255,255,255,0 }, // Netmask
                           { 10,0,0,1 },      // Gateway
                           { 8,8,8,8 });      // DNS

      // only works with synchrone disks (memdisk)
      recursive_fs_dump(*disk->fs().ls("/").entries);

      /** BUCKET SETUP */

      // create squirrel bucket
      squirrels = std::make_shared<SquirrelBucket>();
      // set member name to be unique
      squirrels->add_index<std::string>("name",
      [](const Squirrel& s)->const auto&
      {
        return s.get_name();
      }, SquirrelBucket::UNIQUE);

      // seed squirrels
      squirrels->spawn("Andreas"s, 28U, "Code Monkey"s);
      squirrels->spawn("Alf"s, 6U, "Script kiddie"s);

      // setup users bucket
      users = std::make_shared<UserBucket>();

      users->spawn();
      users->spawn();

      /** ROUTES SETUP **/

      server::Router router;

      // setup Squirrel routes
      router.use("/api/squirrels", routes::Squirrels{squirrels});
      // setup User routes
      router.use("/api/users", routes::Users{users});

      /** DASHBOARD SETUP **/
      dashboard_ = std::make_unique<dashboard::Dashboard>(8192);
      // Add singleton component
      dashboard_->add(dashboard::Memmap::instance());
      dashboard_->add(dashboard::StackSampler::instance());
      dashboard_->add(dashboard::Status::instance());
      // Construct component
      dashboard_->construct<dashboard::Statman>(Statman::get());
      dashboard_->construct<dashboard::TCP>(stack.tcp());
      dashboard_->construct<dashboard::CPUsage>(IRQ_manager::get(), 0ms, 500ms);
      dashboard_->construct<dashboard::Logger>(*logger_, static_cast<size_t>(50));

      // Add Dashboard routes to "/api/dashboard"
      router.use("/api/dashboard", dashboard_->router());

      // Fallback route - serve index.html if route is not found
      router.on_get(".*", [](auto, auto res) {
        #ifdef VERBOSE_WEBSERVER
        printf("[@GET:*] Fallback route - try to serve index.html\n");
        #endif
        disk->fs().cstat("/public/index.html", [res](auto err, const auto& entry) {
          if(err) {
            res->send_code(http::Not_Found);
          } else {
            // Serve index.html
            #ifdef VERBOSE_WEBSERVER
            printf("[@GET:*] (Fallback) Responding with index.html. \n");
            #endif
            res->send_file({disk, entry});
          }
        });
      });

      INFO("Router", "Registered routes:\n%s", router.to_string().c_str());

      /** SERVER SETUP **/

      // initialize server
      server_ = std::make_unique<server::Server>(stack);
      // set routes and start listening
      server_->set_routes(router).listen(80);

      /** MIDDLEWARE SETUP **/

      // custom middleware to serve static files
      auto opt = {"index.html", "index.htm"};
      //server::Middleware_ptr waitress = std::make_shared<Waitress>(disk, "", opt); // original
      server::Middleware_ptr waitress = std::make_shared<middleware::Waitress>(disk, "/public", opt); // WIP
      server_->use(waitress);

      // custom middleware to serve a webpage for a directory
      server::Middleware_ptr director = std::make_shared<middleware::Director>(disk, "/public/static");
      server_->use("/static", director);

      server::Middleware_ptr parsley = std::make_shared<middleware::Parsley>();
      server_->use(parsley);

      server::Middleware_ptr cookie_parser = std::make_shared<middleware::CookieParser>();
      server_->use(cookie_parser);

      // Print TCP information every 1 min
      Timers::periodic(30s, 1min, [](auto){
        printf("@onTimeout [%s]\n%s\n",
          currentDateTime().c_str(), server_->ip_stack().tcp().status().c_str());
      });

    }); // < disk
}

void recursive_fs_dump(vector<fs::Dirent> entries, int depth) {
  auto& filesys = disk->fs();
  int indent = (depth * 3);
  for (auto entry : entries) {

    // Print directories
    if (entry.is_dir()) {
      // Normal dirs
      if (entry.name() != "."  and entry.name() != "..") {
        printf(" %*s-[ %s ]\n", indent, "+", entry.name().c_str());
        filesys.ls(entry, [depth](auto, auto entries) {
          recursive_fs_dump(*entries, depth + 1);
        });
      } else {
        printf(" %*s  %s \n", indent, "+", entry.name().c_str());
      }

    }else {
      // Print files / symlinks etc.
      //printf(" %*s  \n", indent, "|");
      printf(" %*s-> %s \n", indent, "+", entry.name().c_str());
    }
  }
  printf(" %*s \n", indent, " ");
  //printf(" %*s \n", indent, "o");

}
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/update_observer.h"

#include "app/l10n_util.h"
#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "chrome/common/time_format.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"

namespace chromeos {

UpdateObserver::UpdateObserver(Profile* profile)
    : notification_(profile, "update.chromeos", IDR_NOTIFICATION_UPDATE,
                    l10n_util::GetStringUTF16(IDS_UPDATE_TITLE)),
      progress_(-1) {}

UpdateObserver::~UpdateObserver() {
  notification_.Hide();
}

void UpdateObserver::UpdateStatusChanged(UpdateLibrary* library) {
  switch (library->status().status) {
    case UPDATE_STATUS_IDLE:
    case UPDATE_STATUS_CHECKING_FOR_UPDATE:
      // Do nothing in these cases, we don't want to notify the user of the
      // check unless there is an update. We don't hide here because
      // we want the final state to be sticky.
      break;
    case UPDATE_STATUS_UPDATE_AVAILABLE:
      notification_.Show(l10n_util::GetStringUTF16(IDS_UPDATE_AVAILABLE),
                         false);
      break;
    case UPDATE_STATUS_DOWNLOADING:
    {
      int progress = static_cast<int>(library->status().download_progress *
          100.0);
      if (progress != progress_) {
        progress_ = progress;
        notification_.Show(l10n_util::GetStringFUTF16(IDS_UPDATE_DOWNLOADING,
            base::IntToString16(progress_)), false);
      }
    }
      break;
    case UPDATE_STATUS_VERIFYING:
      notification_.Show(l10n_util::GetStringUTF16(IDS_UPDATE_VERIFYING),
                         false);
      break;
    case UPDATE_STATUS_FINALIZING:
      notification_.Show(l10n_util::GetStringUTF16(IDS_UPDATE_FINALIZING),
                         false);
      break;
    case UPDATE_STATUS_UPDATED_NEED_REBOOT:
      notification_.Show(l10n_util::GetStringUTF16(IDS_UPDATE_COMPLETED), true);
      break;
    default:
      notification_.Show(l10n_util::GetStringUTF16(IDS_UPDATE_ERROR), true);
      break;
  }
}

}  // namespace chromeos
<commit_msg>Handle the REPORTING_ERROR_EVENT state appropriately.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/update_observer.h"

#include "app/l10n_util.h"
#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "chrome/common/time_format.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"

namespace chromeos {

UpdateObserver::UpdateObserver(Profile* profile)
    : notification_(profile, "update.chromeos", IDR_NOTIFICATION_UPDATE,
                    l10n_util::GetStringUTF16(IDS_UPDATE_TITLE)),
      progress_(-1) {}

UpdateObserver::~UpdateObserver() {
  notification_.Hide();
}

void UpdateObserver::UpdateStatusChanged(UpdateLibrary* library) {
  switch (library->status().status) {
    case UPDATE_STATUS_IDLE:
    case UPDATE_STATUS_CHECKING_FOR_UPDATE:
      // Do nothing in these cases, we don't want to notify the user of the
      // check unless there is an update. We don't hide here because
      // we want the final state to be sticky.
      break;
    case UPDATE_STATUS_UPDATE_AVAILABLE:
      notification_.Show(l10n_util::GetStringUTF16(IDS_UPDATE_AVAILABLE),
                         false);
      break;
    case UPDATE_STATUS_DOWNLOADING:
    {
      int progress = static_cast<int>(library->status().download_progress *
          100.0);
      if (progress != progress_) {
        progress_ = progress;
        notification_.Show(l10n_util::GetStringFUTF16(IDS_UPDATE_DOWNLOADING,
            base::IntToString16(progress_)), false);
      }
    }
      break;
    case UPDATE_STATUS_VERIFYING:
      notification_.Show(l10n_util::GetStringUTF16(IDS_UPDATE_VERIFYING),
                         false);
      break;
    case UPDATE_STATUS_FINALIZING:
      notification_.Show(l10n_util::GetStringUTF16(IDS_UPDATE_FINALIZING),
                         false);
      break;
    case UPDATE_STATUS_UPDATED_NEED_REBOOT:
      notification_.Show(l10n_util::GetStringUTF16(IDS_UPDATE_COMPLETED), true);
      break;
    case UPDATE_STATUS_REPORTING_ERROR_EVENT:
      // If the update engine encounters an error and we have already
      // notified the user of the update progress, show an error
      // notification. Don't show anything otherwise -- for example,
      // in cases where the update engine encounters an error while
      // checking for an update.
      if (notification_.visible()) {
        notification_.Show(l10n_util::GetStringUTF16(IDS_UPDATE_ERROR), true);
      }
      break;
    default:
      notification_.Show(l10n_util::GetStringUTF16(IDS_UPDATE_ERROR), true);
      break;
  }
}

}  // namespace chromeos
<|endoftext|>


<commit_before>//----------------------------  49b.cc  ---------------------------
//    $Id$
//    Version: $Name$
//
//    Copyright (C) 2004, 2005, 2008, 2009 by the deal.II authors
//
//    This file is subject to QPL and may not be  distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//----------------------------  49b.cc  ---------------------------

// like 49, but do the test for
//  TrilinosWrappers::MPI::BlockVector
//         ::operator = (dealii::BlockVector<TrilinosScalar>)
// with block vectors instead of plain vectors

#include "../tests.h"
#include <deal.II/base/utilities.h>
#include <deal.II/lac/trilinos_block_vector.h>
#include <deal.II/lac/block_vector.h>
#include <fstream>
#include <iostream>
#include <vector>

void test (TrilinosWrappers::MPI::BlockVector &v)
{
  std::vector<types::global_dof_index> sizes (2, 3);
  dealii::BlockVector<TrilinosScalar> w (sizes);

  for (unsigned int i=0; i<w.size(); ++i)
    w(i) = i;

  v = w;

                                   // make sure we get the expected result
  for (unsigned int i=0; i<v.size(); ++i)
    {
      Assert (w(i) == i, ExcInternalError());
      Assert (v(i) == i, ExcInternalError());
    }

				   // now also check the reverse assignment
  w = 0;
  w = v;
  for (unsigned int i=0; i<v.size(); ++i)
    {
      Assert (w(i) == i, ExcInternalError());
      Assert (v(i) == i, ExcInternalError());
    }

  deallog << "OK" << std::endl;
}

int main (int argc,char **argv)
{
  std::ofstream logfile("49b/output");
  deallog.attach(logfile);
  deallog.depth_console(0);
  deallog.threshold_double(1.e-10);

  Utilities::MPI::MPI_InitFinalize mpi_initialization (argc, argv);

  try
    {
      {
	std::vector<Epetra_Map> sizes;
	Epetra_Map map(3, 3, 0, Utilities::Trilinos::comm_world());
	sizes.push_back (map);
	sizes.push_back (map);

        TrilinosWrappers::MPI::BlockVector v (sizes);
        test (v);
      }
    }
  catch (std::exception &exc)
    {
      std::cerr << std::endl << std::endl
		<< "----------------------------------------------------"
		<< std::endl;
      std::cerr << "Exception on processing: " << std::endl
		<< exc.what() << std::endl
		<< "Aborting!" << std::endl
		<< "----------------------------------------------------"
		<< std::endl;

      return 1;
    }
  catch (...)
    {
      std::cerr << std::endl << std::endl
		<< "----------------------------------------------------"
		<< std::endl;
      std::cerr << "Unknown exception!" << std::endl
		<< "Aborting!" << std::endl
		<< "----------------------------------------------------"
		<< std::endl;
      return 1;
    };
}
<commit_msg>Make run again.<commit_after>//----------------------------  49b.cc  ---------------------------
//    $Id$
//    Version: $Name$
//
//    Copyright (C) 2004, 2005, 2008, 2009, 2013 by the deal.II authors
//
//    This file is subject to QPL and may not be  distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//----------------------------  49b.cc  ---------------------------

// like 49, but do the test for
//  TrilinosWrappers::MPI::BlockVector
//         ::operator = (dealii::BlockVector<TrilinosScalar>)
// with block vectors instead of plain vectors

#include "../tests.h"
#include <deal.II/base/utilities.h>
#include <deal.II/lac/trilinos_block_vector.h>
#include <deal.II/lac/block_vector.h>
#include <fstream>
#include <iostream>
#include <vector>

void test (TrilinosWrappers::MPI::BlockVector &v)
{
  std::vector<types::global_dof_index> sizes (2, 3);
  dealii::BlockVector<TrilinosScalar> w (sizes);

  for (unsigned int i=0; i<w.size(); ++i)
    w(i) = i;

  v = w;

                                   // make sure we get the expected result
  for (unsigned int i=0; i<v.size(); ++i)
    {
      Assert (w(i) == i, ExcInternalError());
      Assert (v(i) == i, ExcInternalError());
    }

				   // now also check the reverse assignment
  w = 0;
  w = v;
  for (unsigned int i=0; i<v.size(); ++i)
    {
      Assert (w(i) == i, ExcInternalError());
      Assert (v(i) == i, ExcInternalError());
    }

  deallog << "OK" << std::endl;
}

int main (int argc,char **argv)
{
  std::ofstream logfile("49b/output");
  deallog.attach(logfile);
  deallog.depth_console(0);
  deallog.threshold_double(1.e-10);

  Utilities::MPI::MPI_InitFinalize mpi_initialization (argc, argv);

  try
    {
      {
	std::vector<Epetra_Map> sizes;
	Epetra_Map map(TrilinosWrappers::types::int_type(3),
		       TrilinosWrappers::types::int_type(3),
		       0,
		       Utilities::Trilinos::comm_world());
	sizes.push_back (map);
	sizes.push_back (map);

        TrilinosWrappers::MPI::BlockVector v (sizes);
        test (v);
      }
    }
  catch (std::exception &exc)
    {
      std::cerr << std::endl << std::endl
		<< "----------------------------------------------------"
		<< std::endl;
      std::cerr << "Exception on processing: " << std::endl
		<< exc.what() << std::endl
		<< "Aborting!" << std::endl
		<< "----------------------------------------------------"
		<< std::endl;

      return 1;
    }
  catch (...)
    {
      std::cerr << std::endl << std::endl
		<< "----------------------------------------------------"
		<< std::endl;
      std::cerr << "Unknown exception!" << std::endl
		<< "Aborting!" << std::endl
		<< "----------------------------------------------------"
		<< std::endl;
      return 1;
    };
}
<|endoftext|>


<commit_before><commit_msg>Extended operate test<commit_after><|endoftext|>