<commit_before>/*
 * Copyright (c) 2011, Willow Garage, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the Willow Garage, Inc. nor the names of its
 *       contributors may be used to endorse or promote products derived from
 *       this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
#pragma once
#include <boost/python.hpp>
#include <boost/python/type_id.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>

#include <ecto/util.hpp> //name_of
#include <ecto/tendril.hpp>
#include <stdexcept>
#include <string>
#include <set>
#include <sstream>
#include <cstring>

namespace ecto
{
  /**
   * \class spore
   * \brief The spore is a typed handle for tendrils, making holding onto tendrils a bit easier.
   */
  template<typename T>
  struct spore
  {
    /**
     * Allocates a spore that doesn't point to anything.
     */
    spore()
    {
    }

    /**
     * implicit constructor from a tendril ptr. Needs to be a shared_ptr, as the spore holds a
     * weak_ptr, and uses this to ensure that the spore always points to valid tendril.
     */
    spore(tendril::ptr t) :
        tendril_(t)
    {
      t->enforce_type<T>();
    }

    /**
     * Grab a pointer to the tendril that gave birth to this spore.
     * @return non const pointer to tendril
     */
    inline tendril::ptr p()
    {
      tendril::ptr _p = tendril_.lock();
      if (!_p)
        throw std::logic_error("This spore points to nothing.");
      return _p;
    }
    /**
     * Grab a pointer to the tendril that gave birth to this spore. const overload.
     * @return const pointer to tendril
     */
    inline tendril::const_ptr p() const
    {
      tendril::const_ptr _p = tendril_.lock();
      if (!_p)
        throw std::logic_error("This spore points to nothing. Type name:" + name_of<T>());
      return _p;
    }

    /**
     * Set a typed callback, that will be called when ever the tendril value is changed by the
     * user.
     * @param cb The callback
     * @return ref to this spore, for chaining.
     */
    spore<T>& set_callback(typename boost::function<void(T)> cb)
    {
      p()->set_callback(cb, false);
      return *this;
    }

    spore<T>& notify()
    {
      p()->notify();
      return *this;
    }

    spore<T>& set_doc(const std::string& doc)
    {
      p()->set_doc(doc);
      return *this;
    }

    spore<T>& set_default_val(const T& val)
    {
      p()->set_default_val(val);
      return *this;
    }

    bool dirty() const
    {
      return p()->dirty();
    }

    bool user_supplied() const
    {
      return p()->user_supplied();
    }

    bool has_default() const
    {
      return p()->has_default();
    }

    spore<T>& required(bool b)
    {
      p()->required(b);
      return *this;
    }

    bool required() const
    {
      return p()->required();
    }

    T* operator->()
    {
      tendril::ptr _p = p();
      return &(_p->get<T>());
    }
    const T* operator->() const
    {
      tendril::const_ptr _p = p();
      return &(_p->read<T>());
    }
    const T& operator*() const
    {
      tendril::const_ptr _p = p();
      return _p->read<T>();
    }
    T& operator*()
    {
      tendril::ptr _p = p();
      return _p->get<T>();
    }
    /**
     * This is the const read operation, as opposed to the derefence which is not necessarily const.
     * @return const ref, no copies...
     */
    const T& read() const
    {
      tendril::const_ptr _p = p();
      return _p->read<T>();
    }
    /**
     * Cast operator for convenience.
     */
    operator tendril::ptr()
    {
      return p();
    }
    /**
     * Cast operator for convenience.
     */
    operator tendril::const_ptr() const
    {
      return p();
    }

    tendril::ptr tendril_ptr()
    {
      return p();
    }

    tendril::const_ptr tendril_ptr() const
    {
      return p();
    }

  private:
    boost::weak_ptr<tendril> tendril_;
  };
}
<commit_msg>Minor fix for spore, on null in constructor. Prevents seg fault.<commit_after>/*
 * Copyright (c) 2011, Willow Garage, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the Willow Garage, Inc. nor the names of its
 *       contributors may be used to endorse or promote products derived from
 *       this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
#pragma once
#include <boost/python.hpp>
#include <boost/python/type_id.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>

#include <ecto/util.hpp> //name_of
#include <ecto/tendril.hpp>
#include <stdexcept>
#include <string>
#include <set>
#include <sstream>
#include <cstring>

namespace ecto
{
  /**
   * \class spore
   * \brief The spore is a typed handle for tendrils, making holding onto tendrils a bit easier.
   */
  template<typename T>
  struct spore
  {
    /**
     * Allocates a spore that doesn't point to anything.
     */
    spore()
    {
    }

    /**
     * implicit constructor from a tendril ptr. Needs to be a shared_ptr, as the spore holds a
     * weak_ptr, and uses this to ensure that the spore always points to valid tendril.
     */
    spore(tendril::ptr t) :
        tendril_(t)
    {
      if(!t){
        throw std::logic_error("This tendril is null.");
      }
      t->enforce_type<T>();
    }

    /**
     * Grab a pointer to the tendril that gave birth to this spore.
     * @return non const pointer to tendril
     */
    inline tendril::ptr p()
    {
      tendril::ptr _p = tendril_.lock();
      if (!_p)
        throw std::logic_error("This spore points to nothing.");
      return _p;
    }
    /**
     * Grab a pointer to the tendril that gave birth to this spore. const overload.
     * @return const pointer to tendril
     */
    inline tendril::const_ptr p() const
    {
      tendril::const_ptr _p = tendril_.lock();
      if (!_p)
        throw std::logic_error("This spore points to nothing. Type name:" + name_of<T>());
      return _p;
    }

    /**
     * Set a typed callback, that will be called when ever the tendril value is changed by the
     * user.
     * @param cb The callback
     * @return ref to this spore, for chaining.
     */
    spore<T>& set_callback(typename boost::function<void(T)> cb)
    {
      p()->set_callback(cb, false);
      return *this;
    }

    spore<T>& notify()
    {
      p()->notify();
      return *this;
    }

    spore<T>& set_doc(const std::string& doc)
    {
      p()->set_doc(doc);
      return *this;
    }

    spore<T>& set_default_val(const T& val)
    {
      p()->set_default_val(val);
      return *this;
    }

    bool dirty() const
    {
      return p()->dirty();
    }

    bool user_supplied() const
    {
      return p()->user_supplied();
    }

    bool has_default() const
    {
      return p()->has_default();
    }

    spore<T>& required(bool b)
    {
      p()->required(b);
      return *this;
    }

    bool required() const
    {
      return p()->required();
    }

    T* operator->()
    {
      tendril::ptr _p = p();
      return &(_p->get<T>());
    }
    const T* operator->() const
    {
      tendril::const_ptr _p = p();
      return &(_p->read<T>());
    }
    const T& operator*() const
    {
      tendril::const_ptr _p = p();
      return _p->read<T>();
    }
    T& operator*()
    {
      tendril::ptr _p = p();
      return _p->get<T>();
    }
    /**
     * This is the const read operation, as opposed to the derefence which is not necessarily const.
     * @return const ref, no copies...
     */
    const T& read() const
    {
      tendril::const_ptr _p = p();
      return _p->read<T>();
    }
    /**
     * Cast operator for convenience.
     */
    operator tendril::ptr()
    {
      return p();
    }
    /**
     * Cast operator for convenience.
     */
    operator tendril::const_ptr() const
    {
      return p();
    }

    tendril::ptr tendril_ptr()
    {
      return p();
    }

    tendril::const_ptr tendril_ptr() const
    {
      return p();
    }

  private:
    boost::weak_ptr<tendril> tendril_;
  };
}
<|endoftext|>


<commit_before>#include <deque>
#include <fstream>
#include <sstream>

#include <config/config.h>
#include <config/config_class.h>
#include <config/config_class_log_mask.h>

#include <event/event_callback.h>

#include "wanproxy_config.h"
#include "wanproxy_config_class_codec.h"
#include "wanproxy_config_class_interface.h"
#include "wanproxy_config_class_monitor.h"
#include "wanproxy_config_class_peer.h"
#include "wanproxy_config_class_proxy.h"
#include "wanproxy_config_class_proxy_socks.h"

WANProxyConfig::WANProxyConfig(void)
: log_("/wanproxy/config"),
  config_(NULL)
{ }

WANProxyConfig::~WANProxyConfig()
{
	if (config_ != NULL) {
		delete config_;
		config_ = NULL;
	}
}

bool
WANProxyConfig::parse(std::deque<std::string>& tokens)
{
	std::string command = tokens.front();
	tokens.pop_front();

	if (command == "activate") {
		parse_activate(tokens);
	} else if (command == "create") {
		parse_create(tokens);
	} else if (command == "set") {
		parse_set(tokens);
	} else {
		tokens.clear();
		ERROR(log_) << "Unrecognized configuration command: " << command;
	}
	if (!tokens.empty())
		return (false);
	return (true);
}

void
WANProxyConfig::parse_activate(std::deque<std::string>& tokens)
{
	if (tokens.size() != 1) {
		ERROR(log_) << "Wrong number of words in activate (" << tokens.size() << ")";
		return;
	}

	if (!config_->activate(tokens[0])) {
		ERROR(log_) << "Object (" << tokens[0] << ") activation failed.";
		return;
	}
	tokens.clear();
}

void
WANProxyConfig::parse_create(std::deque<std::string>& tokens)
{
	if (tokens.size() != 2) {
		ERROR(log_) << "Wrong number of words in create (" << tokens.size() << ")";
		return;
	}

	if (!config_->create(tokens[0], tokens[1])) {
		ERROR(log_) << "Object (" << tokens[1] << ") could not be created.";
		return;
	}
	tokens.clear();
}

void
WANProxyConfig::parse_set(std::deque<std::string>& tokens)
{
	if (tokens.size() != 2) {
		ERROR(log_) << "Wrong number of words in set (" << tokens.size() << ")";
		return;
	}

	std::string::iterator dot = std::find(tokens[0].begin(), tokens[0].end(), '.');
	if (dot == tokens[0].end()) {
		ERROR(log_) << "Identifier (" << tokens[0] << ") is not an object member identifier.";
		return;
	}

	std::string object(tokens[0].begin(), dot);
	std::string member(dot + 1, tokens[0].end());
	if (object == "" || member == "") {
		ERROR(log_) << "Object (" << object << ") or member name (" << member << ") is empty.";
		return;
	}

	if (!config_->set(object, member, tokens[1])) {
		ERROR(log_) << "Set of object member (" << tokens[0] << ") failed.";
		return;
	}
	tokens.clear();
}

bool
WANProxyConfig::configure(const std::string& name)
{
	if (config_ != NULL) {
		ERROR(log_) << "WANProxy already configured.";
		return (false);
	}

	INFO(log_) << "Configuring WANProxy.";

	std::fstream in;
	in.open(name.c_str(), std::ios::in);

	if (!in.good()) {
		ERROR(log_) << "Could not open file: " << name;
		return (false);
	}

	config_ = new Config();
	config_->import(&config_class_log_mask);
	config_->import(&wanproxy_config_class_codec);
	config_->import(&wanproxy_config_class_interface);
	config_->import(&wanproxy_config_class_monitor);
	config_->import(&wanproxy_config_class_peer);
	config_->import(&wanproxy_config_class_proxy);
	config_->import(&wanproxy_config_class_proxy_socks);

	std::deque<std::string> tokens;

	while (in.good()) {
		std::string line;
		std::getline(in, line);

		if (line[0] == '#' || line.empty())
			continue;

		std::istringstream is(line);
		while (is.good()) {
			std::string word;
			is >> word;
			if (word[0] == '#')
				break;
			tokens.push_back(word);
		}
		ASSERT(log_, !tokens.empty());
		if (!parse(tokens)) {
			ERROR(log_) << "Error in configuration directive: " << line;

			delete config_;
			config_ = NULL;

			return (false);
		}
		ASSERT(log_, tokens.empty());
	}

	return (true);
}
<commit_msg>Skip empty words.<commit_after>#include <deque>
#include <fstream>
#include <sstream>

#include <config/config.h>
#include <config/config_class.h>
#include <config/config_class_log_mask.h>

#include <event/event_callback.h>

#include "wanproxy_config.h"
#include "wanproxy_config_class_codec.h"
#include "wanproxy_config_class_interface.h"
#include "wanproxy_config_class_monitor.h"
#include "wanproxy_config_class_peer.h"
#include "wanproxy_config_class_proxy.h"
#include "wanproxy_config_class_proxy_socks.h"

