<commit_before>/*
 * Copyright (c) 2015 Oleg Morozenkov
 *
 * 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 "tgbot/Api.h"

#include "tgbot/TgTypeParser.h"
#include "tgbot/TgException.h"
#include "tgbot/net/HttpClient.h"

using namespace std;
using namespace boost::property_tree;

namespace TgBot {

Api::Api(const string& token) : _token(token) {
}

User::Ptr Api::getMe() const {
	return TgTypeParser::getInstance().parseJsonAndGetUser(sendRequest("getMe"));
}

Message::Ptr Api::sendMessage(int32_t chatId, const string& text, bool disableWebPagePreview, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const {
	vector<HttpReqArg> args;
	args.push_back(HttpReqArg("chat_id", chatId));
	args.push_back(HttpReqArg("text", text));
	if (disableWebPagePreview) {
		args.push_back(HttpReqArg("disable_web_page_preview", disableWebPagePreview));
	}
	if (replyToMessageId) {
		args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId));
	}
	if (replyMarkup) {
		args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup)));
	}
	return TgTypeParser::getInstance().parseJsonAndGetMessage(sendRequest("sendMessage", args));
}

Message::Ptr Api::forwardMessage(int32_t chatId, int32_t fromChatId, int32_t messageId) const {
	vector<HttpReqArg> args;
	args.push_back(HttpReqArg("chat_id", chatId));
	args.push_back(HttpReqArg("from_chat_id", fromChatId));
	args.push_back(HttpReqArg("message_id", messageId));
	return TgTypeParser::getInstance().parseJsonAndGetMessage(sendRequest("forwardMessage", args));
}

Message::Ptr Api::sendPhoto(int32_t chatId, const InputFile::Ptr& photo, const string& caption, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const {
	vector<HttpReqArg> args;
	args.push_back(HttpReqArg("chat_id", chatId));
	args.push_back(HttpReqArg("photo", photo->data, true, photo->mimeType, photo->fileName));
	if (!caption.empty()) {
		args.push_back(HttpReqArg("caption", caption));
	}
	if (replyToMessageId) {
		args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId));
	}
	if (replyMarkup) {
		args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup)));
	}
	return TgTypeParser::getInstance().parseJsonAndGetMessage(sendRequest("sendPhoto", args));
}

Message::Ptr Api::sendPhoto(int32_t chatId, const string& photoId, const string& caption, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const {
	vector<HttpReqArg> args;
	args.push_back(HttpReqArg("chat_id", chatId));
	args.push_back(HttpReqArg("photo", photoId));
	if (!caption.empty()) {
		args.push_back(HttpReqArg("caption", caption));
	}
	if (replyToMessageId) {
		args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId));
	}
	if (replyMarkup) {
		args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup)));
	}
	return TgTypeParser::getInstance().parseJsonAndGetMessage(sendRequest("sendPhoto", args));
}

Message::Ptr Api::sendAudio(int32_t chatId, const InputFile::Ptr& audio, int32_t duration, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const {
	vector<HttpReqArg> args;
	args.push_back(HttpReqArg("chat_id", chatId));
	args.push_back(HttpReqArg("audio", audio->data, true, audio->mimeType, audio->fileName));
	if (duration) {
		args.push_back(HttpReqArg("duration", duration));
	}
	if (replyToMessageId) {
		args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId));
	}
	if (replyMarkup) {
		args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup)));
	}
	return TgTypeParser::getInstance().parseJsonAndGetMessage(sendRequest("sendAudio", args));
}

Message::Ptr Api::sendAudio(int32_t chatId, const string& audioId, int32_t duration, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const {
	vector<HttpReqArg> args;
	args.push_back(HttpReqArg("chat_id", chatId));
	args.push_back(HttpReqArg("audio", audioId));
	if (duration) {
		args.push_back(HttpReqArg("duration", duration));
	}
	if (replyToMessageId) {
		args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId));
	}
	if (replyMarkup) {
		args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup)));
	}
	return TgTypeParser::getInstance().parseJsonAndGetMessage(sendRequest("sendAudio", args));
}

Message::Ptr Api::sendDocument(int32_t chatId, const InputFile::Ptr& document, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const {
	vector<HttpReqArg> args;
	args.push_back(HttpReqArg("chat_id", chatId));
	args.push_back(HttpReqArg("document", document->data, true, document->mimeType, document->fileName));
	if (replyToMessageId) {
		args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId));
	}
	if (replyMarkup) {
		args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup)));
	}
	return TgTypeParser::getInstance().parseJsonAndGetMessage(sendRequest("sendDocument", args));
}

Message::Ptr Api::sendDocument(int32_t chatId, const string& document, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const {
	vector<HttpReqArg> args;
	args.push_back(HttpReqArg("chat_id", chatId));
	args.push_back(HttpReqArg("document", document));
	if (replyToMessageId) {
		args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId));
	}
	if (replyMarkup) {
		args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup)));
	}
	return TgTypeParser::getInstance().parseJsonAndGetMessage(sendRequest("sendDocument", args));
}

Message::Ptr Api::sendSticker(int32_t chatId, const InputFile::Ptr& sticker, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const {
	vector<HttpReqArg> args;
	args.push_back(HttpReqArg("chat_id", chatId));
	args.push_back(HttpReqArg("sticker", sticker->data, true, sticker->mimeType, sticker->fileName));
	if (replyToMessageId) {
		args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId));
	}
	if (replyMarkup) {
		args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup)));
	}
	return TgTypeParser::getInstance().parseJsonAndGetMessage(sendRequest("sendSticker", args));
}

Message::Ptr Api::sendSticker(int32_t chatId, const string& stickerId, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const {
	vector<HttpReqArg> args;
	args.push_back(HttpReqArg("chat_id", chatId));
	args.push_back(HttpReqArg("sticker", stickerId));
	if (replyToMessageId) {
		args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId));
	}
	if (replyMarkup) {
		args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup)));
	}
	return TgTypeParser::getInstance().parseJsonAndGetMessage(sendRequest("sendSticker", args));
}

Message::Ptr Api::sendVideo(int32_t chatId, const InputFile::Ptr& video, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const {
	vector<HttpReqArg> args;
	args.push_back(HttpReqArg("chat_id", chatId));
	args.push_back(HttpReqArg("video", video->data, true, video->mimeType, video->fileName));
	if (replyToMessageId) {
		args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId));
	}
	if (replyMarkup) {
		args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup)));
	}
	return TgTypeParser::getInstance().parseJsonAndGetMessage(sendRequest("sendVideo", args));
}

Message::Ptr Api::sendVideo(int32_t chatId, const string& videoId, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const {
	vector<HttpReqArg> args;
	args.push_back(HttpReqArg("chat_id", chatId));
	args.push_back(HttpReqArg("video", videoId));
	if (replyToMessageId) {
		args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId));
	}
	if (replyMarkup) {
		args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup)));
	}
	return TgTypeParser::getInstance().parseJsonAndGetMessage(sendRequest("sendVideo", args));
}

Message::Ptr Api::sendLocation(int32_t chatId, float latitude, float longitude, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const {
	vector<HttpReqArg> args;
	args.push_back(HttpReqArg("chat_id", chatId));
	args.push_back(HttpReqArg("latitude", latitude));
	args.push_back(HttpReqArg("longitude", longitude));
	if (replyToMessageId) {
		args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId));
	}
	if (replyMarkup) {
		args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup)));
	}
	return TgTypeParser::getInstance().parseJsonAndGetMessage(sendRequest("sendLocation", args));
}

void Api::sendChatAction(int32_t chatId, const string& action) const {
	vector<HttpReqArg> args;
	args.push_back(HttpReqArg("chat_id", chatId));
	args.push_back(HttpReqArg("action", action));
	sendRequest("sendChatAction", args);
}

UserProfilePhotos::Ptr Api::getUserProfilePhotos(int32_t userId, int32_t offset, int32_t limit) const {
	vector<HttpReqArg> args;
	args.push_back(HttpReqArg("user_id", userId));
	if (offset) {
		args.push_back(HttpReqArg("offset", offset));
	}
	limit = max(1, min(100, limit));
	args.push_back(HttpReqArg("limit", limit));
	return TgTypeParser::getInstance().parseJsonAndGetUserProfilePhotos(sendRequest("getUserProfilePhotos", args));
}

vector<Update::Ptr> Api::getUpdates(int32_t offset, int32_t limit, int32_t timeout) const {
	vector<HttpReqArg> args;
	if (offset) {
		args.push_back(HttpReqArg("offset", offset));
	}
	limit = max(1, min(100, limit));
	args.push_back(HttpReqArg("limit", limit));
	if (timeout) {
		args.push_back(HttpReqArg("timeout", timeout));
	}
	return TgTypeParser::getInstance().parseJsonAndGetArray<Update>(&TgTypeParser::parseJsonAndGetUpdate, sendRequest("getUpdates", args));
}

void Api::setWebhook(const string& url) const {
	vector<HttpReqArg> args;
	args.push_back(HttpReqArg("url", url));
	sendRequest("setWebhook", args);
}

ptree Api::sendRequest(const string& method, const vector<HttpReqArg>& args) const {

	string url = "https://api.telegram.org/bot";
	url += _token;
	url += "/";
	url += method;

    std::cout << "URL: " << url << std::endl;
	string serverResponse = HttpClient::getInstance().makeRequest(url, args);
	if (serverResponse.find("<html>") != serverResponse.npos) {
		throw TgException("tgbot-cpp library have got html page instead of json response. Maybe you entered wrong bot token.");
	}

    std::cout << "Server Response: " << serverResponse << std::endl;

	ptree result = TgTypeParser::getInstance().parseJson(serverResponse);
	try {
		if (result.get<bool>("ok", false)) {
			return result.get_child("result");
		} else {
			throw TgException(result.get("description", ""));
		}
	} catch (boost::property_tree::ptree_error& e) {
		throw TgException("tgbot-cpp library can't parse json response. " + string(e.what()));
	}
}

}
<commit_msg>Remove cout<commit_after>/*
 * Copyright (c) 2015 Oleg Morozenkov
 *
 * 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 "tgbot/Api.h"

#include "tgbot/TgTypeParser.h"
#include "tgbot/TgException.h"
#include "tgbot/net/HttpClient.h"

using namespace std;
using namespace boost::property_tree;

namespace TgBot {

Api::Api(const string& token) : _token(token) {
}

User::Ptr Api::getMe() const {
	return TgTypeParser::getInstance().parseJsonAndGetUser(sendRequest("getMe"));
}

Message::Ptr Api::sendMessage(int32_t chatId, const string& text, bool disableWebPagePreview, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const {
	vector<HttpReqArg> args;
	args.push_back(HttpReqArg("chat_id", chatId));
	args.push_back(HttpReqArg("text", text));
	if (disableWebPagePreview) {
		args.push_back(HttpReqArg("disable_web_page_preview", disableWebPagePreview));
	}
	if (replyToMessageId) {
		args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId));
	}
	if (replyMarkup) {
		args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup)));
	}
	return TgTypeParser::getInstance().parseJsonAndGetMessage(sendRequest("sendMessage", args));
}

Message::Ptr Api::forwardMessage(int32_t chatId, int32_t fromChatId, int32_t messageId) const {
	vector<HttpReqArg> args;
	args.push_back(HttpReqArg("chat_id", chatId));
	args.push_back(HttpReqArg("from_chat_id", fromChatId));
	args.push_back(HttpReqArg("message_id", messageId));
	return TgTypeParser::getInstance().parseJsonAndGetMessage(sendRequest("forwardMessage", args));
}

Message::Ptr Api::sendPhoto(int32_t chatId, const InputFile::Ptr& photo, const string& caption, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const {
	vector<HttpReqArg> args;
	args.push_back(HttpReqArg("chat_id", chatId));
	args.push_back(HttpReqArg("photo", photo->data, true, photo->mimeType, photo->fileName));
	if (!caption.empty()) {
		args.push_back(HttpReqArg("caption", caption));
	}
	if (replyToMessageId) {
		args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId));
	}
	if (replyMarkup) {
		args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup)));
	}
	return TgTypeParser::getInstance().parseJsonAndGetMessage(sendRequest("sendPhoto", args));
}

Message::Ptr Api::sendPhoto(int32_t chatId, const string& photoId, const string& caption, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const {
	vector<HttpReqArg> args;
	args.push_back(HttpReqArg("chat_id", chatId));
	args.push_back(HttpReqArg("photo", photoId));
	if (!caption.empty()) {
		args.push_back(HttpReqArg("caption", caption));
	}
	if (replyToMessageId) {
		args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId));
	}
	if (replyMarkup) {
		args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup)));
	}
	return TgTypeParser::getInstance().parseJsonAndGetMessage(sendRequest("sendPhoto", args));
}

Message::Ptr Api::sendAudio(int32_t chatId, const InputFile::Ptr& audio, int32_t duration, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const {
	vector<HttpReqArg> args;
	args.push_back(HttpReqArg("chat_id", chatId));
	args.push_back(HttpReqArg("audio", audio->data, true, audio->mimeType, audio->fileName));
	if (duration) {
		args.push_back(HttpReqArg("duration", duration));
	}
	if (replyToMessageId) {
		args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId));
	}
	if (replyMarkup) {
		args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup)));
	}
	return TgTypeParser::getInstance().parseJsonAndGetMessage(sendRequest("sendAudio", args));
}

Message::Ptr Api::sendAudio(int32_t chatId, const string& audioId, int32_t duration, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const {
	vector<HttpReqArg> args;
	args.push_back(HttpReqArg("chat_id", chatId));
	args.push_back(HttpReqArg("audio", audioId));
	if (duration) {
		args.push_back(HttpReqArg("duration", duration));
	}
	if (replyToMessageId) {
		args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId));
	}
	if (replyMarkup) {
		args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup)));
	}
	return TgTypeParser::getInstance().parseJsonAndGetMessage(sendRequest("sendAudio", args));
}

Message::Ptr Api::sendDocument(int32_t chatId, const InputFile::Ptr& document, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const {
	vector<HttpReqArg> args;
	args.push_back(HttpReqArg("chat_id", chatId));
	args.push_back(HttpReqArg("document", document->data, true, document->mimeType, document->fileName));
	if (replyToMessageId) {
		args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId));
	}
	if (replyMarkup) {
		args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup)));
	}
	return TgTypeParser::getInstance().parseJsonAndGetMessage(sendRequest("sendDocument", args));
}

Message::Ptr Api::sendDocument(int32_t chatId, const string& document, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const {
	vector<HttpReqArg> args;
	args.push_back(HttpReqArg("chat_id", chatId));
	args.push_back(HttpReqArg("document", document));
	if (replyToMessageId) {
		args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId));
	}
	if (replyMarkup) {
		args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup)));
	}
	return TgTypeParser::getInstance().parseJsonAndGetMessage(sendRequest("sendDocument", args));
}

Message::Ptr Api::sendSticker(int32_t chatId, const InputFile::Ptr& sticker, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const {
	vector<HttpReqArg> args;
	args.push_back(HttpReqArg("chat_id", chatId));
	args.push_back(HttpReqArg("sticker", sticker->data, true, sticker->mimeType, sticker->fileName));
	if (replyToMessageId) {
		args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId));
	}
	if (replyMarkup) {
		args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup)));
	}
	return TgTypeParser::getInstance().parseJsonAndGetMessage(sendRequest("sendSticker", args));
}

Message::Ptr Api::sendSticker(int32_t chatId, const string& stickerId, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const {
	vector<HttpReqArg> args;
	args.push_back(HttpReqArg("chat_id", chatId));
	args.push_back(HttpReqArg("sticker", stickerId));
	if (replyToMessageId) {
		args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId));
	}
	if (replyMarkup) {
		args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup)));
	}
	return TgTypeParser::getInstance().parseJsonAndGetMessage(sendRequest("sendSticker", args));
}

Message::Ptr Api::sendVideo(int32_t chatId, const InputFile::Ptr& video, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const {
	vector<HttpReqArg> args;
	args.push_back(HttpReqArg("chat_id", chatId));
	args.push_back(HttpReqArg("video", video->data, true, video->mimeType, video->fileName));
	if (replyToMessageId) {
		args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId));
	}
	if (replyMarkup) {
		args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup)));
	}
	return TgTypeParser::getInstance().parseJsonAndGetMessage(sendRequest("sendVideo", args));
}

Message::Ptr Api::sendVideo(int32_t chatId, const string& videoId, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const {
	vector<HttpReqArg> args;
	args.push_back(HttpReqArg("chat_id", chatId));
	args.push_back(HttpReqArg("video", videoId));
	if (replyToMessageId) {
		args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId));
	}
	if (replyMarkup) {
		args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup)));
	}
	return TgTypeParser::getInstance().parseJsonAndGetMessage(sendRequest("sendVideo", args));
}

Message::Ptr Api::sendLocation(int32_t chatId, float latitude, float longitude, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const {
	vector<HttpReqArg> args;
	args.push_back(HttpReqArg("chat_id", chatId));
	args.push_back(HttpReqArg("latitude", latitude));
	args.push_back(HttpReqArg("longitude", longitude));
	if (replyToMessageId) {
		args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId));
	}
	if (replyMarkup) {
		args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup)));
	}
	return TgTypeParser::getInstance().parseJsonAndGetMessage(sendRequest("sendLocation", args));
}

void Api::sendChatAction(int32_t chatId, const string& action) const {
	vector<HttpReqArg> args;
	args.push_back(HttpReqArg("chat_id", chatId));
	args.push_back(HttpReqArg("action", action));
	sendRequest("sendChatAction", args);
}

UserProfilePhotos::Ptr Api::getUserProfilePhotos(int32_t userId, int32_t offset, int32_t limit) const {
	vector<HttpReqArg> args;
	args.push_back(HttpReqArg("user_id", userId));
	if (offset) {
		args.push_back(HttpReqArg("offset", offset));
	}
	limit = max(1, min(100, limit));
	args.push_back(HttpReqArg("limit", limit));
	return TgTypeParser::getInstance().parseJsonAndGetUserProfilePhotos(sendRequest("getUserProfilePhotos", args));
}

vector<Update::Ptr> Api::getUpdates(int32_t offset, int32_t limit, int32_t timeout) const {
	vector<HttpReqArg> args;
	if (offset) {
		args.push_back(HttpReqArg("offset", offset));
	}
	limit = max(1, min(100, limit));
	args.push_back(HttpReqArg("limit", limit));
	if (timeout) {
		args.push_back(HttpReqArg("timeout", timeout));
	}
	return TgTypeParser::getInstance().parseJsonAndGetArray<Update>(&TgTypeParser::parseJsonAndGetUpdate, sendRequest("getUpdates", args));
}

void Api::setWebhook(const string& url) const {
	vector<HttpReqArg> args;
	args.push_back(HttpReqArg("url", url));
	sendRequest("setWebhook", args);
}

ptree Api::sendRequest(const string& method, const vector<HttpReqArg>& args) const {

	string url = "https://api.telegram.org/bot";
	url += _token;
	url += "/";
	url += method;

	string serverResponse = HttpClient::getInstance().makeRequest(url, args);
	if (serverResponse.find("<html>") != serverResponse.npos) {
		throw TgException("tgbot-cpp library have got html page instead of json response. Maybe you entered wrong bot token.");
	}

	ptree result = TgTypeParser::getInstance().parseJson(serverResponse);
	try {
		if (result.get<bool>("ok", false)) {
			return result.get_child("result");
		} else {
			throw TgException(result.get("description", ""));
		}
	} catch (boost::property_tree::ptree_error& e) {
		throw TgException("tgbot-cpp library can't parse json response. " + string(e.what()));
	}
}

}
<|endoftext|>


<commit_before>/*
Copyright (c) 2016 Ingo Wald

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 "CompressedTile.h"

#if TURBO_JPEG
# include "turbojpeg.h"
# define JPEG_QUALITY 100
#endif

namespace ospray {
  namespace dw {

    struct CompressedTileHeader {
      box2i region;
      unsigned char payload[0];
    };

    CompressedTile::CompressedTile()
      : fromRank(-1),
        numBytes(-1),
        data(NULL)
    {}

    CompressedTile::~CompressedTile()
    {
      if (data) delete[] data;
    }

    void CompressedTile::encode(const PlainTile &tile)
    {
      assert(tile.pixel);
      const vec2i begin = tile.region.lower;
      const vec2i end = tile.region.upper;

      int numPixels = (end-begin).product();
      this->numBytes = sizeof(CompressedTileHeader)+numPixels*sizeof(int);
      this->data = new unsigned char[this->numBytes];
      assert(this->data != NULL);
      CompressedTileHeader *header = (CompressedTileHeader *)this->data;
      header->region.lower = begin;
      header->region.upper = end;

#if TURBO_JPEG
      tjhandle compressor = tjInitCompress();
      unsigned char *jpegBuffer = header->payload; //NULL;
      size_t jpegSize = numPixels*sizeof(int);
      int rc = tjCompress2(compressor, (const unsigned char *)tile.pixel,
                           tile.size().x,tile.pitch*sizeof(int),tile.size().y,
                           TJPF_BGRX, &jpegBuffer,&jpegSize,TJSAMP_444,JPEG_QUALITY,0);
      this->numBytes = jpegSize + sizeof(*header);
      printf("compress %i: %li->%li bytes\n",rc,numPixels*sizeof(int),jpegSize);
      tjDestroy(compressor);
#else
      uint32_t *out = (uint32_t *)header->payload;
      const uint32_t *in = (const uint32_t *)tile.pixel;
      for (uint32_t iy=begin.y;iy<end.y;iy++) {
        for (uint32_t ix=begin.x;ix<end.x;ix++) {
          *out++ = *in++;
        }

        in += (tile.pitch-(end.x-begin.x));
      }
#endif
    }

    void CompressedTile::decode(PlainTile &tile)
    {
      const CompressedTileHeader *header = (const CompressedTileHeader *)data;
      tile.region = header->region;
      vec2i size = tile.region.size();
      assert(tile.pixel != NULL);
#if TURBO_JPEG
      tjhandle decompressor = tjInitDecompress();
      size_t jpegSize = this->numBytes-sizeof(*header);
      int rc = tjDecompress2(decompressor, (const unsigned char *)header->payload,
                             this->numBytes-sizeof(*header),
                             (unsigned char*)tile.pixel,
                             size.x,tile.pitch*sizeof(int),size.y,
                             TJPF_BGRX, 0);
      printf("decompress %i: %i bytes\n",rc,this->numBytes);
      tjDestroy(decompressor);
#else
      uint32_t *out = tile.pixel;
      uint32_t *in = (uint32_t *)(data+sizeof(CompressedTileHeader));
      for (int iy=0;iy<size.y;iy++)
        for (int ix=0;ix<size.x;ix++) {
          *out++ = *in++;
        }
#endif
    }

    /*! get region that this tile corresponds to */
    box2i CompressedTile::getRegion() const
    {
      const CompressedTileHeader *header = (const CompressedTileHeader *)data;
      assert(header);
      return header->region;
    }

    /*! send the tile to the given rank in the given group */
    void CompressedTile::sendTo(const MPI::Group &group, const int rank) const
    {
      MPI_CALL(Send(data,numBytes,MPI_BYTE,rank,0,group.comm));
    }

    /*! receive one tile from the outside communicator */
    void CompressedTile::receiveOne(const MPI::Group &outside)
    {
      // printf("receiveone from outside %i/%i\n",outside.rank,outside.size);
      MPI_Status status;
      MPI_CALL(Probe(MPI_ANY_SOURCE,MPI_ANY_TAG,outside.comm,&status));
      fromRank = status.MPI_SOURCE;
      MPI_CALL(Get_count(&status,MPI_BYTE,&numBytes));
      // printf("incoming from %i, %i bytes\n",status.MPI_SOURCE,numBytes);
      data = new unsigned char[numBytes];
      MPI_CALL(Recv(data,numBytes,MPI_BYTE,status.MPI_SOURCE,status.MPI_TAG,
                    outside.comm,&status));
    }

  } // ::ospray::dw
} // ::ospray
<commit_msg>compile fix for linux; turbojpeg under linux uses uchar *, not const uchar *<commit_after>/*
Copyright (c) 2016 Ingo Wald

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 "CompressedTile.h"

#if TURBO_JPEG
# include "turbojpeg.h"
# define JPEG_QUALITY 100
#endif

namespace ospray {
  namespace dw {

    struct CompressedTileHeader {
      box2i region;
      unsigned char payload[0];
    };

    CompressedTile::CompressedTile()
      : fromRank(-1),
        numBytes(-1),
        data(NULL)
    {}

    CompressedTile::~CompressedTile()
    {
      if (data) delete[] data;
    }

    void CompressedTile::encode(const PlainTile &tile)
    {
      assert(tile.pixel);
      const vec2i begin = tile.region.lower;
      const vec2i end = tile.region.upper;

      int numPixels = (end-begin).product();
      this->numBytes = sizeof(CompressedTileHeader)+numPixels*sizeof(int);
      this->data = new unsigned char[this->numBytes];
      assert(this->data != NULL);
      CompressedTileHeader *header = (CompressedTileHeader *)this->data;
      header->region.lower = begin;
      header->region.upper = end;

#if TURBO_JPEG
      tjhandle compressor = tjInitCompress();
      unsigned char *jpegBuffer = header->payload; //NULL;
      size_t jpegSize = numPixels*sizeof(int);
      int rc = tjCompress2(compressor, (unsigned char *)tile.pixel,
                           tile.size().x,tile.pitch*sizeof(int),tile.size().y,
                           TJPF_BGRX, &jpegBuffer,&jpegSize,TJSAMP_444,JPEG_QUALITY,0);
      this->numBytes = jpegSize + sizeof(*header);
      printf("compress %i: %li->%li bytes\n",rc,numPixels*sizeof(int),jpegSize);
      tjDestroy(compressor);
#else
      uint32_t *out = (uint32_t *)header->payload;
      const uint32_t *in = (const uint32_t *)tile.pixel;
      for (uint32_t iy=begin.y;iy<end.y;iy++) {
        for (uint32_t ix=begin.x;ix<end.x;ix++) {
          *out++ = *in++;
        }

        in += (tile.pitch-(end.x-begin.x));
      }
#endif
    }

    void CompressedTile::decode(PlainTile &tile)
    {
      const CompressedTileHeader *header = (const CompressedTileHeader *)data;
      tile.region = header->region;
      vec2i size = tile.region.size();
      assert(tile.pixel != NULL);
#if TURBO_JPEG
      tjhandle decompressor = tjInitDecompress();
      size_t jpegSize = this->numBytes-sizeof(*header);
      int rc = tjDecompress2(decompressor, (unsigned char *)header->payload,
                             this->numBytes-sizeof(*header),
                             (unsigned char*)tile.pixel,
                             size.x,tile.pitch*sizeof(int),size.y,
                             TJPF_BGRX, 0);
      printf("decompress %i: %i bytes\n",rc,this->numBytes);
      tjDestroy(decompressor);
#else
      uint32_t *out = tile.pixel;
      uint32_t *in = (uint32_t *)(data+sizeof(CompressedTileHeader));
      for (int iy=0;iy<size.y;iy++)
        for (int ix=0;ix<size.x;ix++) {
          *out++ = *in++;
        }
#endif
    }

    /*! get region that this tile corresponds to */
    box2i CompressedTile::getRegion() const
    {
      const CompressedTileHeader *header = (const CompressedTileHeader *)data;
      assert(header);
      return header->region;
    }

    /*! send the tile to the given rank in the given group */
    void CompressedTile::sendTo(const MPI::Group &group, const int rank) const
    {
      MPI_CALL(Send(data,numBytes,MPI_BYTE,rank,0,group.comm));
    }

    /*! receive one tile from the outside communicator */
    void CompressedTile::receiveOne(const MPI::Group &outside)
    {
      // printf("receiveone from outside %i/%i\n",outside.rank,outside.size);
      MPI_Status status;
      MPI_CALL(Probe(MPI_ANY_SOURCE,MPI_ANY_TAG,outside.comm,&status));
      fromRank = status.MPI_SOURCE;
      MPI_CALL(Get_count(&status,MPI_BYTE,&numBytes));
      // printf("incoming from %i, %i bytes\n",status.MPI_SOURCE,numBytes);
      data = new unsigned char[numBytes];
      MPI_CALL(Recv(data,numBytes,MPI_BYTE,status.MPI_SOURCE,status.MPI_TAG,
                    outside.comm,&status));
    }

  } // ::ospray::dw
} // ::ospray
<|endoftext|>