WANProxyConfig::WANProxyConfig(void)
: log_("/wanproxy/config"),
  config_(NULL)
{ }

WANProxyConfig::~WANProxyConfig()
{
	if (config_ != NULL) {
		delete config_;
		config_ = NULL;
	}
}

bool
WANProxyConfig::parse(std::deque<std::string>& tokens)
{
	std::string command = tokens.front();
	tokens.pop_front();

	if (command == "activate") {
		parse_activate(tokens);
	} else if (command == "create") {
		parse_create(tokens);
	} else if (command == "set") {
		parse_set(tokens);
	} else {
		tokens.clear();
		ERROR(log_) << "Unrecognized configuration command: " << command;
	}
	if (!tokens.empty())
		return (false);
	return (true);
}

void
WANProxyConfig::parse_activate(std::deque<std::string>& tokens)
{
	if (tokens.size() != 1) {
		ERROR(log_) << "Wrong number of words in activate (" << tokens.size() << ")";
		return;
	}

	if (!config_->activate(tokens[0])) {
		ERROR(log_) << "Object (" << tokens[0] << ") activation failed.";
		return;
	}
	tokens.clear();
}

void
WANProxyConfig::parse_create(std::deque<std::string>& tokens)
{
	if (tokens.size() != 2) {
		ERROR(log_) << "Wrong number of words in create (" << tokens.size() << ")";
		return;
	}

	if (!config_->create(tokens[0], tokens[1])) {
		ERROR(log_) << "Object (" << tokens[1] << ") could not be created.";
		return;
	}
	tokens.clear();
}

void
WANProxyConfig::parse_set(std::deque<std::string>& tokens)
{
	if (tokens.size() != 2) {
		ERROR(log_) << "Wrong number of words in set (" << tokens.size() << ")";
		return;
	}

	std::string::iterator dot = std::find(tokens[0].begin(), tokens[0].end(), '.');
	if (dot == tokens[0].end()) {
		ERROR(log_) << "Identifier (" << tokens[0] << ") is not an object member identifier.";
		return;
	}

	std::string object(tokens[0].begin(), dot);
	std::string member(dot + 1, tokens[0].end());
	if (object == "" || member == "") {
		ERROR(log_) << "Object (" << object << ") or member name (" << member << ") is empty.";
		return;
	}

	if (!config_->set(object, member, tokens[1])) {
		ERROR(log_) << "Set of object member (" << tokens[0] << ") failed.";
		return;
	}
	tokens.clear();
}

bool
WANProxyConfig::configure(const std::string& name)
{
	if (config_ != NULL) {
		ERROR(log_) << "WANProxy already configured.";
		return (false);
	}

	INFO(log_) << "Configuring WANProxy.";

	std::fstream in;
	in.open(name.c_str(), std::ios::in);

	if (!in.good()) {
		ERROR(log_) << "Could not open file: " << name;
		return (false);
	}

	config_ = new Config();
	config_->import(&config_class_log_mask);
	config_->import(&wanproxy_config_class_codec);
	config_->import(&wanproxy_config_class_interface);
	config_->import(&wanproxy_config_class_monitor);
	config_->import(&wanproxy_config_class_peer);
	config_->import(&wanproxy_config_class_proxy);
	config_->import(&wanproxy_config_class_proxy_socks);

	std::deque<std::string> tokens;

	while (in.good()) {
		std::string line;
		std::getline(in, line);

		if (line[0] == '#' || line.empty())
			continue;

		std::istringstream is(line);
		while (is.good()) {
			std::string word;
			is >> word;
			if (word.empty())
				continue;
			if (word[0] == '#')
				break;
			tokens.push_back(word);
		}
		ASSERT(log_, !tokens.empty());
		if (!parse(tokens)) {
			ERROR(log_) << "Error in configuration directive: " << line;

			delete config_;
			config_ = NULL;

			return (false);
		}
		ASSERT(log_, tokens.empty());
	}

	return (true);
}
<|endoftext|>


<commit_before>#include <vector>

#include <common/buffer.h>

#include <event/action.h>
#include <event/callback.h>
#include <event/event_system.h>

#include <io/file.h>

#include "proxy_listener.h"
#include "proxy_socks_listener.h"
#include "wanproxy_config.h"

WANProxyConfig::WANProxyConfig(void)
: log_("/proxy/config"),
  codec_(NULL),
  listeners_(),
  socks_listeners_(),
  config_file_(NULL),
  close_action_(NULL),
  read_action_(NULL),
  read_buffer_()
{
	DEBUG(log_) << "Creating WANProxyConfig instance.";
}

WANProxyConfig::~WANProxyConfig()
{
	ASSERT(config_file_ == NULL);
	ASSERT(close_action_ == NULL);
	ASSERT(read_action_ == NULL);
	ASSERT(read_buffer_.empty());

	std::set<ProxyListener *>::iterator it;
	while ((it = listeners_.begin()) != listeners_.end()) {
		ProxyListener *listener = *it;
		delete listener;
		listeners_.erase(it);
	}
}

void
WANProxyConfig::close_complete(Event e, void *)
{
	close_action_->cancel();
	close_action_ = NULL;

	switch (e.type_) {
	case Event::Done:
		break;
	default:
		HALT(log_) << "Unexpected event: " << e;
	}

	ASSERT(config_file_ != NULL);
	delete config_file_;
	config_file_ = NULL;
}

void
WANProxyConfig::read_complete(Event e, void *)
{
	read_action_->cancel();
	read_action_ = NULL;

	switch (e.type_) {
	case Event::Done:
	case Event::EOS:
		break;
	default:
		HALT(log_) << "Unexpected event: " << e;
	}

	read_buffer_.append(e.buffer_);

	parse();

#if 0
	if (e.type_ == Event::EOS)
		schedule_close();
	else
		schedule_read();
#else
	/*
	 * XXX
	 * The FileDescriptor class doesn't work right with Files yet.  Namely,
	 * it won't detect EOF.  I think the reason is that the EVFILT_READ
	 * filter for kqueue doesn't fire if you're at EOF, which seems dumb.
	 * Need to investigate further.  For now, the config files are small
	 * enough that this works.
	 */
	schedule_close();
#endif
}

void
WANProxyConfig::schedule_close(void)
{
	ASSERT(close_action_ == NULL);
	ASSERT(config_file_ != NULL);
	EventCallback *cb = callback(this, &WANProxyConfig::close_complete);
	close_action_ = config_file_->close(cb);
}

void
WANProxyConfig::schedule_read(void)
{
	DEBUG(log_) << "Reading configuration...";
	ASSERT(read_action_ == NULL);
	ASSERT(config_file_ != NULL);
	EventCallback *cb = callback(this, &WANProxyConfig::read_complete);
	read_action_ = config_file_->read(cb);
}

void
WANProxyConfig::parse(void)
{
	unsigned pos;
	while (read_buffer_.find('\n', &pos)) {
		if (read_buffer_.peek() == '#' || pos == 0) {
			read_buffer_.skip(pos + 1);
			continue;
		}

		Buffer line(read_buffer_, pos);
		read_buffer_.skip(pos + 1);

		std::vector<std::string> tokens;
		while (!line.empty()) {
			unsigned wordlen;
			if (line.find(' ', &pos)) {
				wordlen = pos;
			} else {
				wordlen = line.length();
			}
			uint8_t wordbytes[wordlen];
			line.moveout(wordbytes, wordlen);
			if (!line.empty()) {
				ASSERT(line.peek() == ' ');
				line.skip(1);
			}
			std::string word((const char *)wordbytes, wordlen);
			tokens.push_back(word);
		}

		parse(tokens);
	}
}

void
WANProxyConfig::parse(std::vector<std::string> tokens)
{
	if (tokens[0] == "log-mask") {
		parse_log_mask(tokens);
	} else if (tokens[0] == "proxy") {
		parse_proxy(tokens);
	} else if (tokens[0] == "proxy-socks") {
		parse_proxy_socks(tokens);
	} else {
		ERROR(log_) << "Unrecognized configuration directive: " << tokens[0];
	}
}

void
WANProxyConfig::parse_log_mask(std::vector<std::string> tokens)
{
	if (tokens.size() != 3) {
		ERROR(log_) << "Wrong number of words in log-mask (" << tokens.size() << ")";
		return;
	}

	std::string handle_regex = tokens[1];
	std::string priority_mask = tokens[2];

	if (!Log::mask(handle_regex, priority_mask)) {
		ERROR(log_) << "Unable to set log handle \"" << handle_regex << "\" mask to priority \"" << priority_mask << "\"";
	}
}

void
WANProxyConfig::parse_proxy(std::vector<std::string> tokens)
{
	if (tokens.size() != 10) {
		ERROR(log_) << "Wrong number of words in proxy (" << tokens.size() << ")";
		return;
	}

	std::string local_host = tokens[1];
	unsigned local_port = atoi(tokens[2].c_str());
	if (tokens[3] != "decoder") {
		ERROR(log_) << "Missing 'decoder' statement.";
		return;
	}

	XCodec *local_codec;
	if (tokens[4] == "xcodec")
		local_codec = codec_;
	else if (tokens[4] == "none")
		local_codec = NULL;
	else {
		ERROR(log_) << "Malformed decoder name.";
		return;
	}

	if (tokens[5] != "to") {
		ERROR(log_) << "Missing 'to' statement.";
		return;
	}

	std::string remote_host = tokens[6];
	unsigned remote_port = atoi(tokens[7].c_str());
	if (tokens[8] != "encoder") {
		ERROR(log_) << "Missing 'encoder' statement.";
		return;
	}

	XCodec *remote_codec;
	if (tokens[9] == "xcodec")
		remote_codec = codec_;
	else if (tokens[9] == "none")
		remote_codec = NULL;
	else {
		ERROR(log_) << "Malformed encoder name.";
		return;
	}

	INFO(log_) << "Starting proxy from " << local_host << ':' << local_port << " to " << remote_host << ':' << remote_port;

	ProxyListener *listener = new ProxyListener(local_codec,
						    remote_codec,
						    local_host,
						    local_port,
						    remote_host,
						    remote_port);
	listeners_.insert(listener);
}

void
WANProxyConfig::parse_proxy_socks(std::vector<std::string> tokens)
{
	if (tokens.size() != 3) {
		ERROR(log_) << "Wrong number of words in proxy-socks (" << tokens.size() << ")";
		return;
	}

	std::string local_host = tokens[1];
	unsigned local_port = atoi(tokens[2].c_str());

	INFO(log_) << "Starting socks-proxy on " << local_host << ':' << local_port;

	ProxySocksListener *listener = new ProxySocksListener(local_host, local_port);
	socks_listeners_.insert(listener);
}

bool
WANProxyConfig::configure(XCodec *codec, const std::string& name)
{
	INFO(log_) << "Configuring WANProxy.";

	if (config_file_ != NULL || codec_ != NULL) {
		ERROR(log_) << "WANProxy already configured.";
		return (false);
	}

	FileDescriptor *file = File::open(name, true, false);
	if (file == NULL) {
		ERROR(log_) << "Could not open file: " << name;
		return (false);
	}

	codec_ = codec;
	config_file_ = file;

	schedule_read();

	return (true);
}
<commit_msg>Remove debugging messages that will certainly run before log masks could be configured.<commit_after>#include <vector>

#include <common/buffer.h>

#include <event/action.h>
#include <event/callback.h>
#include <event/event_system.h>

#include <io/file.h>

#include "proxy_listener.h"
#include "proxy_socks_listener.h"
#include "wanproxy_config.h"

WANProxyConfig::WANProxyConfig(void)
: log_("/proxy/config"),
  codec_(NULL),
  listeners_(),
  socks_listeners_(),
  config_file_(NULL),
  close_action_(NULL),
  read_action_(NULL),
  read_buffer_()
{ }

WANProxyConfig::~WANProxyConfig()
{
	ASSERT(config_file_ == NULL);
	ASSERT(close_action_ == NULL);
	ASSERT(read_action_ == NULL);
	ASSERT(read_buffer_.empty());

	std::set<ProxyListener *>::iterator it;
	while ((it = listeners_.begin()) != listeners_.end()) {
		ProxyListener *listener = *it;
		delete listener;
		listeners_.erase(it);
	}
}

void
WANProxyConfig::close_complete(Event e, void *)
{
	close_action_->cancel();
	close_action_ = NULL;

	switch (e.type_) {
	case Event::Done:
		break;
	default:
		HALT(log_) << "Unexpected event: " << e;
	}

	ASSERT(config_file_ != NULL);
	delete config_file_;
	config_file_ = NULL;
}

void
WANProxyConfig::read_complete(Event e, void *)
{
	read_action_->cancel();
	read_action_ = NULL;

	switch (e.type_) {
	case Event::Done:
	case Event::EOS:
		break;
	default:
		HALT(log_) << "Unexpected event: " << e;
	}

	read_buffer_.append(e.buffer_);

	parse();

#if 0
	if (e.type_ == Event::EOS)
		schedule_close();
	else
		schedule_read();
#else
	/*
	 * XXX
	 * The FileDescriptor class doesn't work right with Files yet.  Namely,
	 * it won't detect EOF.  I think the reason is that the EVFILT_READ
	 * filter for kqueue doesn't fire if you're at EOF, which seems dumb.
	 * Need to investigate further.  For now, the config files are small
	 * enough that this works.
	 */
	schedule_close();
#endif
}

void
WANProxyConfig::schedule_close(void)
{
	ASSERT(close_action_ == NULL);
	ASSERT(config_file_ != NULL);
	EventCallback *cb = callback(this, &WANProxyConfig::close_complete);
	close_action_ = config_file_->close(cb);
}

void
WANProxyConfig::schedule_read(void)
{
	ASSERT(read_action_ == NULL);
	ASSERT(config_file_ != NULL);
	EventCallback *cb = callback(this, &WANProxyConfig::read_complete);
	read_action_ = config_file_->read(cb);
}

void
WANProxyConfig::parse(void)
{
	unsigned pos;
	while (read_buffer_.find('\n', &pos)) {
		if (read_buffer_.peek() == '#' || pos == 0) {
			read_buffer_.skip(pos + 1);
			continue;
		}

		Buffer line(read_buffer_, pos);
		read_buffer_.skip(pos + 1);

		std::vector<std::string> tokens;
		while (!line.empty()) {
			unsigned wordlen;
			if (line.find(' ', &pos)) {
				wordlen = pos;
			} else {
				wordlen = line.length();
			}
			uint8_t wordbytes[wordlen];
			line.moveout(wordbytes, wordlen);
			if (!line.empty()) {
				ASSERT(line.peek() == ' ');
				line.skip(1);
			}
			std::string word((const char *)wordbytes, wordlen);
			tokens.push_back(word);
		}

		parse(tokens);
	}
}

void
WANProxyConfig::parse(std::vector<std::string> tokens)
{
	if (tokens[0] == "log-mask") {
		parse_log_mask(tokens);
	} else if (tokens[0] == "proxy") {
		parse_proxy(tokens);
	} else if (tokens[0] == "proxy-socks") {
		parse_proxy_socks(tokens);
	} else {
		ERROR(log_) << "Unrecognized configuration directive: " << tokens[0];
	}
}

void
WANProxyConfig::parse_log_mask(std::vector<std::string> tokens)
{
	if (tokens.size() != 3) {
		ERROR(log_) << "Wrong number of words in log-mask (" << tokens.size() << ")";
		return;
	}

	std::string handle_regex = tokens[1];
	std::string priority_mask = tokens[2];

	if (!Log::mask(handle_regex, priority_mask)) {
		ERROR(log_) << "Unable to set log handle \"" << handle_regex << "\" mask to priority \"" << priority_mask << "\"";
	}
}

void
WANProxyConfig::parse_proxy(std::vector<std::string> tokens)
{
	if (tokens.size() != 10) {
		ERROR(log_) << "Wrong number of words in proxy (" << tokens.size() << ")";
		return;
	}

	std::string local_host = tokens[1];
	unsigned local_port = atoi(tokens[2].c_str());
	if (tokens[3] != "decoder") {
		ERROR(log_) << "Missing 'decoder' statement.";
		return;
	}

	XCodec *local_codec;
	if (tokens[4] == "xcodec")
		local_codec = codec_;
	else if (tokens[4] == "none")
		local_codec = NULL;
	else {
		ERROR(log_) << "Malformed decoder name.";
		return;
	}

	if (tokens[5] != "to") {
		ERROR(log_) << "Missing 'to' statement.";
		return;
	}

	std::string remote_host = tokens[6];
	unsigned remote_port = atoi(tokens[7].c_str());
	if (tokens[8] != "encoder") {
		ERROR(log_) << "Missing 'encoder' statement.";
		return;
	}

	XCodec *remote_codec;
	if (tokens[9] == "xcodec")
		remote_codec = codec_;
	else if (tokens[9] == "none")
		remote_codec = NULL;
	else {
		ERROR(log_) << "Malformed encoder name.";
		return;
	}

	INFO(log_) << "Starting proxy from " << local_host << ':' << local_port << " to " << remote_host << ':' << remote_port;

	ProxyListener *listener = new ProxyListener(local_codec,
						    remote_codec,
						    local_host,
						    local_port,
						    remote_host,
						    remote_port);
	listeners_.insert(listener);
}

void
WANProxyConfig::parse_proxy_socks(std::vector<std::string> tokens)
{
	if (tokens.size() != 3) {
		ERROR(log_) << "Wrong number of words in proxy-socks (" << tokens.size() << ")";
		return;
	}

	std::string local_host = tokens[1];
	unsigned local_port = atoi(tokens[2].c_str());

	INFO(log_) << "Starting socks-proxy on " << local_host << ':' << local_port;

	ProxySocksListener *listener = new ProxySocksListener(local_host, local_port);
	socks_listeners_.insert(listener);
}

bool
WANProxyConfig::configure(XCodec *codec, const std::string& name)
{
	INFO(log_) << "Configuring WANProxy.";

	if (config_file_ != NULL || codec_ != NULL) {
		ERROR(log_) << "WANProxy already configured.";
		return (false);
	}

	FileDescriptor *file = File::open(name, true, false);
	if (file == NULL) {
		ERROR(log_) << "Could not open file: " << name;
		return (false);
	}

	codec_ = codec;
	config_file_ = file;

	schedule_read();

	return (true);
}
<|endoftext|>


<commit_before>/*
Copyright (C) 2016 - Gbor "Razzie" Grzsny

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
*/

#pragma once

#include <exception>
#include <functional>
#include <future>
#include <mutex>
#include <thread>
#include <vector>
#include "raz/memory.hpp"

namespace raz
{
	template<class T>
	class Thread
	{
	public:
		// please note that IMemoryPool must be thread-safe
		Thread(IMemoryPool* memory = nullptr) :
			m_memory(memory),
			m_call_queue(memory)
		{
		}

		Thread(const Thread&) = delete;

		Thread& operator=(const Thread&) = delete;

		~Thread()
		{
			if (m_thread.joinable())
			{
				m_exit_token.set_value();
				m_thread.join();
			}
		}

		template<class... Args>
		bool start(Args... args)
		{
			std::lock_guard<std::mutex> guard(m_mutex);

			if (m_thread.joinable())
				return false;

			m_exit_token = std::move(std::promise<void>());
			m_thread = std::thread(&Thread<T>::run<Args...>, this, std::forward<Args>(args)...);
			return true;
		}

		bool stop()
		{
			std::lock_guard<std::mutex> guard(m_mutex);

			if (m_thread.joinable())
			{
				m_exit_token.set_value();
				m_thread.join();
				return true;
			}

			return false;
		}

		void clear()
		{
			std::lock_guard<std::mutex> guard(m_mutex);
			m_call_queue.clear();
		}

		template<class... Args>
		void operator()(Args... args)
		{
			std::lock_guard<std::mutex> guard(m_mutex);
			m_call_queue.emplace_back(std::allocator_arg, raz::Allocator<char>(m_memory), [args...](T& object) { object(args...); });
		}

	private:
		typedef std::function<void(T&)> ForwardedCall;
		typedef std::vector<ForwardedCall, raz::Allocator<ForwardedCall>> ForwardedCallQueue;

		IMemoryPool* m_memory;
		std::thread m_thread;
		std::promise<void> m_exit_token;
		std::mutex m_mutex;
		ForwardedCallQueue m_call_queue;

		template<class... Args>
		class HasParenthesisOp
		{
			template<class U>
			static auto test(bool) -> decltype(std::declval<U>()(std::declval<Args>()...), void(), std::true_type{})
			{
				return {};
			}

			template<class U>
			static auto test(int) -> std::false_type
			{
				return {};
			}

		public:
			static constexpr bool value = decltype(test<T>(true))::value;
		};

		template<bool>
		void loop(T&);

		template<>
		void loop<true>(T& object)
		{
			object();
		}

		template<>
		void loop<false>(T& object)
		{
		}

		template<bool>
		void error(T&, std::exception&);

		template<>
		void error<true>(T& object, std::exception& e)
		{
			object(e);
		}

		template<>
		void error<false>(T& object, std::exception& e)
		{
		}

		template<class... Args>
		void run(Args... args)
		{
			alignas(alignof(T)) char object_storage[sizeof(T)];

			try
			{
				T* object = new (object_storage) T(std::forward<Args>(args)...);

				std::future<void> exit_token = m_exit_token.get_future();
				ForwardedCallQueue call_queue(m_memory);

				for (;;)
				{
					m_mutex.lock();
					std::swap(m_call_queue, call_queue);
					m_mutex.unlock();

					for (auto& call : call_queue)
						call(*object);

					call_queue.clear();

					loop<HasParenthesisOp<>::value>(*object);

					auto exit_status = exit_token.wait_for(std::chrono::milliseconds(1));
					if (exit_status == std::future_status::ready)
					{
						object->~T();
						return;
					}
				}
			}
			catch (std::exception& e)
			{
				T* object = reinterpret_cast<T*>(object_storage);

				// please note that this is unsafe if the exception was thrown during construction of T
				error<HasParenthesisOp<std::exception&>::value>(*object, e);
				object->~T();
			}
		}
	};
}
<commit_msg>Improved exception handling in thread<commit_after>/*
Copyright (C) 2016 - Gbor "Razzie" Grzsny

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
*/

#pragma once

#include <exception>
#include <functional>
#include <future>
#include <mutex>
#include <thread>
#include <vector>
#include "raz/memory.hpp"

namespace raz
{
	struct ThreadStop
	{
	};

	template<class T>
	class Thread
	{
	public:
		// please note that IMemoryPool must be thread-safe
		Thread(IMemoryPool* memory = nullptr) :
			m_memory(memory),
			m_call_queue(memory)
		{
		}

		Thread(const Thread&) = delete;

		Thread& operator=(const Thread&) = delete;

		~Thread()
		{
			if (m_thread.joinable())
			{
				m_exit_token.set_value();
				m_thread.join();
			}
		}

		template<class... Args>
		std::future<void> start(Args... args)
		{
			std::lock_guard<std::mutex> guard(m_mutex);

			if (m_thread.joinable())
			{
				m_exit_token.set_value();
				m_thread.join();
			}

			m_exit_token = std::move(std::promise<void>());
			m_thread = std::thread(&Thread<T>::run<Args...>, this, std::forward<Args>(args)...);
			m_thread_end = std::move(std::promise<void>());
			return m_thread_end.get_future();
		}

		void stop()
		{
			std::lock_guard<std::mutex> guard(m_mutex);

			if (m_thread.joinable())
			{
				m_exit_token.set_value();
				m_thread.join();
			}
		}

		void clear()
		{
			std::lock_guard<std::mutex> guard(m_mutex);
			m_call_queue.clear();
		}

		template<class... Args>
		void operator()(Args... args)
		{
			std::lock_guard<std::mutex> guard(m_mutex);
			m_call_queue.emplace_back(std::allocator_arg, raz::Allocator<char>(m_memory), [args...](T& object) { object(args...); });
		}

	private:
		typedef std::function<void(T&)> ForwardedCall;
		typedef std::vector<ForwardedCall, raz::Allocator<ForwardedCall>> ForwardedCallQueue;

		IMemoryPool* m_memory;
		std::thread m_thread;
		std::promise<void> m_exit_token;
		std::promise<void> m_thread_end;
		std::mutex m_mutex;
		ForwardedCallQueue m_call_queue;

		template<class... Args>
		class OpCaller
		{
			template<class U>
			static auto test(bool) -> decltype(std::declval<U>()(std::declval<Args>()...), void(), std::true_type{})
			{
				return {};
			}