<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Log$
 * Revision 1.8  2000/05/09 00:22:40  andyh
 * Memory Cleanup.  XMLPlatformUtils::Terminate() deletes all lazily
 * allocated memory; memory leak checking tools will no longer report
 * that leaks exist.  (DOM GetElementsByTagID temporarily removed
 * as part of this.)
 *
 * Revision 1.7  2000/03/24 19:50:29  roddey
 * Clear the 'initialized' flag when the termination call is made. Probably
 * not required technically, but...
 *
 * Revision 1.6  2000/03/02 19:54:44  roddey
 * This checkin includes many changes done while waiting for the
 * 1.1.0 code to be finished. I can't list them all here, but a list is
 * available elsewhere.
 *
 * Revision 1.5  2000/02/06 07:48:03  rahulj
 * Year 2K copyright swat.
 *
 * Revision 1.4  2000/01/19 00:56:59  roddey
 * Changes to get rid of dependence on old utils standard streams and to
 * get rid of the fgLibLocation stuff.
 *
 * Revision 1.3  1999/12/18 00:18:10  roddey
 * More changes to support the new, completely orthagonal support for
 * intrinsic encodings.
 *
 * Revision 1.2  1999/12/15 19:41:28  roddey
 * Support for the new transcoder system, where even intrinsic encodings are
 * done via the same transcoder abstraction as external ones.
 *
 * Revision 1.1.1.1  1999/11/09 01:04:53  twl
 * Initial checkin
 *
 * Revision 1.2  1999/11/08 20:45:11  rahul
 * Swat for adding in Product name and CVS comment log variable.
 *
 */