			template<class U>
			static auto test(int) -> std::false_type
			{
				return {};
			}

			static constexpr bool has_parenthesis_op = decltype(test<T>(true))::value;

			template<bool value>
			static std::enable_if_t<value> _call(T& object, Args... args)
			{
				object(std::forward<Args>(args)...);
			}

			template<int value>
			static std::enable_if_t<!value> _call(T& object, Args... args)
			{
			}

		public:
			static void call(T& object, Args... args)
			{
				_call<has_parenthesis_op>(object, std::forward<Args>(args)...);
			}
		};

		template<class... Args>
		void run(Args... args)
		{
			try
			{
				T object(std::forward<Args>(args)...);

				std::future<void> exit_token = m_exit_token.get_future();
				ForwardedCallQueue call_queue(m_memory);

				for (;;)
				{
					m_mutex.lock();
					std::swap(m_call_queue, call_queue);
					m_mutex.unlock();

					for (auto& call : call_queue)
					{
						try
						{
							call(object);
						}
						catch (ThreadStop)
						{
							m_thread_end.set_value();
							return;
						}
						catch (std::exception& e)
						{
							OpCaller<std::exception&>::call(object, e);
						}
						catch (...)
						{
							OpCaller<std::exception_ptr>::call(object, std::current_exception());
						}
					}

					call_queue.clear();

					try
					{
						OpCaller<>::call(object);
					}
					catch (ThreadStop)
					{
						m_thread_end.set_value();
						return;
					}
					catch (std::exception& e)
					{
						OpCaller<std::exception&>::call(object, e);
					}
					catch (...)
					{
						OpCaller<std::exception_ptr>::call(object, std::current_exception());
					}

					auto exit_status = exit_token.wait_for(std::chrono::milliseconds(1));
					if (exit_status == std::future_status::ready)
					{
						m_thread_end.set_value();
						return;
					}
				}
			}
			catch (...)
			{
				m_thread_end.set_exception(std::current_exception());
			}
		}
	};
}
<|endoftext|>


<commit_before>/***************************************************************************
* Copyright (c) 2016, Johan Mabille and Sylvain Corlay                     *
*                                                                          *
* Distributed under the terms of the BSD 3-Clause License.                 *
*                                                                          *
* The full license is in the file LICENSE, distributed with this software. *
****************************************************************************/

#ifndef XCOMM_HPP
#define XCOMM_HPP

#include <functional>
#include <iostream>
#include <map>
#include <string>
#include <utility>

#include "xguid.hpp"
#include "xmessage.hpp"

namespace xeus
{

    /***********************
     * xtarget declaration *
     ***********************/

    class xcomm;
    class xcomm_manager;

    /**
     * @class xtarget
     * @brief Comm target.
     */
    class XEUS_API xtarget
    {
    public:

        using function_type = std::function<void(const xcomm&, const xmessage&)>;

        xtarget();
        xtarget(const std::string& name, const function_type& callback, xcomm_manager* manager);

        // name accessor
        std::string& name() & noexcept;
        const std::string& name() const & noexcept;
        std::string name() const && noexcept;

        void operator()(const xcomm& comm, const xmessage& request) const;

        void publish_message(const std::string&, xjson, xjson) const;

        void register_comm(xguid, xcomm*) const;
        void unregister_comm(xguid) const;

    private:

        std::string m_name;
        function_type m_callback;
        xcomm_manager* p_manager;
    };

    /*********************
     * xcomm declaration *
     *********************/

    /**
     * @class xcomm
     * @brief Comm object.
     *
     */
    class XEUS_API xcomm
    {
    public:

        using handler_type = std::function<void(const xmessage&)>;

        xcomm() = delete;
        ~xcomm();
        xcomm(xcomm&&);
        xcomm(const xcomm&);
        xcomm(xtarget* target);
        xcomm(xtarget* target, xguid id);

        xcomm& operator=(xcomm&&);
        xcomm& operator=(const xcomm&);

        void open(xjson metadata, xjson data);
        void close(xjson metadata, xjson data);

        xtarget& target() noexcept;
        const xtarget& target() const noexcept;

        void handle_message(const xmessage& request);
        void handle_close(const xmessage& request);

        xguid id() const noexcept;

        template <class T>
        void on_message(T&& handler);
        template <class T>
        void on_close(T&& handler);

    private:

        friend class xcomm_manager;

        /**
         * Send comm message on iopub. Compose iopub message with specified data
         * and rebinds to target's publish_message
         * {
         *    "comm_id": m_id,
         *    "target_name": specified target name,
         *    "data": specified data
         * }
         */
        void send_comm_message(const std::string& msg_type, xjson metadata, xjson data, const std::string&) const;

        handler_type m_close_handler;
        handler_type m_message_handler;
        xtarget* p_target;
        xguid m_id;
        bool m_moved;
    };

    /*****************************
     * xcomm_manager declaration *
     *****************************/

    class xkernel_core;

    /**
     * @class xcomm_manager
     * @brief Manager and registry for comms and comm targets in the kernel.
     */
    class XEUS_API xcomm_manager
    {
    public:

        xcomm_manager(xkernel_core* kernel = nullptr);

        using target_function_type = xtarget::function_type;

        void register_comm_target(const std::string& target_name, const target_function_type& callback);
        void unregister_comm_target(const std::string& target_name);

        void comm_open(const xmessage& request);
        void comm_close(const xmessage& request);
        void comm_msg(const xmessage& request);

        std::map<xguid, xcomm*>& comms() & noexcept;
        const std::map<xguid, xcomm*>& comms() const & noexcept;
        std::map<xguid, xcomm*> comms() const && noexcept;

        xtarget* target(const std::string& target_name);

        void register_comm(xguid, xcomm*);
        void unregister_comm(xguid);

    private:

        friend class xtarget;

        xjson get_metadata() const;

        std::map<xguid, xcomm*> m_comms;
        std::map<std::string, xtarget> m_targets;
        xkernel_core* p_kernel;
    };

    /**************************
     * xtarget implementation *
     **************************/

    inline xtarget::xtarget()
        : m_name(), m_callback(), p_manager(nullptr)
    {
    }

    inline xtarget::xtarget(const std::string& name, const function_type& callback, xcomm_manager* manager)
        : m_name(name), m_callback(callback), p_manager(manager)
    {
    }

    inline std::string& xtarget::name() & noexcept
    {
        return m_name;
    }

    inline const std::string& xtarget::name() const & noexcept
    {
        return m_name;
    }

    inline std::string xtarget::name() const && noexcept
    {
        return m_name;
    }

    inline void xtarget::operator()(const xcomm& comm, const xmessage& message) const
    {
        return m_callback(comm, message);
    }

    inline void xtarget::register_comm(xguid id, xcomm* comm) const
    {
        p_manager->register_comm(id, comm);
    }

    inline void xtarget::unregister_comm(xguid id) const
    {
        p_manager->unregister_comm(id);
    }

    /************************
     * xcomm implementation *
     ************************/

    inline xtarget& xcomm::target() noexcept
    {
        return *p_target;
    }

    inline const xtarget& xcomm::target() const noexcept
    {
        return *p_target;
    }

    inline void xcomm::handle_close(const xmessage& message)
    {
        if (m_close_handler)
        {
            m_close_handler(message);
        }
    }

    inline void xcomm::handle_message(const xmessage& message)
    {
        if (m_message_handler)
        {
            m_message_handler(message);
        }
    }

    inline void xcomm::send_comm_message(const std::string& msg_type, xjson metadata, xjson data,
                                         const std::string& target_name) const
    {
        xjson content;
        content["comm_id"] = guid_to_hex(m_id);
        content["target_name"] = target_name;
        content["data"] = std::move(data);
        target().publish_message(msg_type, std::move(metadata), std::move(content));
    }

    inline xcomm::xcomm(xcomm&& comm)
        : m_close_handler(std::move(comm.m_close_handler)),
          m_message_handler(std::move(comm.m_message_handler)),
          p_target(std::move(comm.p_target)),
          m_id(std::move(comm.m_id))
    {
        comm.m_moved = true;
        p_target->register_comm(m_id, this);
    }

    inline xcomm::xcomm(const xcomm& comm)
        : p_target(comm.p_target), m_id()
    {
        p_target->register_comm(m_id, this);
    }

    inline xcomm& xcomm::operator=(xcomm&& comm)
    {
        m_close_handler = std::move(comm.m_close_handler);
        m_message_handler = std::move(comm.m_message_handler);
        p_target = std::move(comm.p_target);
        p_target->unregister_comm(m_id);
        m_id = std::move(comm.m_id);
        p_target->register_comm(m_id, this);
        comm.m_moved = true;
        return *this;
    }

    inline xcomm& xcomm::operator=(const xcomm& comm)
    {
        p_target = comm.p_target;
        m_id = xguid();
        p_target->register_comm(m_id, this);
        return *this;
    }

    inline xcomm::xcomm(xtarget* target)
        : p_target(target), m_id()
    {
        p_target->register_comm(m_id, this);
    }

    inline xcomm::xcomm(xtarget* target, xguid id)
        : p_target(target), m_id(id)
    {
        p_target->register_comm(m_id, this);
    }

    inline xcomm::~xcomm()
    {
        if (!m_moved)
        {
            p_target->unregister_comm(m_id);
        }
    }

    inline void xcomm::open(xjson metadata, xjson data)
    {
        send_comm_message("comm_open", std::move(metadata), std::move(data), p_target->name());
    }

    inline void xcomm::close(xjson metadata, xjson data)
    {
        send_comm_message("comm_close", std::move(metadata), std::move(data), p_target->name());
    }

    inline xguid xcomm::id() const noexcept
    {
        return m_id;
    }

    template <class T>
    inline void xcomm::on_message(T&& handler)
    {
        m_message_handler = std::forward<T>(handler);
    }

    template <class T>
    inline void xcomm::on_close(T&& handler)
    {
        m_close_handler = std::forward<T>(handler);
    }

    /********************************
     * xcomm_manager implementation *
     ********************************/

    inline xtarget* xcomm_manager::target(const std::string& target_name)
    {
        return &m_targets[target_name];
    }

    inline std::map<xguid, xcomm*>& xcomm_manager::comms() & noexcept
    {
        return m_comms;
    }

    inline const std::map<xguid, xcomm*>& xcomm_manager::comms() const & noexcept
    {
        return m_comms;
    }

    inline std::map<xguid, xcomm*> xcomm_manager::comms() const && noexcept
    {
        return m_comms;
    }
}

#endif
<commit_msg>Enable sending comm messages without target name<commit_after>/***************************************************************************
* Copyright (c) 2016, Johan Mabille and Sylvain Corlay                     *
*                                                                          *
* Distributed under the terms of the BSD 3-Clause License.                 *
*                                                                          *
* The full license is in the file LICENSE, distributed with this software. *
****************************************************************************/

#ifndef XCOMM_HPP
#define XCOMM_HPP

#include <functional>
#include <iostream>
#include <map>
#include <string>
#include <utility>

#include "xguid.hpp"
#include "xmessage.hpp"

namespace xeus
{

    /***********************
     * xtarget declaration *
     ***********************/

    class xcomm;
    class xcomm_manager;

    /**
     * @class xtarget
     * @brief Comm target.
     */
    class XEUS_API xtarget
    {
    public:

        using function_type = std::function<void(const xcomm&, const xmessage&)>;

        xtarget();
        xtarget(const std::string& name, const function_type& callback, xcomm_manager* manager);

        // name accessor
        std::string& name() & noexcept;
        const std::string& name() const & noexcept;
        std::string name() const && noexcept;

        void operator()(const xcomm& comm, const xmessage& request) const;

        void publish_message(const std::string&, xjson, xjson) const;

        void register_comm(xguid, xcomm*) const;
        void unregister_comm(xguid) const;

    private:

        std::string m_name;
        function_type m_callback;
        xcomm_manager* p_manager;
    };

    /*********************
     * xcomm declaration *
     *********************/

    /**
     * @class xcomm
     * @brief Comm object.
     *
     */
    class XEUS_API xcomm
    {
    public:

        using handler_type = std::function<void(const xmessage&)>;

        xcomm() = delete;
        ~xcomm();
        xcomm(xcomm&&);
        xcomm(const xcomm&);
        xcomm(xtarget* target);
        xcomm(xtarget* target, xguid id);

        xcomm& operator=(xcomm&&);
        xcomm& operator=(const xcomm&);

        void open(xjson metadata, xjson data);
        void close(xjson metadata, xjson data);
        void send(xjson metadata, xjson data) const;

        xtarget& target() noexcept;
        const xtarget& target() const noexcept;

        void handle_message(const xmessage& request);
        void handle_close(const xmessage& request);

        xguid id() const noexcept;

        template <class T>
        void on_message(T&& handler);
        template <class T>
        void on_close(T&& handler);

    private:

        friend class xcomm_manager;

        /**
         * Send comm message on iopub. Compose iopub message with specified data
         * and rebinds to target's publish_message
         * {
         *    "comm_id": m_id,
         *    "target_name": specified target name,
         *    "data": specified data
         * }
         */
        void send_comm_message(const std::string& msg_type, xjson metadata, xjson data) const;
        void send_comm_message(const std::string& msg_type, xjson metadata, xjson data, const std::string& target_name) const;

        handler_type m_close_handler;
        handler_type m_message_handler;
        xtarget* p_target;
        xguid m_id;
        bool m_moved;
    };

    /*****************************
     * xcomm_manager declaration *
     *****************************/

    class xkernel_core;

    /**
     * @class xcomm_manager
     * @brief Manager and registry for comms and comm targets in the kernel.
     */
    class XEUS_API xcomm_manager
    {
    public:

        xcomm_manager(xkernel_core* kernel = nullptr);

        using target_function_type = xtarget::function_type;

        void register_comm_target(const std::string& target_name, const target_function_type& callback);
        void unregister_comm_target(const std::string& target_name);

        void comm_open(const xmessage& request);
        void comm_close(const xmessage& request);
        void comm_msg(const xmessage& request);

        std::map<xguid, xcomm*>& comms() & noexcept;
        const std::map<xguid, xcomm*>& comms() const & noexcept;
        std::map<xguid, xcomm*> comms() const && noexcept;

        xtarget* target(const std::string& target_name);

        void register_comm(xguid, xcomm*);
        void unregister_comm(xguid);

    private:

        friend class xtarget;

        xjson get_metadata() const;

        std::map<xguid, xcomm*> m_comms;
        std::map<std::string, xtarget> m_targets;
        xkernel_core* p_kernel;
    };

    /**************************
     * xtarget implementation *
     **************************/

    inline xtarget::xtarget()
        : m_name(), m_callback(), p_manager(nullptr)
    {
    }

    inline xtarget::xtarget(const std::string& name, const function_type& callback, xcomm_manager* manager)
        : m_name(name), m_callback(callback), p_manager(manager)
    {
    }

    inline std::string& xtarget::name() & noexcept
    {
        return m_name;
    }

    inline const std::string& xtarget::name() const & noexcept
    {
        return m_name;
    }

    inline std::string xtarget::name() const && noexcept
    {
        return m_name;
    }

    inline void xtarget::operator()(const xcomm& comm, const xmessage& message) const
    {
        return m_callback(comm, message);
    }

    inline void xtarget::register_comm(xguid id, xcomm* comm) const
    {
        p_manager->register_comm(id, comm);
    }

    inline void xtarget::unregister_comm(xguid id) const
    {
        p_manager->unregister_comm(id);
    }

    /************************
     * xcomm implementation *
     ************************/

    inline xtarget& xcomm::target() noexcept
    {
        return *p_target;
    }

    inline const xtarget& xcomm::target() const noexcept
    {
        return *p_target;
    }

    inline void xcomm::handle_close(const xmessage& message)
    {
        if (m_close_handler)
        {
            m_close_handler(message);
        }
    }

    inline void xcomm::handle_message(const xmessage& message)
    {
        if (m_message_handler)
        {
            m_message_handler(message);
        }
    }

    inline void xcomm::send_comm_message(const std::string& msg_type, xjson metadata, xjson data) const
    {
        xjson content;
        content["comm_id"] = guid_to_hex(m_id);
        content["data"] = std::move(data);
        target().publish_message(msg_type, std::move(metadata), std::move(content));
    }

    inline void xcomm::send_comm_message(const std::string& msg_type, xjson metadata, xjson data,
                                         const std::string& target_name) const
    {
        xjson content;
        content["comm_id"] = guid_to_hex(m_id);
        content["target_name"] = target_name;
        content["data"] = std::move(data);
        target().publish_message(msg_type, std::move(metadata), std::move(content));
    }

    inline xcomm::xcomm(xcomm&& comm)
        : m_close_handler(std::move(comm.m_close_handler)),
          m_message_handler(std::move(comm.m_message_handler)),
          p_target(std::move(comm.p_target)),
          m_id(std::move(comm.m_id))
    {
        comm.m_moved = true;
        p_target->register_comm(m_id, this);
    }

    inline xcomm::xcomm(const xcomm& comm)
        : p_target(comm.p_target), m_id()
    {
        p_target->register_comm(m_id, this);
    }

    inline xcomm& xcomm::operator=(xcomm&& comm)
    {
        m_close_handler = std::move(comm.m_close_handler);
        m_message_handler = std::move(comm.m_message_handler);
        p_target = std::move(comm.p_target);
        p_target->unregister_comm(m_id);
        m_id = std::move(comm.m_id);
        p_target->register_comm(m_id, this);
        comm.m_moved = true;
        return *this;
    }

    inline xcomm& xcomm::operator=(const xcomm& comm)
    {
        p_target = comm.p_target;
        m_id = xguid();
        p_target->register_comm(m_id, this);
        return *this;
    }

    inline xcomm::xcomm(xtarget* target)
        : p_target(target), m_id()
    {
        p_target->register_comm(m_id, this);
    }

    inline xcomm::xcomm(xtarget* target, xguid id)
        : p_target(target), m_id(id)
    {
        p_target->register_comm(m_id, this);
    }

    inline xcomm::~xcomm()
    {
        if (!m_moved)
        {
            p_target->unregister_comm(m_id);
        }
    }

    inline void xcomm::open(xjson metadata, xjson data)
    {
        send_comm_message("comm_open", std::move(metadata), std::move(data), p_target->name());
    }

    inline void xcomm::close(xjson metadata, xjson data)
    {
        send_comm_message("comm_close", std::move(metadata), std::move(data));
    }

    inline void xcomm::send(xjson metadata, xjson data) const
    {
        send_comm_message("comm_msg", std::move(metadata), std::move(data));
    }

    inline xguid xcomm::id() const noexcept
    {
        return m_id;
    }

    template <class T>
    inline void xcomm::on_message(T&& handler)
    {
        m_message_handler = std::forward<T>(handler);
    }

    template <class T>
    inline void xcomm::on_close(T&& handler)
    {
        m_close_handler = std::forward<T>(handler);
    }

    /********************************
     * xcomm_manager implementation *
     ********************************/

    inline xtarget* xcomm_manager::target(const std::string& target_name)
    {
        return &m_targets[target_name];
    }

    inline std::map<xguid, xcomm*>& xcomm_manager::comms() & noexcept
    {
        return m_comms;
    }

    inline const std::map<xguid, xcomm*>& xcomm_manager::comms() const & noexcept
    {
        return m_comms;
    }

    inline std::map<xguid, xcomm*> xcomm_manager::comms() const && noexcept
    {
        return m_comms;
    }
}

#endif
<|endoftext|>


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

#include "chrome/browser/component_updater/flash_component_installer.h"

#include "base/bind.h"
#include "base/base_paths.h"
#include "base/compiler_specific.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "base/values.h"
#include "chrome/browser/component_updater/component_updater_service.h"
#include "chrome/browser/plugin_prefs.h"
#include "chrome/common/chrome_paths.h"
#include "content/browser/browser_thread.h"
#include "content/browser/plugin_service.h"
#include "webkit/plugins/npapi/plugin_list.h"
#include "webkit/plugins/webplugininfo.h"

namespace {

// CRX hash. The extension id is: immdilkhigodmjbnngapbehchmihabbg.
const uint8 sha2_hash[] = {0x5c, 0x40, 0x30, 0xe3, 0x5d, 0x83, 0x2b, 0xd9,
                           0x7b, 0xa3, 0x69, 0xae, 0xbc, 0x7c, 0x5e, 0x5a,
                           0xef, 0xa5, 0xdf, 0x64, 0x6a, 0xe1, 0xc6, 0xdf,
                           0x23, 0x47, 0x30, 0x2a, 0xde, 0xae, 0x9d, 0xf7};

// File name of the internal Flash plugin on different platforms.
const FilePath::CharType kFlashPluginFileName[] =
#if defined(OS_MACOSX)
    FILE_PATH_LITERAL("Flash Player Plugin for Chrome.plugin");
#elif defined(OS_WIN)
    FILE_PATH_LITERAL("gcswf32.dll");
#else  // OS_LINUX, etc.
    FILE_PATH_LITERAL("libgcflashplayer.so");
#endif

const char kNPAPIFlashManifestName[] = "NPAPIFlash";

// The NPAPI flash plugins are in a directory with this name.
const FilePath::CharType kNPAPIFlashBaseDirectory[] =
    FILE_PATH_LITERAL("NPAPIFlash");

// The base directory on windows looks like:
// <profile>\AppData\Local\Google\Chrome\User Data\NPAPIFlash\.
FilePath GetNPAPIFlashBaseDirectory() {
  FilePath result;
  PathService::Get(chrome::DIR_USER_DATA, &result);
  return result.Append(kNPAPIFlashBaseDirectory);
}

std::string NormalizeVersion(const string16& version) {
  std::string ascii_ver = UTF16ToASCII(version);
  std::replace(ascii_ver.begin(), ascii_ver.end(), ',', '.');
  return ascii_ver;
}

}  // namespace

class NPAPIFlashComponentInstaller : public ComponentInstaller {
 public:
  explicit NPAPIFlashComponentInstaller(const Version& version);

  virtual ~NPAPIFlashComponentInstaller() {}

  virtual void OnUpdateError(int error) OVERRIDE;

  virtual bool Install(base::DictionaryValue* manifest,
                       const FilePath& unpack_path) OVERRIDE;

 private:
  Version current_version_;
};

NPAPIFlashComponentInstaller::NPAPIFlashComponentInstaller(
    const Version& version) : current_version_(version) {
  DCHECK(version.IsValid());
}

void NPAPIFlashComponentInstaller::OnUpdateError(int error) {
  NOTREACHED() << "NPAPI flash update error: " << error;
}

bool NPAPIFlashComponentInstaller::Install(base::DictionaryValue* manifest,
                                           const FilePath& unpack_path) {
  std::string name;
  manifest->GetStringASCII("name", &name);
  if (name != kNPAPIFlashManifestName)
    return false;
  std::string proposed_version;
  manifest->GetStringASCII("version", &proposed_version);
  Version version(proposed_version.c_str());
  if (!version.IsValid())
    return false;
  if (current_version_.CompareTo(version) >= 0)
    return false;
  if (!file_util::PathExists(unpack_path.Append(kFlashPluginFileName)))
    return false;
  // Passed the basic tests. Time to install it.
  if (!file_util::Move(unpack_path, GetNPAPIFlashBaseDirectory()))
    return false;
  // Installation is done. Now tell the rest of chrome.
  current_version_ = version;
  webkit::npapi::PluginList::Singleton()->RefreshPlugins();
  return true;
}

void FinishFlashUpdateRegistration(ComponentUpdateService* cus,
                                   const webkit::WebPluginInfo& info) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  // todo(cpu): Add PluginPrefs code here to determine if what we update
  // is actually going to be used.

  Version version(NormalizeVersion(info.version));
  if (!version.IsValid()) {
    NOTREACHED();
    return;
  }

  CrxComponent flash;
  flash.name = "npapi_flash";
  flash.installer = new NPAPIFlashComponentInstaller(version);
  flash.version = version;
  flash.pk_hash.assign(sha2_hash, &sha2_hash[sizeof(sha2_hash)]);
  if (cus->RegisterComponent(flash) != ComponentUpdateService::kOk) {
    NOTREACHED() << "Flash component registration fail";
  }
}