// ---------------------------------------------------------------------------
//  Includes
// ---------------------------------------------------------------------------
#include <util/XMLMsgLoader.hpp>
#include <util/Mutexes.hpp>
#include <util/PlatformUtils.hpp>
#include <util/RefVectorOf.hpp>
#include <util/TransService.hpp>
#include <util/XMLString.hpp>
#include <util/XMLNetAccessor.hpp>
#include <util/XMLUni.hpp>

// ---------------------------------------------------------------------------
//  Local data members
//
//  gSyncMutex
//      This is a mutex that will be used to synchronize access to some of
//      the static data of the platform utilities class and here locally.
// ---------------------------------------------------------------------------
static XMLMutex*                gSyncMutex = 0;
static RefVectorOf<XMLDeleter>* gLazyData;
static bool                     gInitFlag = false;

// ---------------------------------------------------------------------------
//  XMLPlatformUtils: Static Data Members
// ---------------------------------------------------------------------------
XMLNetAccessor*     XMLPlatformUtils::fgNetAccessor = 0;
XMLTransService*    XMLPlatformUtils::fgTransService = 0;

// ---------------------------------------------------------------------------
//  XMLPlatformUtils: Init/term methods
// ---------------------------------------------------------------------------
void XMLPlatformUtils::Initialize()
{
    //
    //  Make sure we haven't already been initialized. Note that this is not
    //  thread safe and is not intended for that. Its more for those COM
    //  like processes that cannot keep up with whether they have initialized
    //  us yet or not.
    //
    if (gInitFlag)
        return;
    gInitFlag = true;

    // Create the local sync mutex
    gSyncMutex = new XMLMutex;

    // Create the array for saving lazily allocated objects to be deleted at termination
    gLazyData= new RefVectorOf<XMLDeleter>(512);

    //
    //  Call the platform init method, which is implemented in each of the
    //  per-platform implementation cpp files. This one does the very low
    //  level per-platform setup. It cannot use any XML util services at all,
    //  i.e. only native services.
    //
    platformInit();

    //
    //  Ask the per-platform code to make the desired transcoding service for
    //  us to use. This call cannot throw any exceptions or do anything that
    //  cause any transcoding to happen. It should create the service and
    //  return it or zero if it cannot.
    //
    //  This one also cannot use any utility services. It can only create a
    //  transcoding service object and return it.
    //
    //  If we cannot make one, then we call panic to end the process.
    //
    fgTransService = makeTransService();
    if (!fgTransService)
        panic(Panic_NoTransService);

    // Initialize the transcoder service
    fgTransService->initTransService();

    //
    //  Try to create a default local code page transcoder. This is the one
    //  that will be used internally by the XMLString class. If we cannot
    //  create one, then call the panic method.
    //
    XMLLCPTranscoder* defXCode = XMLPlatformUtils::fgTransService->makeNewLCPTranscoder();
    if (!defXCode)
        panic(Panic_NoDefTranscoder);
    XMLString::initString(defXCode);

    //
    //  Now lets ask the per-platform code to give us an instance of the type
    //  of network access implementation he wants to use. This can return
    //  a zero pointer if this platform doesn't want to support this.
    //
    fgNetAccessor = makeNetAccessor();
}