// The code in this function is only concerned about learning what flash plugin
// chrome is using and what is its version. This will determine if we register
// for component update or not. Read the comments on RegisterNPAPIFlashComponent
// for more background.
void StartFlashUpdateRegistration(ComponentUpdateService* cus,
                                  const std::vector<webkit::WebPluginInfo>&) {
  FilePath builtin_plugin_path;
  if (!PathService::Get(chrome::FILE_FLASH_PLUGIN, &builtin_plugin_path))
    return;

  FilePath updated_plugin_path =
      GetNPAPIFlashBaseDirectory().Append(kFlashPluginFileName);

  PluginService* plugins = PluginService::GetInstance();
  webkit::WebPluginInfo plugin_info;

  if (plugins->GetPluginInfoByPath(updated_plugin_path, &plugin_info)) {
    // The updated plugin is newer. Since flash is used by pretty much every
    // webpage out there, odds are it is going to be loaded, which means
    // receiving an update is pointless since we can't swap them. You might
    // find this pessimistic. The way we get out of this situation is when
    // we update the whole product.
    DLOG(INFO) << "updated plugin overriding built-in flash";
    return;
  } else if (plugins->GetPluginInfoByPath(builtin_plugin_path, &plugin_info)) {
    // The built plugin is newer. Delete the updated plugin and register for
    // updates. This should be the normal case.
    file_util::Delete(GetNPAPIFlashBaseDirectory(), true);
  } else {
    // Strange installation. Log and abort registration.
    DLOG(WARNING) << "Strange flash npapi configuration";
    return;
  }

  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
      base::Bind(&FinishFlashUpdateRegistration, cus, plugin_info));
}

// Here is the general plan of action: we are going to update flash and we have
// the following cases:
// 1- The active flash is not the built-in flash (user override).
// 2- The active flash is the built-in flash.
// 3- The active flash is the one from the component updater.
// In case 1 we do nothing. In cases 2 and 3 we need to compare versions
// and if the higher version is:
// case 2: remove the component update flash, register with component updater.
// case 3: register with component updater.
//
// In practice, it's complicated. First off, to learn the version of the plugin
// we have to do file IO, which PluginList will do for us but we have to be
// careful not to trigger this on the UI thread: AddExtraPluginPath and
// RefreshPlugins don't trigger file IO, but most of the others calls do.
//
// Secondly, we can do this in a delayed task. Right now we just need to
// register the right plugin before chrome loads the first flash-ladden page.
//
// Interestingly, if PluginList finds two plugins with the same filename and
// same mimetypes, it will only keep the one with the higher version. This is
// our case in the sense that a component updated flash is very much the same
// thing as built-in flash: sometimes newer or sometimes older. That is why
// you don't see version comparison in this code.
//
// So to kick off the magic we add the updated flash path here, even though
// there might not be a flash player in that location. If there is and it is
// newer, it will take its place then we fire StartFlashUpdateRegistration
// on the IO thread to learn which one won. Since we do it in a delayed task
// probably somebody (unknowingly) will pay for the file IO, so usually get
// the information for free.
void RegisterNPAPIFlashComponent(ComponentUpdateService* cus) {
#if defined(OS_WIN)
  webkit::npapi::PluginList* plugins = webkit::npapi::PluginList::Singleton();
  FilePath path = GetNPAPIFlashBaseDirectory().Append(kFlashPluginFileName);
  plugins->AddExtraPluginPath(path);
  plugins->RefreshPlugins();

  // Post the task to the FILE thread because IO may be done once the plugins
  // are loaded.
  BrowserThread::PostDelayedTask(BrowserThread::FILE, FROM_HERE,
      base::Bind(&PluginService::GetPlugins,
                 base::Unretained(PluginService::GetInstance()),
                 base::Bind(&StartFlashUpdateRegistration, cus)),
      8000);
#endif
}
<commit_msg>Enable flash npapi component updater for all platforms except chromeOs<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/component_updater/flash_component_installer.h"

#include "base/bind.h"
#include "base/base_paths.h"
#include "base/compiler_specific.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "base/values.h"
#include "chrome/browser/component_updater/component_updater_service.h"
#include "chrome/browser/plugin_prefs.h"
#include "chrome/common/chrome_paths.h"
#include "content/browser/browser_thread.h"
#include "content/browser/plugin_service.h"
#include "webkit/plugins/npapi/plugin_list.h"
#include "webkit/plugins/webplugininfo.h"

namespace {

// CRX hash. The extension id is: immdilkhigodmjbnngapbehchmihabbg.
const uint8 sha2_hash[] = {0x8c, 0xc3, 0x8b, 0xa7, 0x86, 0xe3, 0xc9, 0x1d,
                           0xd6, 0x0f, 0x14, 0x72, 0x7c, 0x87, 0x01, 0x16,
                           0xe2, 0x00, 0x6c, 0x98, 0xbc, 0xfb, 0x14, 0x1b,
                           0x5c, 0xcd, 0xff, 0x3d, 0xa3, 0x2e, 0x2c, 0x49};

// File name of the internal Flash plugin on different platforms.
const FilePath::CharType kFlashPluginFileName[] =
#if defined(OS_MACOSX)
    FILE_PATH_LITERAL("Flash Player Plugin for Chrome.plugin");
#elif defined(OS_WIN)
    FILE_PATH_LITERAL("gcswf32.dll");
#else  // OS_LINUX, etc.
    FILE_PATH_LITERAL("libgcflashplayer.so");
#endif

const char kNPAPIFlashManifestName[] = "NPAPIFlash";

// The NPAPI flash plugins are in a directory with this name.
const FilePath::CharType kNPAPIFlashBaseDirectory[] =
    FILE_PATH_LITERAL("NPAPIFlash");

// The base directory on windows looks like:
// <profile>\AppData\Local\Google\Chrome\User Data\NPAPIFlash\.
FilePath GetNPAPIFlashBaseDirectory() {
  FilePath result;
  PathService::Get(chrome::DIR_USER_DATA, &result);
  return result.Append(kNPAPIFlashBaseDirectory);
}

std::string NormalizeVersion(const string16& version) {
  std::string ascii_ver = UTF16ToASCII(version);
  std::replace(ascii_ver.begin(), ascii_ver.end(), ',', '.');
  return ascii_ver;
}

}  // namespace

class NPAPIFlashComponentInstaller : public ComponentInstaller {
 public:
  explicit NPAPIFlashComponentInstaller(const Version& version);

  virtual ~NPAPIFlashComponentInstaller() {}

  virtual void OnUpdateError(int error) OVERRIDE;

  virtual bool Install(base::DictionaryValue* manifest,
                       const FilePath& unpack_path) OVERRIDE;

 private:
  Version current_version_;
};

NPAPIFlashComponentInstaller::NPAPIFlashComponentInstaller(
    const Version& version) : current_version_(version) {
  DCHECK(version.IsValid());
}

void NPAPIFlashComponentInstaller::OnUpdateError(int error) {
  NOTREACHED() << "NPAPI flash update error: " << error;
}

bool NPAPIFlashComponentInstaller::Install(base::DictionaryValue* manifest,
                                           const FilePath& unpack_path) {
  std::string name;
  manifest->GetStringASCII("name", &name);
  if (name != kNPAPIFlashManifestName)
    return false;
  std::string proposed_version;
  manifest->GetStringASCII("version", &proposed_version);
  Version version(proposed_version.c_str());
  if (!version.IsValid())
    return false;
  if (current_version_.CompareTo(version) >= 0)
    return false;
  if (!file_util::PathExists(unpack_path.Append(kFlashPluginFileName)))
    return false;
  // Passed the basic tests. Time to install it.
  if (!file_util::Move(unpack_path, GetNPAPIFlashBaseDirectory()))
    return false;
  // Installation is done. Now tell the rest of chrome.
  current_version_ = version;
  webkit::npapi::PluginList::Singleton()->RefreshPlugins();
  return true;
}

void FinishFlashUpdateRegistration(ComponentUpdateService* cus,
                                   const webkit::WebPluginInfo& info) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  // todo(cpu): Add PluginPrefs code here to determine if what we update
  // is actually going to be used.

  Version version(NormalizeVersion(info.version));
  if (!version.IsValid()) {
    NOTREACHED();
    return;
  }

  CrxComponent flash;
  flash.name = "npapi_flash";
  flash.installer = new NPAPIFlashComponentInstaller(version);
  flash.version = version;
  flash.pk_hash.assign(sha2_hash, &sha2_hash[sizeof(sha2_hash)]);
  if (cus->RegisterComponent(flash) != ComponentUpdateService::kOk) {
    NOTREACHED() << "Flash component registration fail";
  }
}

// The code in this function is only concerned about learning what flash plugin
// chrome is using and what is its version. This will determine if we register
// for component update or not. Read the comments on RegisterNPAPIFlashComponent
// for more background.
void StartFlashUpdateRegistration(ComponentUpdateService* cus,
                                  const std::vector<webkit::WebPluginInfo>&) {
  FilePath builtin_plugin_path;
  if (!PathService::Get(chrome::FILE_FLASH_PLUGIN, &builtin_plugin_path))
    return;

  FilePath updated_plugin_path =
      GetNPAPIFlashBaseDirectory().Append(kFlashPluginFileName);

  PluginService* plugins = PluginService::GetInstance();
  webkit::WebPluginInfo plugin_info;

  if (plugins->GetPluginInfoByPath(updated_plugin_path, &plugin_info)) {
    // The updated plugin is newer. Since flash is used by pretty much every
    // webpage out there, odds are it is going to be loaded, which means
    // receiving an update is pointless since we can't swap them. You might
    // find this pessimistic. The way we get out of this situation is when
    // we update the whole product.
    DLOG(INFO) << "updated plugin overriding built-in flash";
    return;
  } else if (plugins->GetPluginInfoByPath(builtin_plugin_path, &plugin_info)) {
    // The built plugin is newer. Delete the updated plugin and register for
    // updates. This should be the normal case.
    file_util::Delete(GetNPAPIFlashBaseDirectory(), true);
  } else {
    // Strange installation. Log and abort registration.
    DLOG(WARNING) << "Strange flash npapi configuration";
    return;
  }

  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
      base::Bind(&FinishFlashUpdateRegistration, cus, plugin_info));
}

// Here is the general plan of action: we are going to update flash and we have
// the following cases:
// 1- The active flash is not the built-in flash (user override).
// 2- The active flash is the built-in flash.
// 3- The active flash is the one from the component updater.
// In case 1 we do nothing. In cases 2 and 3 we need to compare versions
// and if the higher version is:
// case 2: remove the component update flash, register with component updater.
// case 3: register with component updater.
//
// In practice, it's complicated. First off, to learn the version of the plugin
// we have to do file IO, which PluginList will do for us but we have to be
// careful not to trigger this on the UI thread: AddExtraPluginPath and
// RefreshPlugins don't trigger file IO, but most of the others calls do.
//
// Secondly, we can do this in a delayed task. Right now we just need to
// register the right plugin before chrome loads the first flash-ladden page.
//
// Interestingly, if PluginList finds two plugins with the same filename and
// same mimetypes, it will only keep the one with the higher version. This is
// our case in the sense that a component updated flash is very much the same
// thing as built-in flash: sometimes newer or sometimes older. That is why
// you don't see version comparison in this code.
//
// So to kick off the magic we add the updated flash path here, even though
// there might not be a flash player in that location. If there is and it is
// newer, it will take its place then we fire StartFlashUpdateRegistration
// on the IO thread to learn which one won. Since we do it in a delayed task
// probably somebody (unknowingly) will pay for the file IO, so usually get
// the information for free.
void RegisterNPAPIFlashComponent(ComponentUpdateService* cus) {
#if !defined(OS_CHROMEOS)
  webkit::npapi::PluginList* plugins = webkit::npapi::PluginList::Singleton();
  FilePath path = GetNPAPIFlashBaseDirectory().Append(kFlashPluginFileName);
  plugins->AddExtraPluginPath(path);
  plugins->RefreshPlugins();

  // Post the task to the FILE thread because IO may be done once the plugins
  // are loaded.
  BrowserThread::PostDelayedTask(BrowserThread::FILE, FROM_HERE,
      base::Bind(&PluginService::GetPlugins,
                 base::Unretained(PluginService::GetInstance()),
                 base::Bind(&StartFlashUpdateRegistration, cus)),
      8000);
#endif
}
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "com4j.h"
#include "unmarshaller.h"
#include "safearray.h"

__declspec(dllexport) int __stdcall foo(IUnknown* pUnk, int arg1, short arg2) {
	return arg1+arg2;
}

Environment::~Environment() {
	foo(NULL,0,3);
	// run post actions
	while( postActions!=NULL ) {
		postActions->act(env);
		PostAction* old = postActions;
		postActions = postActions->next;
		delete old;
	}
}