void XMLPlatformUtils::Terminate()
{
    // Delete any net accessor that got installed
    delete fgNetAccessor;
    fgNetAccessor = 0;

    //
    //  Call the method that cleans up the registered lazy eval objects.
    //  This is all higher level code which might try to report errors if
    //  they have problems, so we want to do this before we hose our
    //  fundamental bits and pieces.
    //
    cleanupLazyData();

    //
    //  Call some other internal modules to give them a chance to clean up.
    //  Do the string class last in case something tries to use it during
    //  cleanup.
    //
    XMLString::termString();

    // Clean up the the transcoding service
    delete fgTransService;
    fgTransService = 0;

    // Clean up the sync mutex
    delete gSyncMutex;
    gSyncMutex = 0;

    //
    //  And do platform termination. This cannot do use any XML services
    //  at all, it can only clean up local stuff. It it reports an error,
    //  it cannot use any XML exception or error reporting services.
    //
    platformTerm();

    // And say we are no longer initialized
    gInitFlag = false;
}

// ---------------------------------------------------------------------------
//  XMLPlatformUtils: Msg support methods
// ---------------------------------------------------------------------------
XMLMsgLoader* XMLPlatformUtils::loadMsgSet(const XMLCh* const msgDomain)
{
    //
    //  Ask the platform support to load up the correct type of message
    //  loader for the indicated message set. We don't check here whether it
    //  works or not. That's their decision.
    //
    return loadAMsgSet(msgDomain);
}

// ---------------------------------------------------------------------------
//  XMLPlatformUtils: Lazy eval methods
// ---------------------------------------------------------------------------
void XMLPlatformUtils::registerLazyData(XMLDeleter* const deleter)
{
    // Just add a copy of this object to the vector. MUST be synchronized
    XMLMutexLock lock(gSyncMutex);
    gLazyData->addElement(deleter);
}

void XMLPlatformUtils::cleanupLazyData()
{
    //
    //  Loop through the vector and try to delete each object. Use a try
    //  block so that we don't fall out prematurely if one of them hoses.
    //  Note that we effectively do them in reverse order of their having
    //  been registered.
    //
    //  Also, note that we don't synchronize here because this is happening
    //  during shutdown.
    //
    while (gLazyData->size())
    {
        try
        {
            gLazyData->removeLastElement();
        }

        catch(...)
        {
            // We don't try to report errors here, just fall through
        }
    }
    delete gLazyData;
    gLazyData = 0;
}
<commit_msg>check if initialized in Terminate() to stop access violations submitted by John_Roper@iOra.com<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Log$
 * Revision 1.9  2000/06/26 20:30:04  jpolast
 * check if initialized in Terminate() to stop access violations
 * submitted by John_Roper@iOra.com
 *
 * Revision 1.8  2000/05/09 00:22:40  andyh
 * Memory Cleanup.  XMLPlatformUtils::Terminate() deletes all lazily
 * allocated memory; memory leak checking tools will no longer report
 * that leaks exist.  (DOM GetElementsByTagID temporarily removed
 * as part of this.)
 *
 * Revision 1.7  2000/03/24 19:50:29  roddey
 * Clear the 'initialized' flag when the termination call is made. Probably
 * not required technically, but...
 *
 * Revision 1.6  2000/03/02 19:54:44  roddey
 * This checkin includes many changes done while waiting for the
 * 1.1.0 code to be finished. I can't list them all here, but a list is
 * available elsewhere.
 *
 * Revision 1.5  2000/02/06 07:48:03  rahulj
 * Year 2K copyright swat.
 *
 * Revision 1.4  2000/01/19 00:56:59  roddey
 * Changes to get rid of dependence on old utils standard streams and to
 * get rid of the fgLibLocation stuff.
 *
 * Revision 1.3  1999/12/18 00:18:10  roddey
 * More changes to support the new, completely orthagonal support for
 * intrinsic encodings.
 *
 * Revision 1.2  1999/12/15 19:41:28  roddey
 * Support for the new transcoder system, where even intrinsic encodings are
 * done via the same transcoder abstraction as external ones.
 *
 * Revision 1.1.1.1  1999/11/09 01:04:53  twl
 * Initial checkin
 *
 * Revision 1.2  1999/11/08 20:45:11  rahul
 * Swat for adding in Product name and CVS comment log variable.
 *
 */

// ---------------------------------------------------------------------------
//  Includes
// ---------------------------------------------------------------------------
#include <util/XMLMsgLoader.hpp>
#include <util/Mutexes.hpp>
#include <util/PlatformUtils.hpp>
#include <util/RefVectorOf.hpp>
#include <util/TransService.hpp>
#include <util/XMLString.hpp>
#include <util/XMLNetAccessor.hpp>
#include <util/XMLUni.hpp>

// ---------------------------------------------------------------------------
//  Local data members
//
//  gSyncMutex
//      This is a mutex that will be used to synchronize access to some of
//      the static data of the platform utilities class and here locally.
// ---------------------------------------------------------------------------
static XMLMutex*                gSyncMutex = 0;
static RefVectorOf<XMLDeleter>* gLazyData;
static bool                     gInitFlag = false;

// ---------------------------------------------------------------------------
//  XMLPlatformUtils: Static Data Members
// ---------------------------------------------------------------------------
XMLNetAccessor*     XMLPlatformUtils::fgNetAccessor = 0;
XMLTransService*    XMLPlatformUtils::fgTransService = 0;

// ---------------------------------------------------------------------------
//  XMLPlatformUtils: Init/term methods
// ---------------------------------------------------------------------------
void XMLPlatformUtils::Initialize()
{
    //
    //  Make sure we haven't already been initialized. Note that this is not
    //  thread safe and is not intended for that. Its more for those COM
    //  like processes that cannot keep up with whether they have initialized
    //  us yet or not.
    //
    if (gInitFlag)
        return;
    gInitFlag = true;

    // Create the local sync mutex
    gSyncMutex = new XMLMutex;

    // Create the array for saving lazily allocated objects to be deleted at termination
    gLazyData= new RefVectorOf<XMLDeleter>(512);

    //
    //  Call the platform init method, which is implemented in each of the
    //  per-platform implementation cpp files. This one does the very low
    //  level per-platform setup. It cannot use any XML util services at all,
    //  i.e. only native services.
    //
    platformInit();

    //
    //  Ask the per-platform code to make the desired transcoding service for
    //  us to use. This call cannot throw any exceptions or do anything that
    //  cause any transcoding to happen. It should create the service and
    //  return it or zero if it cannot.
    //
    //  This one also cannot use any utility services. It can only create a
    //  transcoding service object and return it.
    //
    //  If we cannot make one, then we call panic to end the process.
    //
    fgTransService = makeTransService();
    if (!fgTransService)
        panic(Panic_NoTransService);

    // Initialize the transcoder service
    fgTransService->initTransService();

    //
    //  Try to create a default local code page transcoder. This is the one
    //  that will be used internally by the XMLString class. If we cannot
    //  create one, then call the panic method.
    //
    XMLLCPTranscoder* defXCode = XMLPlatformUtils::fgTransService->makeNewLCPTranscoder();
    if (!defXCode)
        panic(Panic_NoDefTranscoder);
    XMLString::initString(defXCode);

    //
    //  Now lets ask the per-platform code to give us an instance of the type
    //  of network access implementation he wants to use. This can return
    //  a zero pointer if this platform doesn't want to support this.
    //
    fgNetAccessor = makeNetAccessor();
}

void XMLPlatformUtils::Terminate()
{

	if (!gInitFlag)
		return;

    // Delete any net accessor that got installed
    delete fgNetAccessor;
    fgNetAccessor = 0;

    //
    //  Call the method that cleans up the registered lazy eval objects.
    //  This is all higher level code which might try to report errors if
    //  they have problems, so we want to do this before we hose our
    //  fundamental bits and pieces.
    //
    cleanupLazyData();

    //
    //  Call some other internal modules to give them a chance to clean up.
    //  Do the string class last in case something tries to use it during
    //  cleanup.
    //
    XMLString::termString();

    // Clean up the the transcoding service
    delete fgTransService;
    fgTransService = 0;

    // Clean up the sync mutex
    delete gSyncMutex;
    gSyncMutex = 0;

    //
    //  And do platform termination. This cannot do use any XML services
    //  at all, it can only clean up local stuff. It it reports an error,
    //  it cannot use any XML exception or error reporting services.
    //
    platformTerm();

    // And say we are no longer initialized
    gInitFlag = false;
}

// ---------------------------------------------------------------------------
//  XMLPlatformUtils: Msg support methods
// ---------------------------------------------------------------------------
XMLMsgLoader* XMLPlatformUtils::loadMsgSet(const XMLCh* const msgDomain)
{
    //
    //  Ask the platform support to load up the correct type of message
    //  loader for the indicated message set. We don't check here whether it
    //  works or not. That's their decision.
    //
    return loadAMsgSet(msgDomain);
}

// ---------------------------------------------------------------------------
//  XMLPlatformUtils: Lazy eval methods
// ---------------------------------------------------------------------------
void XMLPlatformUtils::registerLazyData(XMLDeleter* const deleter)
{
    // Just add a copy of this object to the vector. MUST be synchronized
    XMLMutexLock lock(gSyncMutex);
    gLazyData->addElement(deleter);
}

void XMLPlatformUtils::cleanupLazyData()
{
    //
    //  Loop through the vector and try to delete each object. Use a try
    //  block so that we don't fall out prematurely if one of them hoses.
    //  Note that we effectively do them in reverse order of their having
    //  been registered.
    //
    //  Also, note that we don't synchronize here because this is happening
    //  during shutdown.
    //
    while (gLazyData->size())
    {
        try
        {
            gLazyData->removeLastElement();
        }

        catch(...)
        {
            // We don't try to report errors here, just fall through
        }
    }
    delete gLazyData;
    gLazyData = 0;
}
<|endoftext|>


<commit_before>#include "../stdafx.h"

#include "wrapper/cms/signed_data.h"

Handle<CertificateCollection> SignedData::certificates(){
	LOGGER_FN();

	STACK_OF(X509) *certs;

	LOGGER_OPENSSL(CMS_get1_certs);
	certs = CMS_get1_certs(this->internal());

	return new CertificateCollection(certs);
}

Handle<Certificate> SignedData::certificates(int index){
	LOGGER_FN();

	return this->certificates()->items(index);
}

Handle<SignerCollection> SignedData::signers(){
	LOGGER_FN();

	stack_st_CMS_SignerInfo *signers_ = CMS_get0_SignerInfos(this->internal());

	return new SignerCollection(signers_, this->handle());
}

Handle<Signer> SignedData::signers(int index){
	LOGGER_FN();

	return this->signers()->items(index);
}

bool SignedData::isDetached(){
	LOGGER_FN();

	LOGGER_OPENSSL("CMS_is_detached");
	int res = CMS_is_detached(this->internal());

	if (res == -1){
		THROW_OPENSSL_EXCEPTION(0, SignedData, NULL, "CMS_is_detached");
	}

	return res == 1;
}