#ifdef	_DEBUG
static int invocationCount = 0;
#endif

jobject Environment::invoke( void* pComObject, ComMethod method, jobjectArray args, jint* convs,
	jclass retType, int retIndex, bool retIsInOut, jint retConv ) {
	// list of clean up actions

	int i;
	DWORD spBefore,spAfter;
	// the unmarshaller if this method should return an object.
	Unmarshaller* retUnm = NULL;

// somehow anonymous union here makes the compiler upset
// --- when we do "push pv" it pushes something different!
//	union {
		BSTR bstr;
		Unmarshaller* unm;
		const wchar_t*	lpcwstr;
		const char*		lpcstr;
		INT8	int8;
		INT16	int16;
		INT32	int32;
		double d;
		float f;
		void*	pv;
		SAFEARRAY* psa;
		VARIANT* pvar;
		VARIANT_BOOL vbool;
//	};

	HRESULT hr;

	const int paramLen = env->GetArrayLength(args);

	__asm mov [spBefore],ESP;

	// push arguments to the stack
	// since we are accumlating things to the stack
	for( i=paramLen; i>=0; i-- ) {
		// to handle the case where the [retval] comes as the last in the parameter,
		// we start from i=length, not usual i=lengh-1
		unm = NULL;
		jobject arg = NULL;
		// TODO: check if we can safely use local variables

		if( i!=paramLen ) {
			arg = env->GetObjectArrayElement(args,i);
			switch( convs[i] ) {
			case cvBSTR:
				bstr = toBSTR((jstring)arg);
				_asm push bstr;
				break;

			case cvBSTR_byRef:
				if(arg==NULL) {
					pv = NULL;
				} else {
					unm = new BSTRUnmarshaller(toBSTR((jstring)jholder(arg)->get(env)));
					add( new OutParamHandler( jholder(arg), unm ) );
					pv = unm->addr();
				}
				_asm push pv;
				break;

			case cvLPCWSTR:
				lpcwstr = toLPCWSTR((jstring)arg);
				_asm push lpcwstr;
				break;

			case cvLPCSTR:
				lpcstr = toLPCSTR((jstring)arg);
				_asm push lpcstr;
				break;

			case cvINT8:
				_ASSERT( sizeof(INT8)==sizeof(jbyte) );
				int8 = javaLangNumber_byteValue(env,arg);
				_asm push int8;
				break;

			case cvINT8_byRef:
				if(arg==NULL) {
					pv = NULL;
				} else {
					unm = new ByteUnmarshaller(env,jholder(arg)->get(env));
					add(new OutParamHandler( jholder(arg), unm ) );
					pv = unm->addr();
				}
				_asm push pv;
				break;

			case cvINT16:
				_ASSERT( sizeof(INT16)==sizeof(jshort) );
				int16 = javaLangNumber_shortValue(env,arg);
				_asm push int16;
				break;

			case cvINT16_byRef:
				if(arg==NULL) {
					pv = NULL;
				} else {
					unm = new ShortUnmarshaller(env,jholder(arg)->get(env));
					add(new OutParamHandler( jholder(arg), unm ) );
					pv = unm->addr();
				}
				_asm push pv;
				break;

			case cvINT32:
			case cvComObject:
			case cvDISPATCH:
				_ASSERT( sizeof(INT32)==sizeof(jint) );
				int32 = javaLangNumber_intValue(env,arg);
				_asm push int32;
				break;

			case cvPVOID:
				pv = env->GetDirectBufferAddress(arg);
				if(pv==NULL) {
					error(env,__FILE__,__LINE__,"the given Buffer object is not a direct buffer");
					return NULL;
				}
				_asm push pv;
				break;

			case cvINT32_byRef:
				if(arg==NULL) {
					pv = NULL;
				} else {
					unm = new IntUnmarshaller(env,jholder(arg)->get(env));
					add( new OutParamHandler( jholder(arg), unm ) );
					pv = unm->addr();
				}
				_asm push pv;
				break;

			case cvDATE:
			case cvDouble:
				// TODO: check if this is correct
				d = javaLangNumber_doubleValue(env,arg);
				f = reinterpret_cast<float*>(&d)[1];
				_asm push f;
				f = reinterpret_cast<float*>(&d)[0];
				_asm push f;
				break;

			case cvFloat:
				f = javaLangNumber_floatValue(env,arg);
				_asm push f;
				break;

			case cvBool:
				if(javaLangBoolean_booleanValue(env,arg)) {
					int32 = TRUE;
				} else {
					int32 = FALSE;
				}
				_asm push int32;
				break;

			case cvVariantBool:
				if(javaLangBoolean_booleanValue(env,arg)) {
					vbool = VARIANT_TRUE;
				} else {
					vbool = VARIANT_FALSE;
				}
				_asm push vbool;
				break;

			case cvVariantBool_byRef:
				if(arg==NULL) {
					pv = NULL;
				} else {
					unm = new VariantBoolUnmarshaller(env,jholder(arg)->get(env));
					add( new OutParamHandler( jholder(arg), unm ) );
					pv = unm->addr();
				}
				_asm push pv;
				break;

			case cvGUID:
				_ASSERT( sizeof(GUID)==sizeof(jlong)*2 );
				pv = env->GetLongArrayElements( (jlongArray)arg, NULL );
				add(new LongArrayCleanUp((jlongArray)arg,pv));
				_asm push pv;
				break;

			case cvVARIANT:
				_ASSERT(sizeof(VARIANT)==0x10);
				_asm sub ESP,0x10;
				_asm mov [pvar],ESP;

				if(env->IsSameObject(env->GetObjectClass(arg),com4j_Variant)) {
					// if we got a com4j.Variant object, create its copy
					jobject img = env->GetObjectField(arg,com4j_Variant_image);
					VariantCopy(pvar,(VARIANT*)env->GetDirectBufferAddress(img));
				} else {
					// otherwise convert a value to a VARIANT, and simply use that for the stack var.
					// since we aren't using VariantCopy, there's no need to VariantClear pSrc.
					VARIANT* pSrc = convertToVariant(env,arg);
					*reinterpret_cast<VARIANT*>(pvar) = *pSrc;
					delete pSrc;
				}
				break;

			case cvVARIANT_byRef:
				if(env->IsSameObject(env->GetObjectClass(arg),com4j_Variant)) {
					// if we got a com4j.Variant object, pass its image
					jobject img = env->GetObjectField(arg,com4j_Variant_image);
					pvar = (VARIANT*)env->GetDirectBufferAddress(img);
				} else {
					// otherwise convert a value to a VARIANT
					pvar = convertToVariant(env,arg);
					add(new VARIANTCleanUp(pvar));
				}
				_asm push pvar;
				break;

			case cvSAFEARRAY:
				psa = safearray::SafeArrayXducer::toNative(env,(jarray)arg);
				if(psa==NULL) {
					error(env,__FILE__,__LINE__,"unable to convert the given array to SAFEARRAY");
					return NULL;
				}
				add( new SAFEARRAYCleanUp(psa) );
				_asm push psa;
				break;

			default:
				error(env,__FILE__,__LINE__,"unexpected conversion type: %d",convs[i]);
				return NULL;
			}
		}

		if(i==retIndex) {
			if(retIsInOut) {
				// reuse the current unmarshaller
				if(unm==NULL) {
					error(env,__FILE__,__LINE__,"in/out return value must be passed by ref");
					return NULL;
				}
				retUnm = unm;
			} else {
				switch(retConv) {
				case cvBSTR:
					retUnm = new BSTRUnmarshaller(NULL);
					break;

				case cvHRESULT:
					// this is a special case which we handle later
					break;

				case cvComObject:
				case cvDISPATCH:
					retUnm = new ComObjectUnmarshaller();
					break;

				case cvINT32:
					retUnm = new IntUnmarshaller(env,NULL);
					break;

				case cvBool:
				case cvVariantBool:
					retUnm = new BoolUnmarshaller(env,NULL);
					break;

				case cvFloat:
					retUnm = new FloatUnmarshaller(env,NULL);
					break;

				case cvDouble:
				case cvDATE:
					retUnm = new DoubleUnmarshaller(env,NULL);
					break;

				case cvGUID:
					retUnm = new GUIDUnmarshaller();
					break;

				case cvVARIANT_byRef:
					retUnm = new VariantUnmarshaller(retType);
					break;

				default:
					error(env,__FILE__,__LINE__,"unexpected conversion type: %d",retConv);
					return NULL;
				}

				if(retUnm!=NULL) {
					pv = retUnm->addr();
					_asm push pv;
				}
			}
		}
	}

#ifdef	_DEBUG
	invocationCount++;	// for debugging. this makes it easier to set a break-point.
#endif

	// push the 'this' pointer
	__asm push pComObject;

	// invoke the method.
	__asm call method;

	__asm mov [spAfter],ESP;

	// once the call returns, stack should have been cleaned up,
	// and the return value should be in EAX.
	__asm mov hr,EAX;

	// check that the stack size is correct
	if(spBefore!=spAfter) {
		__asm mov ESP, [spBefore];
		error(env,__FILE__,__LINE__,"Unexpected stack corruption. Is the method definition correct?");
		return NULL;
	}

	// if the caller wants the HRESULT as the return value,
	// don't throw ComException
	if(retConv==cvHRESULT) {
		jclass javaLangInteger = env->FindClass("java/lang/Integer");
		return env->NewObject(
			javaLangInteger,
			env->GetMethodID(javaLangInteger,"<init>","(I)V"),
			hr );
	}

	// otherwise check the HRESULT first
	if(FAILED(hr)) {
		wchar_t* pmsg = NULL;
		jobject str = NULL;
		if(!FAILED(FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr, 0, (LPWSTR)&pmsg, 0, NULL ))) {
			if(pmsg!=NULL) {
				str = env->NewString(pmsg,wcslen(pmsg));
				LocalFree(pmsg);
			}
		}
		env->Throw( (jthrowable)comexception_new_hr(env, str, (jint)hr, env->NewStringUTF(__FILE__), (jint)__LINE__ ) );
	}

	if(retUnm==NULL)	return NULL;
	jobject r = retUnm->unmarshal(env);
	if(!retIsInOut)
		// if retIsInOut, it will be cleaned up by a holder.
		delete retUnm;
	return r;
}

void Environment::add( PostAction* a ) {
	a->next = postActions;
	postActions = a;
}

const jchar* Environment::toChars( jstring s ) {
	if(s==NULL)		return NULL;

	const jchar* r = env->GetStringChars(s,NULL);

	class ReleaseStringCharsCleanUp : public PostAction {
		const jchar*	buf;
		jstring			str;
	public:
		ReleaseStringCharsCleanUp( jstring _str, const jchar* _buf ) {
			str = _str;
			buf = _buf;
		}
		void act( JNIEnv* env ) {
			env->ReleaseStringChars(str,buf);
		}
	};

	add( new ReleaseStringCharsCleanUp(s,r) );
	return r;
}

const wchar_t* Environment::toLPCWSTR( jstring s ) {
	if(s==NULL)		return NULL;

	_ASSERT( sizeof(jchar)==sizeof(wchar_t) );

	const jchar* r = toChars(s);
	jsize sz = env->GetStringLength(s);
	wchar_t* buf = new wchar_t[sz+1];
	memcpy(buf,r,sz*sizeof(wchar_t));
	buf[sz]=L'\0';
	add( new DeleteCleanUp<wchar_t>(buf) );
	return buf;
}

LPCSTR Environment::toLPCSTR( jstring s ) {
	if(s==NULL)		return NULL;

	const jchar* r = toChars(s);
	jsize sz = env->GetStringLength(s);
	char* buf = new char[sz*2+1];
	int len = WideCharToMultiByte( CP_ACP, 0, r, sz, buf, sz*2+1, NULL, NULL );
	buf[len] = '\0';
	add( new DeleteCleanUp<char>(buf) );
	return buf;
}

BSTR Environment::toBSTR( jstring s ) {
	if(s==NULL)		return NULL;

	BSTR bstr = SysAllocStringLen(toChars(s),env->GetStringLength(s));
	add(new BSTRCleanUp(bstr));
	return bstr;
}
<commit_msg>size of the VARIANT_BOOL stack was wrong<commit_after>#include "stdafx.h"
#include "com4j.h"
#include "unmarshaller.h"
#include "safearray.h"