void SignedData::read(Handle<Bio> in, DataFormat::DATA_FORMAT format){
	LOGGER_FN();

	try{
		if (in.isEmpty()){
			THROW_EXCEPTION(0, SignedData, NULL, "Parameter %d cann't be NULL", 1);
		}

		CMS_ContentInfo *ci = NULL;

		in->reset();

		switch (format){
		case DataFormat::DER:
			LOGGER_OPENSSL(d2i_CMS_bio);
			ci = d2i_CMS_bio(in->internal(), NULL);
			if (ci == NULL){
				THROW_OPENSSL_EXCEPTION(0, SignedData, NULL, "d2i_CMS_bio");
			}

			LOGGER_OPENSSL(CMS_is_detached);
			if (ci && !CMS_is_detached(ci)){
				LOGGER_INFO("Get content from DER file");

				LOGGER_OPENSSL(CMS_get0_content);
				ASN1_OCTET_STRING *asn = (*CMS_get0_content(ci));
				if (asn == NULL){
					THROW_EXCEPTION(0, SignedData, NULL, "CMS_get0_content");
				}

				LOGGER_OPENSSL(BIO_new_mem_buf);
				Handle<Bio> content = new Bio(BIO_new_mem_buf(asn->data, asn->length));
				if (content->internal() == NULL){
					THROW_EXCEPTION(0, SignedData, NULL, "Error set content cms to BIO");
				}

				this->setContent(content);
			}

			break;
		case DataFormat::BASE64:
		{
			LOGGER_OPENSSL("PEM_read_bio_CMS");
			if ((ci = PEM_read_bio_CMS(in->internal(), NULL, NULL, NULL)) == NULL){
				THROW_OPENSSL_EXCEPTION(0, SignedData, NULL, "PEM_read_bio_CMS");
			};

			LOGGER_OPENSSL(CMS_is_detached);
			if (ci && !CMS_is_detached(ci)){
				LOGGER_INFO("Get content from DER file");

				ASN1_OCTET_STRING *asn = (*CMS_get0_content(ci));
				if (asn == NULL){
					THROW_EXCEPTION(0, SignedData, NULL, "CMS_get0_content");
				}

				Handle<Bio> content = new Bio(BIO_new_mem_buf(asn->data, asn->length));
				if (content->internal() == NULL){
					THROW_EXCEPTION(0, SignedData, NULL, "Error set content cms to BIO");
				}

				this->setContent(content);
			}

			break;
		}
		default:
			THROW_EXCEPTION(0, SignedData, NULL, ERROR_DATA_FORMAT_UNKNOWN_FORMAT, format);
		}

		if (!ci) {
			puts(OpenSSL::printErrors()->c_str());
			THROW_EXCEPTION(0, SignedData, NULL, "Can not read CMS signed data from BIO");
		}

		this->setData(ci);
	}
	catch (Handle<Exception> e){
		THROW_EXCEPTION(0, SignedData, e, "Error read cms");
	}
}

void SignedData::write(Handle<Bio> out, DataFormat::DATA_FORMAT format){
	LOGGER_FN();

	if (out.isEmpty())
		THROW_EXCEPTION(0, SignedData, NULL, "Parameter %d is NULL", 1);

	switch (format){
	case DataFormat::DER:

		LOGGER_OPENSSL("i2d_CMS_bio");
		if (i2d_CMS_bio(out->internal(), this->internal()) < 1)
			THROW_OPENSSL_EXCEPTION(0, SignedData, NULL, "i2d_CMS_bio", NULL);

		// LOGGER_OPENSSL("i2d_CMS_bio_stream");
		// if (i2d_CMS_bio_stream(out->internal(), this->internal(), this->content->internal(), flags) < 1)
		//   THROW_OPENSSL_EXCEPTION(0, SignedData, NULL, "i2d_CMS_bio_stream", NULL);

		break;
	case DataFormat::BASE64:
		LOGGER_OPENSSL("PEM_write_bio_CMS");
		if (PEM_write_bio_CMS(out->internal(), this->internal()) < 1)
			THROW_OPENSSL_EXCEPTION(0, SignedData, NULL, "PEM_write_bio_CMS", NULL);

		// LOGGER_OPENSSL("PEM_write_bio_CMS_stream");
		// if (PEM_write_bio_CMS_stream(out->internal(), this->internal(), this->content->internal(), flags) < 1)
		//   THROW_OPENSSL_EXCEPTION(0, SignedData, NULL, "PEM_write_bio_CMS_stream", NULL);

		break;

	default:
		THROW_EXCEPTION(0, SignedData, NULL, ERROR_DATA_FORMAT_UNKNOWN_FORMAT, format);
	}
}

Handle<Signer> SignedData::createSigner(Handle<Certificate> cert, Handle<Key> pkey){
	LOGGER_FN();

	const EVP_MD *md = EVP_get_digestbyname(cert->getSignatureDigest()->c_str());

	LOGGER_OPENSSL("CMS_add1_signer");
	CMS_SignerInfo *signer = CMS_add1_signer(this->internal(), cert->internal(), pkey->internal(), md, flags);
	if (!signer){
		THROW_OPENSSL_EXCEPTION(0, SignedData, NULL, "CMS_add1_signer");
	}

	return new Signer(signer, this->handle());
}

void SignedData::addCertificate(Handle<Certificate> cert){
	LOGGER_FN();

	Handle<Certificate> cert_copy = cert->duplicate();

	LOGGER_OPENSSL("CMS_add0_cert");
	if (CMS_add0_cert(this->internal(), cert_copy->internal()) < 1){
		THROW_EXCEPTION(0, SignedData, NULL, "Certificate already present");
	}

	cert_copy->setParent(this->handle());
}

void SignedData::setContent(Handle<Bio> value){
	LOGGER_FN();

	this->content = value;
}

Handle<Bio> SignedData::getContent(){
	LOGGER_FN();

	this->content->reset();
	return this->content;
}

bool SignedData::verify(Handle<CertificateCollection> certs){
	LOGGER_FN();
	int res;

	try {
		stack_st_X509 *pCerts = NULL;
		if (!certs.isEmpty()){
			pCerts = certs->internal();
		}

		//
		content->reset();

		X509_STORE *store = X509_STORE_new();

		LOGGER_OPENSSL("CMS_verify");
		res = CMS_verify(this->internal(), pCerts, store, content->internal(), NULL, flags);
		LOGGER_OPENSSL("X509_STORE_free");
		X509_STORE_free(store);

		return res == 1;
	}
	catch (Handle<Exception> e){
		THROW_EXCEPTION(0, SignedData, e, "Error CMS verify");
	}
}

Handle<SignedData> SignedData::sign(Handle<Certificate> cert, Handle<Key> pkey, Handle<CertificateCollection> certs, Handle<Bio> content, unsigned int flags){
	LOGGER_FN();

	LOGGER_OPENSSL("CMS_sign");
	CMS_ContentInfo *res = CMS_sign(cert->internal(), pkey->internal(), certs->internal(), content->internal(), flags);
	if (!res){
		THROW_OPENSSL_EXCEPTION(0, SignedData, NULL, "CMS_sign");
	}

	Handle<SignedData> sd = new SignedData(res);
	sd->flags = flags;

	return sd;
}

void SignedData::sign(){
	LOGGER_FN();

	if (!(flags & CMS_DETACHED)){
		CMS_set_detached(this->internal(), 0);
	}

	flags |= CMS_BINARY; /*Don't translate message to text*/

	LOGGER_OPENSSL("CMS_final");
	if (CMS_final(this->internal(), this->content->internal(), NULL, flags) < 1){
		THROW_OPENSSL_EXCEPTION(0, SignedData, NULL, "CMS_final");
	}
}

int SignedData::getFlags(){
	LOGGER_FN();

	return this->flags;
}

void SignedData::setFlags(int v){
	LOGGER_FN();

	this->flags = v;
}

void SignedData::addFlag(int v){
	LOGGER_FN();

	this->flags |= v;
}
void SignedData::removeFlags(int v){
	LOGGER_FN();

	this->flags ^= v;
}
<commit_msg>wrapper: revert b7c32e784e7e6d386829965cc0d3f632bb6b6842<commit_after>#include "../stdafx.h"

#include "wrapper/cms/signed_data.h"

Handle<CertificateCollection> SignedData::certificates(){
	LOGGER_FN();

	STACK_OF(X509) *certs;

	LOGGER_OPENSSL(CMS_get1_certs);
	certs = CMS_get1_certs(this->internal());

	return new CertificateCollection(certs);
}

Handle<Certificate> SignedData::certificates(int index){
	LOGGER_FN();

	return this->certificates()->items(index);
}

Handle<SignerCollection> SignedData::signers(){
	LOGGER_FN();

	stack_st_CMS_SignerInfo *signers_ = CMS_get0_SignerInfos(this->internal());

	return new SignerCollection(signers_, this->handle());
}

Handle<Signer> SignedData::signers(int index){
	LOGGER_FN();

	return this->signers()->items(index);
}

bool SignedData::isDetached(){
	LOGGER_FN();

	LOGGER_OPENSSL("CMS_is_detached");
	int res = CMS_is_detached(this->internal());

	if (res == -1){
		THROW_OPENSSL_EXCEPTION(0, SignedData, NULL, "CMS_is_detached");
	}

	return res == 1;
}

void SignedData::read(Handle<Bio> in, DataFormat::DATA_FORMAT format){
	LOGGER_FN();

	try{
		if (in.isEmpty()){
			THROW_EXCEPTION(0, SignedData, NULL, "Parameter %d cann't be NULL", 1);
		}

		CMS_ContentInfo *ci = NULL;

		in->reset();

		switch (format){
		case DataFormat::DER:
			LOGGER_OPENSSL(d2i_CMS_bio);
			ci = d2i_CMS_bio(in->internal(), NULL);
			if (ci == NULL){
				THROW_OPENSSL_EXCEPTION(0, SignedData, NULL, "d2i_CMS_bio");
			}

			LOGGER_OPENSSL(CMS_is_detached);
			if (ci && !CMS_is_detached(ci)){
				LOGGER_INFO("Get content from DER file");

				LOGGER_OPENSSL(CMS_get0_content);
				ASN1_OCTET_STRING *asn = (*CMS_get0_content(ci));
				if (asn == NULL){
					THROW_EXCEPTION(0, SignedData, NULL, "CMS_get0_content");
				}

				LOGGER_OPENSSL(BIO_new_mem_buf);
				Handle<Bio> content = new Bio(BIO_new_mem_buf(asn->data, asn->length));
				if (content->internal() == NULL){
					THROW_EXCEPTION(0, SignedData, NULL, "Error set content cms to BIO");
				}

				this->setContent(content);
			}

			break;
		case DataFormat::BASE64:
		{
			LOGGER_OPENSSL("PEM_read_bio_CMS");
			if ((ci = PEM_read_bio_CMS(in->internal(), NULL, NULL, NULL)) == NULL){
				THROW_OPENSSL_EXCEPTION(0, SignedData, NULL, "PEM_read_bio_CMS");
			};

			LOGGER_OPENSSL(CMS_is_detached);
			if (ci && !CMS_is_detached(ci)){
				LOGGER_INFO("Get content from DER file");

				ASN1_OCTET_STRING *asn = (*CMS_get0_content(ci));
				if (asn == NULL){
					THROW_EXCEPTION(0, SignedData, NULL, "CMS_get0_content");
				}

				Handle<Bio> content = new Bio(BIO_new_mem_buf(asn->data, asn->length));
				if (content->internal() == NULL){
					THROW_EXCEPTION(0, SignedData, NULL, "Error set content cms to BIO");
				}

				this->setContent(content);
			}

			break;
		}
		default:
			THROW_EXCEPTION(0, SignedData, NULL, ERROR_DATA_FORMAT_UNKNOWN_FORMAT, format);
		}

		if (!ci) {
			puts(OpenSSL::printErrors()->c_str());
			THROW_EXCEPTION(0, SignedData, NULL, "Can not read CMS signed data from BIO");
		}

		this->setData(ci);
	}
	catch (Handle<Exception> e){
		THROW_EXCEPTION(0, SignedData, e, "Error read cms");
	}
}