Environment::~Environment() {
	// run post actions
	while( postActions!=NULL ) {
		postActions->act(env);
		PostAction* old = postActions;
		postActions = postActions->next;
		delete old;
	}
}

#ifdef	_DEBUG
static int invocationCount = 0;
#endif

jobject Environment::invoke( void* pComObject, ComMethod method, jobjectArray args, jint* convs,
	jclass retType, int retIndex, bool retIsInOut, jint retConv ) {
	// list of clean up actions

	int i;
	DWORD spBefore,spAfter;
	// the unmarshaller if this method should return an object.
	Unmarshaller* retUnm = NULL;

// somehow anonymous union here makes the compiler upset
// --- when we do "push pv" it pushes something different!
//	union {
		BSTR bstr;
		Unmarshaller* unm;
		const wchar_t*	lpcwstr;
		const char*		lpcstr;
		INT8	int8;
		INT16	int16;
		INT32	int32;
		double d;
		float f;
		void*	pv;
		SAFEARRAY* psa;
		VARIANT* pvar;
		// VARIANT_BOOL vbool;
//	};

	HRESULT hr;

	const int paramLen = env->GetArrayLength(args);

	__asm mov [spBefore],ESP;

	// push arguments to the stack
	// since we are accumlating things to the stack
	for( i=paramLen; i>=0; i-- ) {
		// to handle the case where the [retval] comes as the last in the parameter,
		// we start from i=length, not usual i=lengh-1
		unm = NULL;
		jobject arg = NULL;
		// TODO: check if we can safely use local variables

		if( i!=paramLen ) {
			arg = env->GetObjectArrayElement(args,i);
			switch( convs[i] ) {
			case cvBSTR:
				bstr = toBSTR((jstring)arg);
				_asm push bstr;
				break;

			case cvBSTR_byRef:
				if(arg==NULL) {
					pv = NULL;
				} else {
					unm = new BSTRUnmarshaller(toBSTR((jstring)jholder(arg)->get(env)));
					add( new OutParamHandler( jholder(arg), unm ) );
					pv = unm->addr();
				}
				_asm push pv;
				break;

			case cvLPCWSTR:
				lpcwstr = toLPCWSTR((jstring)arg);
				_asm push lpcwstr;
				break;

			case cvLPCSTR:
				lpcstr = toLPCSTR((jstring)arg);
				_asm push lpcstr;
				break;

			case cvINT8:
				_ASSERT( sizeof(INT8)==sizeof(jbyte) );
				int8 = javaLangNumber_byteValue(env,arg);
				_asm push int8;
				break;

			case cvINT8_byRef:
				if(arg==NULL) {
					pv = NULL;
				} else {
					unm = new ByteUnmarshaller(env,jholder(arg)->get(env));
					add(new OutParamHandler( jholder(arg), unm ) );
					pv = unm->addr();
				}
				_asm push pv;
				break;

			case cvINT16:
				_ASSERT( sizeof(INT16)==sizeof(jshort) );
				int16 = javaLangNumber_shortValue(env,arg);
				_asm push int16;
				break;

			case cvINT16_byRef:
				if(arg==NULL) {
					pv = NULL;
				} else {
					unm = new ShortUnmarshaller(env,jholder(arg)->get(env));
					add(new OutParamHandler( jholder(arg), unm ) );
					pv = unm->addr();
				}
				_asm push pv;
				break;

			case cvINT32:
			case cvComObject:
			case cvDISPATCH:
				_ASSERT( sizeof(INT32)==sizeof(jint) );
				int32 = javaLangNumber_intValue(env,arg);
				_asm push int32;
				break;

			case cvPVOID:
				pv = env->GetDirectBufferAddress(arg);
				if(pv==NULL) {
					error(env,__FILE__,__LINE__,"the given Buffer object is not a direct buffer");
					return NULL;
				}
				_asm push pv;
				break;

			case cvINT32_byRef:
				if(arg==NULL) {
					pv = NULL;
				} else {
					unm = new IntUnmarshaller(env,jholder(arg)->get(env));
					add( new OutParamHandler( jholder(arg), unm ) );
					pv = unm->addr();
				}
				_asm push pv;
				break;

			case cvDATE:
			case cvDouble:
				// TODO: check if this is correct
				d = javaLangNumber_doubleValue(env,arg);
				f = reinterpret_cast<float*>(&d)[1];
				_asm push f;
				f = reinterpret_cast<float*>(&d)[0];
				_asm push f;
				break;

			case cvFloat:
				f = javaLangNumber_floatValue(env,arg);
				_asm push f;
				break;

			case cvBool:
				if(javaLangBoolean_booleanValue(env,arg)) {
					int32 = TRUE;
				} else {
					int32 = FALSE;
				}
				_asm push int32;
				break;

			case cvVariantBool:
				if(javaLangBoolean_booleanValue(env,arg)) {
					int32 = VARIANT_TRUE;
				} else {
					int32 = VARIANT_FALSE;
				}
				_asm push int32;
				break;

			case cvVariantBool_byRef:
				if(arg==NULL) {
					pv = NULL;
				} else {
					unm = new VariantBoolUnmarshaller(env,jholder(arg)->get(env));
					add( new OutParamHandler( jholder(arg), unm ) );
					pv = unm->addr();
				}
				_asm push pv;
				break;

			case cvGUID:
				_ASSERT( sizeof(GUID)==sizeof(jlong)*2 );
				pv = env->GetLongArrayElements( (jlongArray)arg, NULL );
				add(new LongArrayCleanUp((jlongArray)arg,pv));
				_asm push pv;
				break;

			case cvVARIANT:
				_ASSERT(sizeof(VARIANT)==0x10);
				_asm sub ESP,0x10;
				_asm mov [pvar],ESP;

				if(env->IsSameObject(env->GetObjectClass(arg),com4j_Variant)) {
					// if we got a com4j.Variant object, create its copy
					jobject img = env->GetObjectField(arg,com4j_Variant_image);
					VariantCopy(pvar,(VARIANT*)env->GetDirectBufferAddress(img));
				} else {
					// otherwise convert a value to a VARIANT, and simply use that for the stack var.
					// since we aren't using VariantCopy, there's no need to VariantClear pSrc.
					VARIANT* pSrc = convertToVariant(env,arg);
					*reinterpret_cast<VARIANT*>(pvar) = *pSrc;
					delete pSrc;
				}
				break;

			case cvVARIANT_byRef:
				if(env->IsSameObject(env->GetObjectClass(arg),com4j_Variant)) {
					// if we got a com4j.Variant object, pass its image
					jobject img = env->GetObjectField(arg,com4j_Variant_image);
					pvar = (VARIANT*)env->GetDirectBufferAddress(img);
				} else {
					// otherwise convert a value to a VARIANT
					pvar = convertToVariant(env,arg);
					add(new VARIANTCleanUp(pvar));
				}
				_asm push pvar;
				break;

			case cvSAFEARRAY:
				psa = safearray::SafeArrayXducer::toNative(env,(jarray)arg);
				if(psa==NULL) {
					error(env,__FILE__,__LINE__,"unable to convert the given array to SAFEARRAY");
					return NULL;
				}
				add( new SAFEARRAYCleanUp(psa) );
				_asm push psa;
				break;

			default:
				error(env,__FILE__,__LINE__,"unexpected conversion type: %d",convs[i]);
				return NULL;
			}
		}

		if(i==retIndex) {
			if(retIsInOut) {
				// reuse the current unmarshaller
				if(unm==NULL) {
					error(env,__FILE__,__LINE__,"in/out return value must be passed by ref");
					return NULL;
				}
				retUnm = unm;
			} else {
				switch(retConv) {
				case cvBSTR:
					retUnm = new BSTRUnmarshaller(NULL);
					break;

				case cvHRESULT:
					// this is a special case which we handle later
					break;

				case cvComObject:
				case cvDISPATCH:
					retUnm = new ComObjectUnmarshaller();
					break;

				case cvINT32:
					retUnm = new IntUnmarshaller(env,NULL);
					break;

				case cvBool:
				case cvVariantBool:
					retUnm = new BoolUnmarshaller(env,NULL);
					break;

				case cvFloat:
					retUnm = new FloatUnmarshaller(env,NULL);
					break;

				case cvDouble:
				case cvDATE:
					retUnm = new DoubleUnmarshaller(env,NULL);
					break;

				case cvGUID:
					retUnm = new GUIDUnmarshaller();
					break;

				case cvVARIANT_byRef:
					retUnm = new VariantUnmarshaller(retType);
					break;

				default:
					error(env,__FILE__,__LINE__,"unexpected conversion type: %d",retConv);
					return NULL;
				}

				if(retUnm!=NULL) {
					pv = retUnm->addr();
					_asm push pv;
				}
			}
		}
	}

#ifdef	_DEBUG
	invocationCount++;	// for debugging. this makes it easier to set a break-point.
#endif

	// push the 'this' pointer
	__asm push pComObject;

	// invoke the method.
	__asm call method;

	__asm mov [spAfter],ESP;

	// once the call returns, stack should have been cleaned up,
	// and the return value should be in EAX.
	__asm mov hr,EAX;

	// check that the stack size is correct
	if(spBefore!=spAfter) {
		__asm mov ESP, [spBefore];
		error(env,__FILE__,__LINE__,"Unexpected stack corruption. Is the method definition correct?");
		return NULL;
	}

	// if the caller wants the HRESULT as the return value,
	// don't throw ComException
	if(retConv==cvHRESULT) {
		jclass javaLangInteger = env->FindClass("java/lang/Integer");
		return env->NewObject(
			javaLangInteger,
			env->GetMethodID(javaLangInteger,"<init>","(I)V"),
			hr );
	}

	// otherwise check the HRESULT first
	if(FAILED(hr)) {
		wchar_t* pmsg = NULL;
		jobject str = NULL;
		if(!FAILED(FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr, 0, (LPWSTR)&pmsg, 0, NULL ))) {
			if(pmsg!=NULL) {
				str = env->NewString(pmsg,wcslen(pmsg));
				LocalFree(pmsg);
			}
		}
		env->Throw( (jthrowable)comexception_new_hr(env, str, (jint)hr, env->NewStringUTF(__FILE__), (jint)__LINE__ ) );
	}

	if(retUnm==NULL)	return NULL;
	jobject r = retUnm->unmarshal(env);
	if(!retIsInOut)
		// if retIsInOut, it will be cleaned up by a holder.
		delete retUnm;
	return r;
}

void Environment::add( PostAction* a ) {
	a->next = postActions;
	postActions = a;
}

const jchar* Environment::toChars( jstring s ) {
	if(s==NULL)		return NULL;

	const jchar* r = env->GetStringChars(s,NULL);

	class ReleaseStringCharsCleanUp : public PostAction {
		const jchar*	buf;
		jstring			str;
	public:
		ReleaseStringCharsCleanUp( jstring _str, const jchar* _buf ) {
			str = _str;
			buf = _buf;
		}
		void act( JNIEnv* env ) {
			env->ReleaseStringChars(str,buf);
		}
	};

	add( new ReleaseStringCharsCleanUp(s,r) );
	return r;
}

const wchar_t* Environment::toLPCWSTR( jstring s ) {
	if(s==NULL)		return NULL;

	_ASSERT( sizeof(jchar)==sizeof(wchar_t) );

	const jchar* r = toChars(s);
	jsize sz = env->GetStringLength(s);
	wchar_t* buf = new wchar_t[sz+1];
	memcpy(buf,r,sz*sizeof(wchar_t));
	buf[sz]=L'\0';
	add( new DeleteCleanUp<wchar_t>(buf) );
	return buf;
}

LPCSTR Environment::toLPCSTR( jstring s ) {
	if(s==NULL)		return NULL;

	const jchar* r = toChars(s);
	jsize sz = env->GetStringLength(s);
	char* buf = new char[sz*2+1];
	int len = WideCharToMultiByte( CP_ACP, 0, r, sz, buf, sz*2+1, NULL, NULL );
	buf[len] = '\0';
	add( new DeleteCleanUp<char>(buf) );
	return buf;
}

BSTR Environment::toBSTR( jstring s ) {
	if(s==NULL)		return NULL;

	BSTR bstr = SysAllocStringLen(toChars(s),env->GetStringLength(s));
	add(new BSTRCleanUp(bstr));
	return bstr;
}
<|endoftext|>