void SignedData::write(Handle<Bio> out, DataFormat::DATA_FORMAT format){
	LOGGER_FN();

	if (out.isEmpty())
		THROW_EXCEPTION(0, SignedData, NULL, "Parameter %d is NULL", 1);

	switch (format){
	case DataFormat::DER:

		LOGGER_OPENSSL("i2d_CMS_bio");
		if (i2d_CMS_bio(out->internal(), this->internal()) < 1)
			THROW_OPENSSL_EXCEPTION(0, SignedData, NULL, "i2d_CMS_bio", NULL);

		// LOGGER_OPENSSL("i2d_CMS_bio_stream");
		// if (i2d_CMS_bio_stream(out->internal(), this->internal(), this->content->internal(), flags) < 1)
		//   THROW_OPENSSL_EXCEPTION(0, SignedData, NULL, "i2d_CMS_bio_stream", NULL);

		break;
	case DataFormat::BASE64:
		LOGGER_OPENSSL("PEM_write_bio_CMS");
		if (PEM_write_bio_CMS(out->internal(), this->internal()) < 1)
			THROW_OPENSSL_EXCEPTION(0, SignedData, NULL, "PEM_write_bio_CMS", NULL);

		// LOGGER_OPENSSL("PEM_write_bio_CMS_stream");
		// if (PEM_write_bio_CMS_stream(out->internal(), this->internal(), this->content->internal(), flags) < 1)
		//   THROW_OPENSSL_EXCEPTION(0, SignedData, NULL, "PEM_write_bio_CMS_stream", NULL);

		break;

	default:
		THROW_EXCEPTION(0, SignedData, NULL, ERROR_DATA_FORMAT_UNKNOWN_FORMAT, format);
	}
}

Handle<Signer> SignedData::createSigner(Handle<Certificate> cert, Handle<Key> pkey){
	LOGGER_FN();

	int def_nid;
	LOGGER_OPENSSL("EVP_PKEY_get_default_digest_nid");
	if (EVP_PKEY_get_default_digest_nid(pkey->internal(), &def_nid) <= 0) {
		THROW_OPENSSL_EXCEPTION(0, SignedData, NULL, "Unknown digest name");

	}
	LOGGER_OPENSSL("EVP_PKEY_get_default_digest_nid");
	const EVP_MD *md = EVP_get_digestbynid(def_nid);
	if (md == NULL) {
		THROW_OPENSSL_EXCEPTION(0, SignedData, NULL, "No default digest");
	}

	LOGGER_OPENSSL("CMS_add1_signer");
	CMS_SignerInfo *signer = CMS_add1_signer(this->internal(), cert->internal(), pkey->internal(), md, flags);
	if (!signer){
		THROW_OPENSSL_EXCEPTION(0, SignedData, NULL, "CMS_add1_signer");
	}

	return new Signer(signer, this->handle());
}

void SignedData::addCertificate(Handle<Certificate> cert){
	LOGGER_FN();

	Handle<Certificate> cert_copy = cert->duplicate();

	LOGGER_OPENSSL("CMS_add0_cert");
	if (CMS_add0_cert(this->internal(), cert_copy->internal()) < 1){
		THROW_EXCEPTION(0, SignedData, NULL, "Certificate already present");
	}

	cert_copy->setParent(this->handle());
}

void SignedData::setContent(Handle<Bio> value){
	LOGGER_FN();

	this->content = value;
}

Handle<Bio> SignedData::getContent(){
	LOGGER_FN();

	this->content->reset();
	return this->content;
}

bool SignedData::verify(Handle<CertificateCollection> certs){
	LOGGER_FN();
	int res;

	try {
		stack_st_X509 *pCerts = NULL;
		if (!certs.isEmpty()){
			pCerts = certs->internal();
		}

		//
		content->reset();

		X509_STORE *store = X509_STORE_new();

		LOGGER_OPENSSL("CMS_verify");
		res = CMS_verify(this->internal(), pCerts, store, content->internal(), NULL, flags);
		LOGGER_OPENSSL("X509_STORE_free");
		X509_STORE_free(store);

		return res == 1;
	}
	catch (Handle<Exception> e){
		THROW_EXCEPTION(0, SignedData, e, "Error CMS verify");
	}
}

Handle<SignedData> SignedData::sign(Handle<Certificate> cert, Handle<Key> pkey, Handle<CertificateCollection> certs, Handle<Bio> content, unsigned int flags){
	LOGGER_FN();

	LOGGER_OPENSSL("CMS_sign");
	CMS_ContentInfo *res = CMS_sign(cert->internal(), pkey->internal(), certs->internal(), content->internal(), flags);
	if (!res){
		THROW_OPENSSL_EXCEPTION(0, SignedData, NULL, "CMS_sign");
	}

	Handle<SignedData> sd = new SignedData(res);
	sd->flags = flags;

	return sd;
}

void SignedData::sign(){
	LOGGER_FN();

	if (!(flags & CMS_DETACHED)){
		CMS_set_detached(this->internal(), 0);
	}

	flags |= CMS_BINARY; /*Don't translate message to text*/

	LOGGER_OPENSSL("CMS_final");
	if (CMS_final(this->internal(), this->content->internal(), NULL, flags) < 1){
		THROW_OPENSSL_EXCEPTION(0, SignedData, NULL, "CMS_final");
	}
}

int SignedData::getFlags(){
	LOGGER_FN();

	return this->flags;
}

void SignedData::setFlags(int v){
	LOGGER_FN();

	this->flags = v;
}

void SignedData::addFlag(int v){
	LOGGER_FN();

	this->flags |= v;
}
void SignedData::removeFlags(int v){
	LOGGER_FN();

	this->flags ^= v;
}
<|endoftext|>


<commit_before>#include"ics3/eeprom.hpp"

#include"ics3/eepparam.hpp"

#include<stdexcept>

ics::EepParam ics::Eeprom::get(EepParam place) const {
  place.read(data);
  return place;
}

void ics::Eeprom::set(const EepParam& param) noexcept {
  param.write(data);
}

ics::Eeprom::Eeprom(const std::array<unsigned char, 64>& src)
: data {src}
{}
<commit_msg>Update eeprom for ubuntu14.04<commit_after>#include"ics3/eeprom.hpp"

#include"ics3/eepparam.hpp"

#include<stdexcept>
#include<algorithm>

ics::EepParam ics::Eeprom::get(EepParam place) const {
  place.read(data);
  return place;
}

void ics::Eeprom::set(const EepParam& param) noexcept {
  param.write(data);
}

ics::Eeprom::Eeprom(const std::array<unsigned char, 64>& src)
: data {}
{
  std::copy(src.begin(), src.end(), data.begin());
}
<|endoftext|>


<commit_before>#include "network.h"
#include "chip.h"
#include "debug.h"
//#define NETWORK_DEBUG
using namespace std;

Network::Network(Core *the_core_arg, int num_mod)
  :
      net_queue(new NetQueue* [num_mod]),
      transport(new Transport),
      the_core(the_core_arg),
      net_num_mod(num_mod)
//Network::Network(int tid, int num_mod, Core* the_core_arg)
{
   int i;
   int num_pac_type = MAX_PACKET_TYPE - MIN_PACKET_TYPE + 1;

   the_core = the_core_arg;
   net_tid = the_core->getRank(); //FIXME network needs a unique id to provide debugging
   net_num_mod = g_config->totalMods();

   transport->ptInit(the_core->getId(), num_mod);
//   transport->ptInit(the_core->getRank(), num_mod);

   for(i = 0; i < net_num_mod; i++)
   {
      net_queue[i] = new NetQueue [num_pac_type];
   }

   callbacks = new NetworkCallback [num_pac_type];

   for(i = 0; i < num_pac_type; i++)
      callbacks[i] = NULL;

   callback_objs = new void* [num_pac_type];
   assert(callbacks != NULL);
   assert(callback_objs != NULL);
}

Network::~Network()
{
   delete [] callback_objs;
   delete [] callbacks;

   for (int i = 0; i < net_num_mod; i++)
      {
         delete [] net_queue[i];
      }
   delete [] net_queue;

   delete transport;
}

void Network::netCheckMessages()
{
   assert(false);
}

int Network::netSend(NetPacket packet)
{
   char *buffer;
   UInt32 buf_size;

   the_core->lockClock();
   UINT64 time = the_core->getProcTime() + netLatency(packet) + netProcCost(packet);
   the_core->unlockClock();

   buffer = netCreateBuf(packet, &buf_size, time);
   transport->ptSend(packet.receiver, buffer, buf_size);

   the_core->lockClock();
   the_core->setProcTime(the_core->getProcTime() + netProcCost(packet));
   the_core->unlockClock();

   // FIXME?: Should we be returning buf_size instead?
   return packet.length;
}

void Network::printNetPacket(NetPacket packet) {
	stringstream ss;
	ss << endl;
	ss << "printNetPacket: DON'T CALL ME" << endl;
	debugPrint (net_tid, "NETWORK", ss.str());
}

int Network::netSendMagic(NetPacket packet)
{
   char *buffer;
   UInt32 buf_size;

   the_core->lockClock();
   UINT64 time = the_core->getProcTime();
   the_core->unlockClock();

   buffer = netCreateBuf(packet, &buf_size, time);
   transport->ptSend(packet.receiver, buffer, buf_size);

   // FIXME?: Should we be returning buf_size instead?
   return packet.length;
}

NetPacket Network::netRecvMagic(NetMatch match)
{
   return netRecv(match);
}

NetPacket Network::netRecv(NetMatch match)
{
   NetPacket packet;
   NetQueueEntry entry;
   bool loop = true;

   int num_pac_type = MAX_PACKET_TYPE - MIN_PACKET_TYPE + 1;

   int sender_start = 0;
   int sender_end = net_num_mod;

   int type_start = 0;
   int type_end = num_pac_type;

   if(match.sender_flag)
   {
       assert(0 <= match.sender && match.sender < net_num_mod);
       sender_start = match.sender;
       sender_end = sender_start + 1;
   }

   if(match.type_flag)
   {
       assert(0 <= match.type && match.type < MAX_PACKET_TYPE - MIN_PACKET_TYPE + 1);
       type_start = match.type;
       type_end = type_start + 1;
   }

   while(loop)
   {
      // Initialized to garbage values
      entry.time = 0;

      for(int i = sender_start; i < sender_end; i++)
      {
          for(int j = type_start; j < type_end; j++)
          {
				 net_queue [ i ][ j ] . lock ();

				 if( !(net_queue[i][j].empty()) )
				 {
					 if((entry.time == 0) || (entry.time > net_queue[i][j].top().time))
					 {
						 entry = net_queue[i][j].top();
						 loop = false;
					 }
				 }

				 net_queue [ i ][ j ] . unlock ();
          }
      }

      // No valid packets found in our queue, wait for the
      // "network manager" thread to wake us up
      if ( loop )
		{
			waitForUserPacket();
		};
   }

   assert(0 <= entry.packet.sender && entry.packet.sender < net_num_mod);
   assert(0 <= entry.packet.type && entry.packet.type < MAX_PACKET_TYPE - MIN_PACKET_TYPE + 1);

   // FIXME: Will the reference stay the same (Note this is a priority queue)??
	net_queue[entry.packet.sender][entry.packet.type].lock();
   net_queue[entry.packet.sender][entry.packet.type].pop();
   net_queue[entry.packet.sender][entry.packet.type].unlock();

   packet = entry.packet;

   //Atomically update the time
   the_core->lockClock();
   if(the_core->getProcTime() < entry.time)
      the_core->setProcTime(entry.time);
   the_core->unlockClock();

   return packet;
}

void Network::printNetMatch(NetMatch match, int receiver) {
	stringstream ss;
	ss << endl;
	ss << "Network Match "
		<< match.sender << " -> " << receiver
		<< " SenderFlag: " << match.sender_flag
		<< " Type: " << packetTypeToString(match.type)
		<< " TypeFlag: " << match.type_flag
		<< "----";
	debugPrint (net_tid, "NETWORK", ss.str());

}

string Network::packetTypeToString(PacketType type)
{
  switch(type) {
  case INVALID:
    return "INVALID                     ";
  case USER:
    return "USER                        ";
  case SHARED_MEM_REQ:
    return "SHARED_MEM_REQ              ";
  case SHARED_MEM_RESPONSE:
    return "SHARED_MEM_RESPONSE	        ";
  case SHARED_MEM_UPDATE_UNEXPECTED:
    return "SHARED_MEM_UPDATE_UNEXPECTED";
  case SHARED_MEM_ACK:
    return "SHARED_MEM_ACK              ";
  case SHARED_MEM_EVICT:
    return "SHARED_MEM_EVICT            ";
  case MCP_REQUEST_TYPE:
    return "MCP_REQUEST_TYPE		";
  case MCP_RESPONSE_TYPE:
    return "MCP_RESPONSE_TYPE           ";
  default:
    return "ERROR in PacketTypeToString";
  }
  return "ERROR in PacketTypeToString";
}

int Network::netSendToMCP(const char *buf, unsigned int len, bool is_magic)
{
   NetPacket packet;
   packet.sender = netCommID();
   packet.receiver = g_config->totalMods() - 1;
   packet.length = len;
   packet.type = MCP_REQUEST_TYPE;

   //FIXME: This is bad casting away constness
   packet.data = (char *)buf;

   if(is_magic)
      return netSendMagic(packet);
   else
      return netSend(packet);
}

NetPacket Network::netRecvFromMCP()
{
   NetMatch match;
   match.sender = g_config->totalMods() - 1;
   match.sender_flag = true;
   match.type = MCP_RESPONSE_TYPE;
   match.type_flag = true;
   return netRecv(match);
}

int Network::netMCPSend(int commid, const char *buf, unsigned int len, bool is_magic)
{
   NetPacket packet;
   packet.sender = g_config->totalMods() - 1;
   packet.receiver = commid;
   packet.length = len;
   packet.type = MCP_RESPONSE_TYPE;

   //FIXME: This is bad casting away constness
   packet.data = (char *)buf;
   if(is_magic)
      return netSendMagic(packet);
   else
      return netSend(packet);
}

NetPacket Network::netMCPRecv()
{
   NetMatch match;
   match.sender_flag = false;
   match.type = MCP_REQUEST_TYPE;
   match.type_flag = true;
   return netRecv(match);
}

bool Network::netQuery(NetMatch match)
{
   NetQueueEntry entry;
   bool found = false;

   the_core->lockClock();
   entry.time = the_core->getProcTime();
   the_core->unlockClock();

   int num_pac_type = MAX_PACKET_TYPE - MIN_PACKET_TYPE + 1;

   int sender_start = 0;
   int sender_end = net_num_mod;

   int type_start = 0;
   int type_end = num_pac_type;

   if(match.sender_flag)
   {
       assert(0 <= match.sender && match.sender < net_num_mod);
       sender_start = match.sender;
       sender_end = sender_start + 1;
   }

   if(match.type_flag)
   {
       assert(0 <= match.type && match.type < MAX_PACKET_TYPE - MIN_PACKET_TYPE + 1);
       type_start = match.type;
       type_end = type_start + 1;
   }

   for(int i = sender_start; i < sender_end; i++)
   {
       for(int j = type_start; j < type_end; j++)
       {
			 //net_queue[i][j].lock();

           if(!net_queue[i][j].empty() && entry.time >= net_queue[i][j].top().time)
           {
               found = true;
               break;
           }

			 //net_queue[i][j].unlock();
       }
   }

   return found;
}

char* Network::netCreateBuf(NetPacket packet, UInt32* buffer_size, UINT64 time)
{
   char *buffer;

   *buffer_size = sizeof(packet.type) + sizeof(packet.sender) +
                     sizeof(packet.receiver) + sizeof(packet.length) +
                     packet.length + sizeof(time);

   buffer = new char [*buffer_size];

   char *dest = buffer;

   memcpy(dest, (char*)&packet.type, sizeof(packet.type));
   dest += sizeof(packet.type);

   memcpy(dest, (char*)&packet.sender, sizeof(packet.sender));
   dest += sizeof(packet.sender);

   memcpy(dest, (char*)&packet.receiver, sizeof(packet.receiver));
   dest += sizeof(packet.receiver);

   memcpy(dest, (char*)&packet.length, sizeof(packet.length));
   dest += sizeof(packet.length);

   memcpy(dest, (char*)packet.data, packet.length);
   dest += packet.length;

   memcpy(dest, (char*)&time, sizeof(time));
   dest += sizeof(time);

   return buffer;
}

void Network::netExPacket(char *buffer, NetPacket &packet, UINT64 &time)
{
   char *ptr = buffer;

   memcpy((char *) &packet.type, ptr, sizeof(packet.type));
   ptr += sizeof(packet.type);

   memcpy((char *) &packet.sender, ptr, sizeof(packet.sender));
   ptr += sizeof(packet.sender);

   memcpy((char *) &packet.receiver, ptr, sizeof(packet.receiver));
   ptr += sizeof(packet.receiver);

   memcpy((char *) &packet.length, ptr, sizeof(packet.length));
   ptr += sizeof(packet.length);

   packet.data = new char[packet.length];

   memcpy((char *) packet.data, ptr, packet.length);
   ptr += packet.length;

   memcpy((char *) &time, ptr, sizeof(time));
   ptr += sizeof(time);

   // HK
   // De-allocate dynamic memory
   delete [] buffer;
}

void Network::netPullFromTransport()
{
	// HK
	// FIXME
	// The clock updation model for interrupts could be made smarter

   // These are a set of tasks to be performed every time the SMEM layer is
   // entered
   char *buffer;
   NetQueueEntry entry;

	// Pull up packets waiting in the physical transport layer
   while(transport->ptQuery()) {
      buffer = transport->ptRecv();
      Network::netExPacket(buffer, entry.packet, entry.time);
      assert(0 <= entry.packet.sender && entry.packet.sender < net_num_mod);
      assert(0 <= entry.packet.type && entry.packet.type < MAX_PACKET_TYPE - MIN_PACKET_TYPE + 1);

      // asynchronous I/O support
      assert((unsigned int)entry.packet.type <= MAX_PACKET_TYPE);
      NetworkCallback callback = callbacks[entry.packet.type];

      if (callback != NULL)
         {
            assert(0 <= entry.packet.sender && entry.packet.sender < net_num_mod);
            assert(MIN_PACKET_TYPE <= entry.packet.type && entry.packet.type <= MAX_PACKET_TYPE);

            the_core->lockClock();
            if(the_core->getProcTime() < entry.time)
               {
                  the_core->setProcTime(entry.time);
               }
            the_core->unlockClock();

            callback(callback_objs[entry.packet.type], entry.packet);
         }

      // synchronous I/O support
      else
         {
            // TODO: Performance Consideration
            // We need to lock only when 'entry.packet.type' is one of the following:
            // 1) USER
            // 2) SHARED_MEM_RESPONSE
            // 3) MCP_NETWORK_TYPE
            net_queue[entry.packet.sender][entry.packet.type].lock();
            net_queue[entry.packet.sender][entry.packet.type].push(entry);
            net_queue[entry.packet.sender][entry.packet.type].unlock();
         }
   }
}

void Network::registerCallback(PacketType type, NetworkCallback callback, void *obj)
{
   assert((unsigned int)type <= MAX_PACKET_TYPE);
   callbacks[type] = callback;
   callback_objs[type] = obj;
}

void Network::unregisterCallback(PacketType type)
{
   assert((unsigned int)type <= MAX_PACKET_TYPE);
   callbacks[type] = NULL;
}

void Network::waitForUserPacket()
{

}

void Network::notifyWaitingUserThread()
{

}

UINT64 Network::netProcCost(NetPacket packet)
{
      return 0;
};

UINT64 Network::netLatency(NetPacket packet)
{
      return 30;
};

<commit_msg>[network] Add warning to netQuery saying that it does not work.<commit_after>#include "network.h"
#include "chip.h"
#include "debug.h"
//#define NETWORK_DEBUG
using namespace std;

Network::Network(Core *the_core_arg, int num_mod)
  :
      net_queue(new NetQueue* [num_mod]),
      transport(new Transport),
      the_core(the_core_arg),
      net_num_mod(num_mod)
//Network::Network(int tid, int num_mod, Core* the_core_arg)
{
   int i;
   int num_pac_type = MAX_PACKET_TYPE - MIN_PACKET_TYPE + 1;

   the_core = the_core_arg;
   net_tid = the_core->getRank(); //FIXME network needs a unique id to provide debugging
   net_num_mod = g_config->totalMods();

   transport->ptInit(the_core->getId(), num_mod);
//   transport->ptInit(the_core->getRank(), num_mod);

   for(i = 0; i < net_num_mod; i++)
   {
      net_queue[i] = new NetQueue [num_pac_type];
   }

   callbacks = new NetworkCallback [num_pac_type];

   for(i = 0; i < num_pac_type; i++)
      callbacks[i] = NULL;

   callback_objs = new void* [num_pac_type];
   assert(callbacks != NULL);
   assert(callback_objs != NULL);
}

Network::~Network()
{
   delete [] callback_objs;
   delete [] callbacks;

   for (int i = 0; i < net_num_mod; i++)
      {
         delete [] net_queue[i];
      }
   delete [] net_queue;

   delete transport;
}

void Network::netCheckMessages()
{
   assert(false);
}

int Network::netSend(NetPacket packet)
{
   char *buffer;
   UInt32 buf_size;

   the_core->lockClock();
   UINT64 time = the_core->getProcTime() + netLatency(packet) + netProcCost(packet);
   the_core->unlockClock();

   buffer = netCreateBuf(packet, &buf_size, time);
   transport->ptSend(packet.receiver, buffer, buf_size);

   the_core->lockClock();
   the_core->setProcTime(the_core->getProcTime() + netProcCost(packet));
   the_core->unlockClock();

   // FIXME?: Should we be returning buf_size instead?
   return packet.length;
}

void Network::printNetPacket(NetPacket packet) {
	stringstream ss;
	ss << endl;
	ss << "printNetPacket: DON'T CALL ME" << endl;
	debugPrint (net_tid, "NETWORK", ss.str());
}

int Network::netSendMagic(NetPacket packet)
{
   char *buffer;
   UInt32 buf_size;

   the_core->lockClock();
   UINT64 time = the_core->getProcTime();
   the_core->unlockClock();

   buffer = netCreateBuf(packet, &buf_size, time);
   transport->ptSend(packet.receiver, buffer, buf_size);

   // FIXME?: Should we be returning buf_size instead?
   return packet.length;
}

NetPacket Network::netRecvMagic(NetMatch match)
{
   return netRecv(match);
}

NetPacket Network::netRecv(NetMatch match)
{
   NetPacket packet;
   NetQueueEntry entry;
   bool loop = true;

   int num_pac_type = MAX_PACKET_TYPE - MIN_PACKET_TYPE + 1;

   int sender_start = 0;
   int sender_end = net_num_mod;

   int type_start = 0;
   int type_end = num_pac_type;

   if(match.sender_flag)
   {
       assert(0 <= match.sender && match.sender < net_num_mod);
       sender_start = match.sender;
       sender_end = sender_start + 1;
   }

   if(match.type_flag)
   {
       assert(0 <= match.type && match.type < MAX_PACKET_TYPE - MIN_PACKET_TYPE + 1);
       type_start = match.type;
       type_end = type_start + 1;
   }

   while(loop)
   {
      // Initialized to garbage values
      entry.time = 0;

      for(int i = sender_start; i < sender_end; i++)
      {
          for(int j = type_start; j < type_end; j++)
          {
				 net_queue [ i ][ j ] . lock ();

				 if( !(net_queue[i][j].empty()) )
				 {
					 if((entry.time == 0) || (entry.time > net_queue[i][j].top().time))
					 {
						 entry = net_queue[i][j].top();
						 loop = false;
					 }
				 }

				 net_queue [ i ][ j ] . unlock ();
          }
      }

      // No valid packets found in our queue, wait for the
      // "network manager" thread to wake us up
      if ( loop )
		{
			waitForUserPacket();
		};
   }

   assert(0 <= entry.packet.sender && entry.packet.sender < net_num_mod);
   assert(0 <= entry.packet.type && entry.packet.type < MAX_PACKET_TYPE - MIN_PACKET_TYPE + 1);

   // FIXME: Will the reference stay the same (Note this is a priority queue)??
	net_queue[entry.packet.sender][entry.packet.type].lock();
   net_queue[entry.packet.sender][entry.packet.type].pop();
   net_queue[entry.packet.sender][entry.packet.type].unlock();

   packet = entry.packet;

   //Atomically update the time
   the_core->lockClock();
   if(the_core->getProcTime() < entry.time)
      the_core->setProcTime(entry.time);
   the_core->unlockClock();

   return packet;
}

void Network::printNetMatch(NetMatch match, int receiver) {
	stringstream ss;
	ss << endl;
	ss << "Network Match "
		<< match.sender << " -> " << receiver
		<< " SenderFlag: " << match.sender_flag
		<< " Type: " << packetTypeToString(match.type)
		<< " TypeFlag: " << match.type_flag
		<< "----";
	debugPrint (net_tid, "NETWORK", ss.str());

}

string Network::packetTypeToString(PacketType type)
{
  switch(type) {
  case INVALID:
    return "INVALID                     ";
  case USER:
    return "USER                        ";
  case SHARED_MEM_REQ:
    return "SHARED_MEM_REQ              ";
  case SHARED_MEM_RESPONSE:
    return "SHARED_MEM_RESPONSE	        ";
  case SHARED_MEM_UPDATE_UNEXPECTED:
    return "SHARED_MEM_UPDATE_UNEXPECTED";
  case SHARED_MEM_ACK:
    return "SHARED_MEM_ACK              ";
  case SHARED_MEM_EVICT:
    return "SHARED_MEM_EVICT            ";
  case MCP_REQUEST_TYPE:
    return "MCP_REQUEST_TYPE		";
  case MCP_RESPONSE_TYPE:
    return "MCP_RESPONSE_TYPE           ";
  default:
    return "ERROR in PacketTypeToString";
  }
  return "ERROR in PacketTypeToString";
}

int Network::netSendToMCP(const char *buf, unsigned int len, bool is_magic)
{
   NetPacket packet;
   packet.sender = netCommID();
   packet.receiver = g_config->totalMods() - 1;
   packet.length = len;
   packet.type = MCP_REQUEST_TYPE;

   //FIXME: This is bad casting away constness
   packet.data = (char *)buf;

   if(is_magic)
      return netSendMagic(packet);
   else
      return netSend(packet);
}

NetPacket Network::netRecvFromMCP()
{
   NetMatch match;
   match.sender = g_config->totalMods() - 1;
   match.sender_flag = true;
   match.type = MCP_RESPONSE_TYPE;
   match.type_flag = true;
   return netRecv(match);
}

int Network::netMCPSend(int commid, const char *buf, unsigned int len, bool is_magic)
{
   NetPacket packet;
   packet.sender = g_config->totalMods() - 1;
   packet.receiver = commid;
   packet.length = len;
   packet.type = MCP_RESPONSE_TYPE;

   //FIXME: This is bad casting away constness
   packet.data = (char *)buf;
   if(is_magic)
      return netSendMagic(packet);
   else
      return netSend(packet);
}

NetPacket Network::netMCPRecv()
{
   NetMatch match;
   match.sender_flag = false;
   match.type = MCP_REQUEST_TYPE;
   match.type_flag = true;
   return netRecv(match);
}

bool Network::netQuery(NetMatch match)
{
   // FIXME: !!WARNING!! It appears that this function does not work.
   assert(false);

   NetQueueEntry entry;
   bool found = false;

   the_core->lockClock();
   entry.time = the_core->getProcTime();
   the_core->unlockClock();

   int num_pac_type = MAX_PACKET_TYPE - MIN_PACKET_TYPE + 1;

   int sender_start = 0;
   int sender_end = net_num_mod;

   int type_start = 0;
   int type_end = num_pac_type;

   if(match.sender_flag)
   {
       assert(0 <= match.sender && match.sender < net_num_mod);
       sender_start = match.sender;
       sender_end = sender_start + 1;
   }

   if(match.type_flag)
   {
       assert(0 <= match.type && match.type < MAX_PACKET_TYPE - MIN_PACKET_TYPE + 1);
       type_start = match.type;
       type_end = type_start + 1;
   }

   for(int i = sender_start; i < sender_end; i++)
   {
       for(int j = type_start; j < type_end; j++)
       {
           net_queue[i][j].lock();

           if(!net_queue[i][j].empty() && entry.time >= net_queue[i][j].top().time)
           {
               found = true;
               break;
           }

           net_queue[i][j].unlock();
       }
   }

   return found;
}

char* Network::netCreateBuf(NetPacket packet, UInt32* buffer_size, UINT64 time)
{
   char *buffer;

   *buffer_size = sizeof(packet.type) + sizeof(packet.sender) +
                     sizeof(packet.receiver) + sizeof(packet.length) +
                     packet.length + sizeof(time);

   buffer = new char [*buffer_size];

   char *dest = buffer;

   memcpy(dest, (char*)&packet.type, sizeof(packet.type));
   dest += sizeof(packet.type);

   memcpy(dest, (char*)&packet.sender, sizeof(packet.sender));
   dest += sizeof(packet.sender);

   memcpy(dest, (char*)&packet.receiver, sizeof(packet.receiver));
   dest += sizeof(packet.receiver);

   memcpy(dest, (char*)&packet.length, sizeof(packet.length));
   dest += sizeof(packet.length);

   memcpy(dest, (char*)packet.data, packet.length);
   dest += packet.length;

   memcpy(dest, (char*)&time, sizeof(time));
   dest += sizeof(time);

   return buffer;
}

void Network::netExPacket(char *buffer, NetPacket &packet, UINT64 &time)
{
   char *ptr = buffer;

   memcpy((char *) &packet.type, ptr, sizeof(packet.type));
   ptr += sizeof(packet.type);

   memcpy((char *) &packet.sender, ptr, sizeof(packet.sender));
   ptr += sizeof(packet.sender);

   memcpy((char *) &packet.receiver, ptr, sizeof(packet.receiver));
   ptr += sizeof(packet.receiver);

   memcpy((char *) &packet.length, ptr, sizeof(packet.length));
   ptr += sizeof(packet.length);

   packet.data = new char[packet.length];

   memcpy((char *) packet.data, ptr, packet.length);
   ptr += packet.length;

   memcpy((char *) &time, ptr, sizeof(time));
   ptr += sizeof(time);

   // HK
   // De-allocate dynamic memory
   delete [] buffer;
}

void Network::netPullFromTransport()
{
	// HK
	// FIXME
	// The clock updation model for interrupts could be made smarter

   // These are a set of tasks to be performed every time the SMEM layer is
   // entered
   char *buffer;
   NetQueueEntry entry;

	// Pull up packets waiting in the physical transport layer
   while(transport->ptQuery()) {
      buffer = transport->ptRecv();
      Network::netExPacket(buffer, entry.packet, entry.time);
      assert(0 <= entry.packet.sender && entry.packet.sender < net_num_mod);
      assert(0 <= entry.packet.type && entry.packet.type < MAX_PACKET_TYPE - MIN_PACKET_TYPE + 1);

      // asynchronous I/O support
      assert((unsigned int)entry.packet.type <= MAX_PACKET_TYPE);
      NetworkCallback callback = callbacks[entry.packet.type];

      if (callback != NULL)
         {
            assert(0 <= entry.packet.sender && entry.packet.sender < net_num_mod);
            assert(MIN_PACKET_TYPE <= entry.packet.type && entry.packet.type <= MAX_PACKET_TYPE);

            the_core->lockClock();
            if(the_core->getProcTime() < entry.time)
               {
                  the_core->setProcTime(entry.time);
               }
            the_core->unlockClock();

            callback(callback_objs[entry.packet.type], entry.packet);
         }

      // synchronous I/O support
      else
         {
            // TODO: Performance Consideration
            // We need to lock only when 'entry.packet.type' is one of the following:
            // 1) USER
            // 2) SHARED_MEM_RESPONSE
            // 3) MCP_NETWORK_TYPE
            net_queue[entry.packet.sender][entry.packet.type].lock();
            net_queue[entry.packet.sender][entry.packet.type].push(entry);
            net_queue[entry.packet.sender][entry.packet.type].unlock();
         }
   }
}

void Network::registerCallback(PacketType type, NetworkCallback callback, void *obj)
{
   assert((unsigned int)type <= MAX_PACKET_TYPE);
   callbacks[type] = callback;
   callback_objs[type] = obj;
}

void Network::unregisterCallback(PacketType type)
{
   assert((unsigned int)type <= MAX_PACKET_TYPE);
   callbacks[type] = NULL;
}

void Network::waitForUserPacket()
{

}

void Network::notifyWaitingUserThread()
{

}

UINT64 Network::netProcCost(NetPacket packet)
{
      return 0;
};

UINT64 Network::netLatency(NetPacket packet)
{
      return 30;
};

<|endoftext|>