<commit_before>/** Copyright (C) 2012 Aldebaran Robotics
*/

#ifndef _WIN32
#include <fnmatch.h>
#else
# include <shlwapi.h>
# pragma comment(lib, "shlwapi.lib")
#endif

#include <boost/program_options.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/foreach.hpp>

#include <qi/log.hpp>
#include <qi/application.hpp>
#include <qimessaging/session.hpp>
#include <qitype/jsoncodec.hpp>

#define foreach BOOST_FOREACH

const char* callType[] = {
  "?", "C", "R", "E", "S"
};
typedef std::map<std::string, qi::AnyObject> ObjectMap;
ObjectMap objectMap;

bool numeric = false;
bool printMo = false;
bool disableTrace = false;
bool traceState = false;
bool cleaned = false;
std::string sdUrl;
std::vector<std::string> objectNames;
unsigned int maxServiceLength = 0;
qiLogCategory("qitrace");

void onTrace(ObjectMap::value_type ov, const qi::EventTrace& trace)
{
  static unsigned int maxLen = 0;
  std::string name = boost::lexical_cast<std::string>(trace.slotId);
  if (!numeric)
  {
    qi::MetaObject mo = ov.second->metaObject();
    qi::MetaMethod* m = mo.method(trace.slotId);
    if (m)
      name = m->name();
    else
    {
      qi::MetaSignal* s = mo.signal(trace.slotId);
      if (s)
        name = s->name();
      else
        name = name + "(??" ")"; // trigraph protect mode on
    }
  }
  maxLen = std::max(maxLen, (unsigned int)name.size());
  unsigned int traceKind = trace.kind;
  if (traceKind > 4)
    traceKind = 0;
  std::string spacing(maxLen + 8 - name.size(), ' ');
  std::string spacing2(maxServiceLength + 8 - ov.first.size(), ' ');
  std::cout << ov.first << spacing2 << trace.id << '\t' << callType[traceKind] << ' ' << name
   << spacing << trace.timestamp.tv_sec << '.' << trace.timestamp.tv_usec
   << "\t" << qi::encodeJSON(trace.arguments) << std::endl;
}

_QI_COMMAND_LINE_OPTIONS(
  "Qitrace options",
  ("numeric,n", bool_switch(&numeric), "Do not resolve slot Ids to names")
  ("service-directory,s", value<std::string>(&sdUrl), "url to connect to")
  ("object,o", value<std::vector<std::string> >(&objectNames), "Object(s) to monitor, specify multiple times, comma-separate, use '*' for all, use '-globPattern' to remove from list")
  ("print,p", bool_switch(&printMo), "Print out the Metaobject and exit")
  ("disable,d", bool_switch(&disableTrace), "Disable trace on objects and exit")
  ("trace-status", bool_switch(&traceState), "Show trace status on objects and exit")
  );

int main(int argc, char** argv)
{
  qi::Application app(argc, argv);
  if (std::find(argv + 1, argv + argc, std::string("-h"))-argv < argc
    ||  std::find(argv + 1, argv + argc, std::string("--help"))-argv < argc)
    return 0; // Fixme have Application report that!
  qi::Session s;
  if (sdUrl.empty())
    sdUrl = "localhost";
  qi::Url url(sdUrl, "tcp", 9559);
  qiLogVerbose() << "Connecting to sd";
  s.connect(url);
  qiLogVerbose() << "Resolving services";
  // resolve target service names
  std::vector<std::string> services;
  for (unsigned i=0; i<objectNames.size(); ++i)
  {

    std::vector<std::string> split;
    boost::split(split, objectNames[i], boost::algorithm::is_any_of(","));
    for (unsigned i=0; i<split.size(); ++i)
    {
      if (split[i].empty())
        continue;
      else if (split[i] == "*")
      {
        std::vector<qi::ServiceInfo> si = s.services();
        for (unsigned i=0; i<si.size(); ++i)
          services.push_back(si[i].name());
      }
      else if (split[i][0] == '-')
      {
        std::string pattern = split[i].substr(1);
        for (unsigned i=0; i<services.size(); ++i)
        {
          if (qi::os::fnmatch(pattern, services[i]))
          {
            services[i] = services[services.size() - 1];
            services.pop_back();
            --i; // don't forget to check the new element we juste swaped in
          }
        }
      }
      else
        services.push_back(split[i]);
    }

  }
  std::vector<std::string> servicesOk;
  qiLogVerbose() << "Fetching services: " << boost::join(services, ",");
  // access services
  for (unsigned i=0; i<services.size(); ++i)
  {
    qi::AnyObject o;
    try
    {
      o = s.service(services[i]);
    }
    catch (const std::exception& e)
    {
      qiLogError() << "Error fetching " << services[i] << " : " << e.what();
      services[i] = "";
      continue;
    }
    if (!o)
    {
      qiLogError() << "Error fetching " << services[i];
      services[i] = "";
      continue;
    }
    objectMap[services[i]] = o;
    servicesOk.push_back(services[i]);
    if (printMo)
    {
      std::cout << "\n\n" << services[i] << "\n";
      qi::details::printMetaObject(std::cout, o->metaObject());
    }
    if (disableTrace)
    {
      try
      {
        o->call<void>("enableTrace", false);
      }
      catch(...)
      {}
    }
    if (traceState)
    {
      try
      {
        bool s = o->call<bool>("isTraceEnabled");
        std::cout << services[i] << ": " << s << std::endl;
      }
      catch(...)
      {}
    }
  }

  if (printMo || disableTrace || traceState || objectMap.empty())
    return 0;

  qiLogVerbose() << "Monitoring services: " << boost::join(servicesOk, ",");
  foreach(ObjectMap::value_type& ov, objectMap)
  {
    maxServiceLength = std::max(maxServiceLength, (unsigned int)ov.first.size());
    ov.second->connect("traceObject", (boost::function<void(qi::EventTrace)>)
      boost::bind(&onTrace, ov, _1)).async();
  }
  app.run();
  while (!cleaned)
    qi::os::msleep(20);
  return 0;
}
<commit_msg>qitrace: more compressed output, display call user/system time used.<commit_after>/** Copyright (C) 2012 Aldebaran Robotics
*/

#include <boost/program_options.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/foreach.hpp>

#include <qi/log.hpp>
#include <qi/os.hpp>
#include <qi/application.hpp>
#include <qimessaging/session.hpp>
#include <qitype/jsoncodec.hpp>

#define foreach BOOST_FOREACH

const char* callType[] = {
  "?", "C", "R", "E", "S"
};
typedef std::map<std::string, qi::AnyObject> ObjectMap;
ObjectMap objectMap;

bool numeric = false;
bool printMo = false;
bool disableTrace = false;
bool traceState = false;
bool cleaned = false;
bool full = false;
std::string sdUrl;
std::vector<std::string> objectNames;
unsigned int maxServiceLength = 0;
qiLogCategory("qitrace");

void onTrace(ObjectMap::value_type ov, const qi::EventTrace& trace)
{
  static qi::int64_t secStart = 0;
  if (!secStart && !full)
    secStart = trace.timestamp().tv_sec;
  static unsigned int maxLen = 0;
  std::string name = boost::lexical_cast<std::string>(trace.slotId());
  if (!numeric)
  {
    qi::MetaObject mo = ov.second->metaObject();
    qi::MetaMethod* m = mo.method(trace.slotId());
    if (m)
      name = m->name();
    else
    {
      qi::MetaSignal* s = mo.signal(trace.slotId());
      if (s)
        name = s->name();
      else
        name = name + "(??" ")"; // trigraph protect mode on
    }
  }
  if (!full && name.size() > 25)
  {
    name = name.substr(0, 22) + "...";
  }
  std::string serviceName = ov.first;
  if (!full && serviceName.size() > 17)
    serviceName = serviceName.substr(0, 14) + "...";
  maxLen = std::max(maxLen, (unsigned int)name.size());
  unsigned int traceKind = trace.kind();
  if (traceKind > 4)
    traceKind = 0;
  std::string spacing(maxLen + 2 - name.size(), ' ');
  std::string spacing2((full?maxServiceLength:17) + 2 - ov.first.size(), ' ');
  if (trace.kind() == qi::EventTrace::Event_Result)
  {
    std::cout << serviceName << spacing2 << trace.id() << ' ' << callType[traceKind] << ' ' << name
      << spacing << (trace.timestamp().tv_sec - secStart) << '.' << trace.timestamp().tv_usec
      << ' ' << trace.userUsTime() << ' ' << trace.systemUsTime() << ' ' << qi::encodeJSON(trace.arguments()) << std::endl;
  }
  else
  {
    std::cout << serviceName << spacing2 << trace.id() << ' ' << callType[traceKind] << ' ' << name
      << spacing << (trace.timestamp().tv_sec - secStart) << '.' << trace.timestamp().tv_usec
      << ' ' << qi::encodeJSON(trace.arguments()) << std::endl;
  }
}

_QI_COMMAND_LINE_OPTIONS(
  "Qitrace options",
  ("numeric,n", bool_switch(&numeric), "Do not resolve slot Ids to names")
  ("full,f", bool_switch(&full), "Do not abreviate anything")
  ("service-directory,s", value<std::string>(&sdUrl), "url to connect to")
  ("object,o", value<std::vector<std::string> >(&objectNames), "Object(s) to monitor, specify multiple times, comma-separate, use '*' for all, use '-globPattern' to remove from list")
  ("print,p", bool_switch(&printMo), "Print out the Metaobject and exit")
  ("disable,d", bool_switch(&disableTrace), "Disable trace on objects and exit")
  ("trace-status", bool_switch(&traceState), "Show trace status on objects and exit")
  );

int main(int argc, char** argv)
{
  qi::Application app(argc, argv);
  if (std::find(argv + 1, argv + argc, std::string("-h"))-argv < argc
    ||  std::find(argv + 1, argv + argc, std::string("--help"))-argv < argc)
    return 0; // Fixme have Application report that!
  qi::Session s;
  if (sdUrl.empty())
    sdUrl = "localhost";
  qi::Url url(sdUrl, "tcp", 9559);
  qiLogVerbose() << "Connecting to sd";
  s.connect(url);
  qiLogVerbose() << "Resolving services";
  // resolve target service names
  std::vector<std::string> services;
  for (unsigned i=0; i<objectNames.size(); ++i)
  {

    std::vector<std::string> split;
    boost::split(split, objectNames[i], boost::algorithm::is_any_of(","));
    for (unsigned i=0; i<split.size(); ++i)
    {
      if (split[i].empty())
        continue;
      else if (split[i] == "*")
      {
        std::vector<qi::ServiceInfo> si = s.services();
        for (unsigned i=0; i<si.size(); ++i)
          services.push_back(si[i].name());
      }
      else if (split[i][0] == '-')
      {
        std::string pattern = split[i].substr(1);
        for (unsigned i=0; i<services.size(); ++i)
        {
          if (qi::os::fnmatch(pattern, services[i]))
          {
            services[i] = services[services.size() - 1];
            services.pop_back();
            --i; // don't forget to check the new element we juste swaped in
          }
        }
      }
      else
        services.push_back(split[i]);
    }

  }
  std::vector<std::string> servicesOk;
  qiLogVerbose() << "Fetching services: " << boost::join(services, ",");
  // access services
  for (unsigned i=0; i<services.size(); ++i)
  {
    qi::AnyObject o;
    try
    {
      o = s.service(services[i]);
    }
    catch (const std::exception& e)
    {
      qiLogError() << "Error fetching " << services[i] << " : " << e.what();
      services[i] = "";
      continue;
    }
    if (!o)
    {
      qiLogError() << "Error fetching " << services[i];
      services[i] = "";
      continue;
    }
    objectMap[services[i]] = o;
    servicesOk.push_back(services[i]);
    if (printMo)
    {
      std::cout << "\n\n" << services[i] << "\n";
      qi::details::printMetaObject(std::cout, o->metaObject());
    }
    if (disableTrace)
    {
      try
      {
        o->call<void>("enableTrace", false);
      }
      catch(...)
      {}
    }
    if (traceState)
    {
      try
      {
        bool s = o->call<bool>("isTraceEnabled");
        std::cout << services[i] << ": " << s << std::endl;
      }
      catch(...)
      {}
    }
  }

  if (printMo || disableTrace || traceState || objectMap.empty())
    return 0;

  qiLogVerbose() << "Monitoring services: " << boost::join(servicesOk, ",");
  foreach(ObjectMap::value_type& ov, objectMap)
  {
    maxServiceLength = std::max(maxServiceLength, (unsigned int)ov.first.size());
    ov.second->connect("traceObject", (boost::function<void(qi::EventTrace)>)
      boost::bind(&onTrace, ov, _1)).async();
  }
  app.run();
  while (!cleaned)
    qi::os::msleep(20);
  return 0;
}
<|endoftext|>


<commit_before>/*
kmsc - Kurento Media Server C/C++ implementation
Copyright (C) 2012 Tikal Technologies

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 3
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "JoinableServiceHandler.h"

#include <log.h>

using ::com::kurento::kms::JoinableServiceHandler;
using ::com::kurento::kms::MediaSessionImpl;
using ::com::kurento::kms::JoinableImpl;
using ::com::kurento::commons::mediaspec::_Direction_VALUES_TO_NAMES;

using ::com::kurento::log::Log;

static Log l("JoinableServiceHandler");
#define i(...) aux_info(l, __VA_ARGS__);
#define d(...) aux_debug(l, __VA_ARGS__);
#define w(...) aux_warn(l, __VA_ARGS__);
#define e(...) aux_error(l, __VA_ARGS__);

JoinableServiceHandler::JoinableServiceHandler() {
	manager = MediaSessionManager::getInstance();
}

JoinableServiceHandler::~JoinableServiceHandler() {
	MediaSessionManager::releaseInstance(manager);
}

void
JoinableServiceHandler::getStreams(std::vector<StreamType::type> &_return,
						const Joinable& joinable) {
	i("getStreams from joinable: %lld", joinable.object.id);
	try {
		MediaSessionImpl &session = manager->getMediaSession(joinable.session);
		JoinableImpl &j = session.getJoinable(joinable);
		j.getStreams(_return);
	} catch(JoinableNotFoundException ex) {
		throw ex;
	} catch (MediaSessionNotFoundException ex) {
		JoinableNotFoundException e;
		e.__set_description("MediaSession not found");
		throw e;
	} catch (MediaServerException ex) {
		throw ex;
	} catch (...) {
		MediaServerException ex;
		ex.__set_description("Unkown exception found");
		ex.__set_code(ErrorCode::type::UNEXPECTED);
		throw ex;
	}
}

void
JoinableServiceHandler::join(const Joinable& from, const Joinable& to,
					const Direction direction) {
	if (_Direction_VALUES_TO_NAMES.find(direction) == _Direction_VALUES_TO_NAMES.end()) {
		JoinException ex;
		ex.__set_description("Invalid direction");
		throw ex;
	}

	i("join %lld and %lld with direction %s", from.object.id, to.object.id,
			_Direction_VALUES_TO_NAMES.find(direction)->second);
	try {
		if (from.session != to.session) {
			JoinException ex;
			ex.__set_description("Joinables are not in the same "
								"session");
			throw ex;
		}
		MediaSessionImpl &session = manager->getMediaSession(from.session);
		JoinableImpl &f = session.getJoinable(from);
		JoinableImpl &t = session.getJoinable(to);
		f.join(t, direction);
	} catch(JoinException ex){
		throw ex;
	} catch(JoinableNotFoundException ex) {
		throw ex;
	} catch (MediaSessionNotFoundException ex) {
		JoinableNotFoundException e;
		e.__set_description("MediaSession not found");
		throw e;
	} catch (MediaServerException ex) {
		throw ex;
	} catch (...) {
		MediaServerException ex;
		ex.__set_description("Unkown exception found");
		ex.__set_code(ErrorCode::type::UNEXPECTED);
		throw ex;
	}
}

void
JoinableServiceHandler::unjoin(const Joinable& from, const Joinable& to) {
	i("unjoin %lld and %lld", from.object.id, to.object.id);
	try {
		if (from.session != to.session) {
			JoinException ex;
			ex.__set_description("Joinables are not in the same "
			"session");
			throw ex;
		}
		MediaSessionImpl &session = manager->getMediaSession(from.session);
		JoinableImpl &f = session.getJoinable(from);
		JoinableImpl &t = session.getJoinable(to);
		f.unjoin(t);
	} catch(JoinException ex){
		throw ex;
	} catch(JoinableNotFoundException ex) {
		throw ex;
	} catch (MediaSessionNotFoundException ex) {
		JoinableNotFoundException e;
		e.__set_description("MediaSession not found");
		throw e;
	} catch (MediaServerException ex) {
		throw ex;
	} catch (...) {
		MediaServerException ex;
		ex.__set_description("Unkown exception found");
		ex.__set_code(ErrorCode::type::UNEXPECTED);
		throw ex;
	}
}

void
JoinableServiceHandler::joinStream(const Joinable& from, const Joinable& to,
					const StreamType::type stream,
					const Direction direction) {
	if (_Direction_VALUES_TO_NAMES.find(direction) ==
					_Direction_VALUES_TO_NAMES.end()) {
		JoinException ex;
		ex.__set_description("Invalid direction");
		throw ex;
	}

	if (_StreamType_VALUES_TO_NAMES.find(stream) ==
					_StreamType_VALUES_TO_NAMES.end()) {
		JoinException ex;
		ex.__set_description("Invalid stream");
		throw ex;
	}

	i("joinStream %s of %lld with %lld with direction %s",
			_StreamType_VALUES_TO_NAMES.find(stream)->second,
			from.object.id, to.object.id,
			_Direction_VALUES_TO_NAMES.find(direction)->second);
	try {
		if (from.session != to.session) {
			JoinException ex;
			ex.__set_description("Joinables are not in the same "
			"session");
			throw ex;
		}
		MediaSessionImpl &session = manager->getMediaSession(from.session);
		JoinableImpl &f = session.getJoinable(from);
		JoinableImpl &t = session.getJoinable(to);
		f.join(t, stream, direction);
	} catch(StreamNotFoundException ex) {
		throw ex;
	} catch(JoinException ex){
		throw ex;
	} catch(JoinableNotFoundException ex) {
		throw ex;
	} catch (MediaSessionNotFoundException ex) {
		JoinableNotFoundException e;
		e.__set_description("MediaSession not found");
		throw e;
	} catch (MediaServerException ex) {
		throw ex;
	} catch (...) {
		MediaServerException ex;
		ex.__set_description("Unkown exception found");
		ex.__set_code(ErrorCode::type::UNEXPECTED);
		throw ex;
	}
}

void
JoinableServiceHandler::unjoinStream(const Joinable& from, const Joinable& to,
						const StreamType::type stream) {
	if (_StreamType_VALUES_TO_NAMES.find(stream) ==
					_StreamType_VALUES_TO_NAMES.end()) {
		JoinException ex;
		ex.__set_description("Invalid stream");
		throw ex;
	}

	i("unjoinStream %s of %lld with %lld",
			_StreamType_VALUES_TO_NAMES.find(stream)->second,
			from.object.id, to.object.id);
	try {
		if (from.session != to.session) {
			JoinException ex;
			ex.__set_description("Joinables are not in the same "
			"session");
			throw ex;
		}
		MediaSessionImpl &session = manager->getMediaSession(from.session);
		JoinableImpl &f = session.getJoinable(from);
		JoinableImpl &t = session.getJoinable(to);
		f.unjoin(t, stream);
	} catch(StreamNotFoundException ex) {
		throw ex;
	} catch(JoinException ex){
		throw ex;
	} catch(JoinableNotFoundException ex) {
		throw ex;
	} catch (MediaSessionNotFoundException ex) {
		JoinableNotFoundException e;
		e.__set_description("MediaSession not found");
		throw e;
	} catch (MediaServerException ex) {
		throw ex;
	} catch (...) {
		MediaServerException ex;
		ex.__set_description("Unkown exception found");
		ex.__set_code(ErrorCode::type::UNEXPECTED);
		throw ex;
	}
}

void
JoinableServiceHandler::getJoinees(std::vector<Joinable> &_return,
							const Joinable& from) {
	i("getJoinees of %lld", from.object.id);
	try {
		MediaSessionImpl &session = manager->getMediaSession(from.session);
		JoinableImpl &f = session.getJoinable(from);
		f.getJoinees(_return);
	} catch(JoinException ex){
		throw ex;
	} catch(JoinableNotFoundException ex) {
		throw ex;
	} catch (MediaSessionNotFoundException ex) {
		JoinableNotFoundException e;
		e.__set_description("MediaSession not found");
		throw e;
	} catch (MediaServerException ex) {
		throw ex;
	} catch (...) {
		MediaServerException ex;
		ex.__set_description("Unkown exception found");
		ex.__set_code(ErrorCode::type::UNEXPECTED);
		throw ex;
	}
}

void
JoinableServiceHandler::getDirectionJoinees(std::vector<Joinable> &_return,
					const Joinable& from,
					const Direction direction) {
	if (_Direction_VALUES_TO_NAMES.find(direction) ==
					_Direction_VALUES_TO_NAMES.end()) {
		JoinException ex;
		ex.__set_description("Invalid direction");
		throw ex;
	}

	i("getDirectionJoiness of %lld with direction %s", from.object.id,
			_Direction_VALUES_TO_NAMES.find(direction)->second);
	try {
		MediaSessionImpl &session = manager->getMediaSession(from.session);
		JoinableImpl &f = session.getJoinable(from);
		f.getJoinees(_return, direction);
	} catch(JoinException ex){
		throw ex;
	} catch(JoinableNotFoundException ex) {
		throw ex;
	} catch (MediaSessionNotFoundException ex) {
		JoinableNotFoundException e;
		e.__set_description("MediaSession not found");
		throw e;
	} catch (MediaServerException ex) {
		throw ex;
	} catch (...) {
		MediaServerException ex;
		ex.__set_description("Unkown exception found");
		ex.__set_code(ErrorCode::type::UNEXPECTED);
		throw ex;
	}
}

void
JoinableServiceHandler::getStreamJoinees(std::vector<Joinable> &_return,
						const Joinable& from,
						const StreamType::type stream) {
	if (_StreamType_VALUES_TO_NAMES.find(stream) ==
					_StreamType_VALUES_TO_NAMES.end()) {
		JoinException ex;
		ex.__set_description("Invalid stream");
		throw ex;
	}

	i("getStreamJoinees of stream %s from %lld",
			_StreamType_VALUES_TO_NAMES.find(stream)->second,
			from.object.id);
	try {
		MediaSessionImpl &session = manager->getMediaSession(from.session);
		JoinableImpl &f = session.getJoinable(from);
		f.getJoinees(_return, stream);
	} catch(StreamNotFoundException ex) {
		throw ex;
	} catch(JoinException ex){
		throw ex;
	} catch(JoinableNotFoundException ex) {
		throw ex;
	} catch (MediaSessionNotFoundException ex) {
		JoinableNotFoundException e;
		e.__set_description("MediaSession not found");
		throw e;
	} catch (MediaServerException ex) {
		throw ex;
	} catch (...) {
		MediaServerException ex;
		ex.__set_description("Unkown exception found");
		ex.__set_code(ErrorCode::type::UNEXPECTED);
		throw ex;
	}
}

void
JoinableServiceHandler::getStreamDirectionJoinees(std::vector<Joinable> &_return,
						const Joinable& from,
						const StreamType::type stream,
						const Direction direction) {
	if (_StreamType_VALUES_TO_NAMES.find(stream) ==
					_StreamType_VALUES_TO_NAMES.end()) {
		JoinException ex;
		ex.__set_description("Invalid stream");
		throw ex;
	}

	if (_Direction_VALUES_TO_NAMES.find(direction) ==
					_Direction_VALUES_TO_NAMES.end()) {
		JoinException ex;
		ex.__set_description("Invalid direction");
		throw ex;
	}

	i("getStreamDirectionJoinees of stream %s from %lld with direction %s",
			_StreamType_VALUES_TO_NAMES.find(stream)->second,
			from.object.id,
			_Direction_VALUES_TO_NAMES.find(direction)->second);
	try {
		MediaSessionImpl &session = manager->getMediaSession(from.session);
		JoinableImpl &f = session.getJoinable(from);
		f.getJoinees(_return, stream, direction);
	} catch(StreamNotFoundException ex) {
		throw ex;
	} catch(JoinException ex){
		throw ex;
	} catch(JoinableNotFoundException ex) {
		throw ex;
	} catch (MediaSessionNotFoundException ex) {
		JoinableNotFoundException e;
		e.__set_description("MediaSession not found");
		throw e;
	} catch (MediaServerException ex) {
		throw ex;
	} catch (...) {
		MediaServerException ex;
		ex.__set_description("Unkown exception found");
		ex.__set_code(ErrorCode::type::UNEXPECTED);
		throw ex;
	}
}

void
JoinableServiceHandler::release(const Joinable& joinable) {
	i("release joinable %lld", joinable.object.id);

	try {
		MediaSessionImpl &session = manager->getMediaSession(joinable.session);
		session.deleteJoinable(joinable);
	} catch(JoinableNotFoundException ex) {
		throw ex;
	} catch (MediaSessionNotFoundException ex) {
		JoinableNotFoundException e;
		e.__set_description("MediaSession not found");
		throw e;
	} catch (MediaServerException ex) {
		throw ex;
	} catch (...) {
		MediaServerException ex;
		ex.__set_description("Unkown exception found");
		ex.__set_code(ErrorCode::type::UNEXPECTED);
		throw ex;
	}
}
<commit_msg>Improve exceptions thrown by release method and print them<commit_after>/*
kmsc - Kurento Media Server C/C++ implementation
Copyright (C) 2012 Tikal Technologies

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 3
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "JoinableServiceHandler.h"

#include <log.h>

using ::com::kurento::kms::JoinableServiceHandler;
using ::com::kurento::kms::MediaSessionImpl;
using ::com::kurento::kms::JoinableImpl;
using ::com::kurento::commons::mediaspec::_Direction_VALUES_TO_NAMES;

using ::com::kurento::log::Log;

static Log l("JoinableServiceHandler");
#define i(...) aux_info(l, __VA_ARGS__);
#define d(...) aux_debug(l, __VA_ARGS__);
#define w(...) aux_warn(l, __VA_ARGS__);
#define e(...) aux_error(l, __VA_ARGS__);

JoinableServiceHandler::JoinableServiceHandler() {
	manager = MediaSessionManager::getInstance();
}

JoinableServiceHandler::~JoinableServiceHandler() {
	MediaSessionManager::releaseInstance(manager);
}

void
JoinableServiceHandler::getStreams(std::vector<StreamType::type> &_return,
						const Joinable& joinable) {
	i("getStreams from joinable: %lld", joinable.object.id);
	try {
		MediaSessionImpl &session = manager->getMediaSession(joinable.session);
		JoinableImpl &j = session.getJoinable(joinable);
		j.getStreams(_return);
	} catch(JoinableNotFoundException ex) {
		throw ex;
	} catch (MediaSessionNotFoundException ex) {
		JoinableNotFoundException e;
		e.__set_description("MediaSession not found");
		throw e;
	} catch (MediaServerException ex) {
		throw ex;
	} catch (...) {
		MediaServerException ex;
		ex.__set_description("Unkown exception found");
		ex.__set_code(ErrorCode::type::UNEXPECTED);
		throw ex;
	}
}

void
JoinableServiceHandler::join(const Joinable& from, const Joinable& to,
					const Direction direction) {
	if (_Direction_VALUES_TO_NAMES.find(direction) == _Direction_VALUES_TO_NAMES.end()) {
		JoinException ex;
		ex.__set_description("Invalid direction");
		throw ex;
	}

	i("join %lld and %lld with direction %s", from.object.id, to.object.id,
			_Direction_VALUES_TO_NAMES.find(direction)->second);
	try {
		if (from.session != to.session) {
			JoinException ex;
			ex.__set_description("Joinables are not in the same "
								"session");
			throw ex;
		}
		MediaSessionImpl &session = manager->getMediaSession(from.session);
		JoinableImpl &f = session.getJoinable(from);
		JoinableImpl &t = session.getJoinable(to);
		f.join(t, direction);
	} catch(JoinException ex){
		throw ex;
	} catch(JoinableNotFoundException ex) {
		throw ex;
	} catch (MediaSessionNotFoundException ex) {
		JoinableNotFoundException e;
		e.__set_description("MediaSession not found");
		throw e;
	} catch (MediaServerException ex) {
		throw ex;
	} catch (...) {
		MediaServerException ex;
		ex.__set_description("Unkown exception found");
		ex.__set_code(ErrorCode::type::UNEXPECTED);
		throw ex;
	}
}

void
JoinableServiceHandler::unjoin(const Joinable& from, const Joinable& to) {
	i("unjoin %lld and %lld", from.object.id, to.object.id);
	try {
		if (from.session != to.session) {
			JoinException ex;
			ex.__set_description("Joinables are not in the same "
			"session");
			throw ex;
		}
		MediaSessionImpl &session = manager->getMediaSession(from.session);
		JoinableImpl &f = session.getJoinable(from);
		JoinableImpl &t = session.getJoinable(to);
		f.unjoin(t);
	} catch(JoinException ex){
		throw ex;
	} catch(JoinableNotFoundException ex) {
		throw ex;
	} catch (MediaSessionNotFoundException ex) {
		JoinableNotFoundException e;
		e.__set_description("MediaSession not found");
		throw e;
	} catch (MediaServerException ex) {
		throw ex;
	} catch (...) {
		MediaServerException ex;
		ex.__set_description("Unkown exception found");
		ex.__set_code(ErrorCode::type::UNEXPECTED);
		throw ex;
	}
}

void
JoinableServiceHandler::joinStream(const Joinable& from, const Joinable& to,
					const StreamType::type stream,
					const Direction direction) {
	if (_Direction_VALUES_TO_NAMES.find(direction) ==
					_Direction_VALUES_TO_NAMES.end()) {
		JoinException ex;
		ex.__set_description("Invalid direction");
		throw ex;
	}

	if (_StreamType_VALUES_TO_NAMES.find(stream) ==
					_StreamType_VALUES_TO_NAMES.end()) {
		JoinException ex;
		ex.__set_description("Invalid stream");
		throw ex;
	}

	i("joinStream %s of %lld with %lld with direction %s",
			_StreamType_VALUES_TO_NAMES.find(stream)->second,
			from.object.id, to.object.id,
			_Direction_VALUES_TO_NAMES.find(direction)->second);
	try {
		if (from.session != to.session) {
			JoinException ex;
			ex.__set_description("Joinables are not in the same "
			"session");
			throw ex;
		}
		MediaSessionImpl &session = manager->getMediaSession(from.session);
		JoinableImpl &f = session.getJoinable(from);
		JoinableImpl &t = session.getJoinable(to);
		f.join(t, stream, direction);
	} catch(StreamNotFoundException ex) {
		throw ex;
	} catch(JoinException ex){
		throw ex;
	} catch(JoinableNotFoundException ex) {
		throw ex;
	} catch (MediaSessionNotFoundException ex) {
		JoinableNotFoundException e;
		e.__set_description("MediaSession not found");
		throw e;
	} catch (MediaServerException ex) {
		throw ex;
	} catch (...) {
		MediaServerException ex;
		ex.__set_description("Unkown exception found");
		ex.__set_code(ErrorCode::type::UNEXPECTED);
		throw ex;
	}
}

void
JoinableServiceHandler::unjoinStream(const Joinable& from, const Joinable& to,
						const StreamType::type stream) {
	if (_StreamType_VALUES_TO_NAMES.find(stream) ==
					_StreamType_VALUES_TO_NAMES.end()) {
		JoinException ex;
		ex.__set_description("Invalid stream");
		throw ex;
	}

	i("unjoinStream %s of %lld with %lld",
			_StreamType_VALUES_TO_NAMES.find(stream)->second,
			from.object.id, to.object.id);
	try {
		if (from.session != to.session) {
			JoinException ex;
			ex.__set_description("Joinables are not in the same "
			"session");
			throw ex;
		}
		MediaSessionImpl &session = manager->getMediaSession(from.session);
		JoinableImpl &f = session.getJoinable(from);
		JoinableImpl &t = session.getJoinable(to);
		f.unjoin(t, stream);
	} catch(StreamNotFoundException ex) {
		throw ex;
	} catch(JoinException ex){
		throw ex;
	} catch(JoinableNotFoundException ex) {
		throw ex;
	} catch (MediaSessionNotFoundException ex) {
		JoinableNotFoundException e;
		e.__set_description("MediaSession not found");
		throw e;
	} catch (MediaServerException ex) {
		throw ex;
	} catch (...) {
		MediaServerException ex;
		ex.__set_description("Unkown exception found");
		ex.__set_code(ErrorCode::type::UNEXPECTED);
		throw ex;
	}
}

void
JoinableServiceHandler::getJoinees(std::vector<Joinable> &_return,
							const Joinable& from) {
	i("getJoinees of %lld", from.object.id);
	try {
		MediaSessionImpl &session = manager->getMediaSession(from.session);
		JoinableImpl &f = session.getJoinable(from);
		f.getJoinees(_return);
	} catch(JoinException ex){
		throw ex;
	} catch(JoinableNotFoundException ex) {
		throw ex;
	} catch (MediaSessionNotFoundException ex) {
		JoinableNotFoundException e;
		e.__set_description("MediaSession not found");
		throw e;
	} catch (MediaServerException ex) {
		throw ex;
	} catch (...) {
		MediaServerException ex;
		ex.__set_description("Unkown exception found");
		ex.__set_code(ErrorCode::type::UNEXPECTED);
		throw ex;
	}
}

void
JoinableServiceHandler::getDirectionJoinees(std::vector<Joinable> &_return,
					const Joinable& from,
					const Direction direction) {
	if (_Direction_VALUES_TO_NAMES.find(direction) ==
					_Direction_VALUES_TO_NAMES.end()) {
		JoinException ex;
		ex.__set_description("Invalid direction");
		throw ex;
	}

	i("getDirectionJoiness of %lld with direction %s", from.object.id,
			_Direction_VALUES_TO_NAMES.find(direction)->second);
	try {
		MediaSessionImpl &session = manager->getMediaSession(from.session);
		JoinableImpl &f = session.getJoinable(from);
		f.getJoinees(_return, direction);
	} catch(JoinException ex){
		throw ex;
	} catch(JoinableNotFoundException ex) {
		throw ex;
	} catch (MediaSessionNotFoundException ex) {
		JoinableNotFoundException e;
		e.__set_description("MediaSession not found");
		throw e;
	} catch (MediaServerException ex) {
		throw ex;
	} catch (...) {
		MediaServerException ex;
		ex.__set_description("Unkown exception found");
		ex.__set_code(ErrorCode::type::UNEXPECTED);
		throw ex;
	}
}

void
JoinableServiceHandler::getStreamJoinees(std::vector<Joinable> &_return,
						const Joinable& from,
						const StreamType::type stream) {
	if (_StreamType_VALUES_TO_NAMES.find(stream) ==
					_StreamType_VALUES_TO_NAMES.end()) {
		JoinException ex;
		ex.__set_description("Invalid stream");
		throw ex;
	}

	i("getStreamJoinees of stream %s from %lld",
			_StreamType_VALUES_TO_NAMES.find(stream)->second,
			from.object.id);
	try {
		MediaSessionImpl &session = manager->getMediaSession(from.session);
		JoinableImpl &f = session.getJoinable(from);
		f.getJoinees(_return, stream);
	} catch(StreamNotFoundException ex) {
		throw ex;
	} catch(JoinException ex){
		throw ex;
	} catch(JoinableNotFoundException ex) {
		throw ex;
	} catch (MediaSessionNotFoundException ex) {
		JoinableNotFoundException e;
		e.__set_description("MediaSession not found");
		throw e;
	} catch (MediaServerException ex) {
		throw ex;
	} catch (...) {
		MediaServerException ex;
		ex.__set_description("Unkown exception found");
		ex.__set_code(ErrorCode::type::UNEXPECTED);
		throw ex;
	}
}

void
JoinableServiceHandler::getStreamDirectionJoinees(std::vector<Joinable> &_return,
						const Joinable& from,
						const StreamType::type stream,
						const Direction direction) {
	if (_StreamType_VALUES_TO_NAMES.find(stream) ==
					_StreamType_VALUES_TO_NAMES.end()) {
		JoinException ex;
		ex.__set_description("Invalid stream");
		throw ex;
	}

	if (_Direction_VALUES_TO_NAMES.find(direction) ==
					_Direction_VALUES_TO_NAMES.end()) {
		JoinException ex;
		ex.__set_description("Invalid direction");
		throw ex;
	}

	i("getStreamDirectionJoinees of stream %s from %lld with direction %s",
			_StreamType_VALUES_TO_NAMES.find(stream)->second,
			from.object.id,
			_Direction_VALUES_TO_NAMES.find(direction)->second);
	try {
		MediaSessionImpl &session = manager->getMediaSession(from.session);
		JoinableImpl &f = session.getJoinable(from);
		f.getJoinees(_return, stream, direction);
	} catch(StreamNotFoundException ex) {
		throw ex;
	} catch(JoinException ex){
		throw ex;
	} catch(JoinableNotFoundException ex) {
		throw ex;
	} catch (MediaSessionNotFoundException ex) {
		JoinableNotFoundException e;
		e.__set_description("MediaSession not found");
		throw e;
	} catch (MediaServerException ex) {
		throw ex;
	} catch (...) {
		MediaServerException ex;
		ex.__set_description("Unkown exception found");
		ex.__set_code(ErrorCode::type::UNEXPECTED);
		throw ex;
	}
}

void
JoinableServiceHandler::release(const Joinable& joinable) {
	i("release joinable %lld", joinable.object.id);

	try {
		MediaSessionImpl &session = manager->getMediaSession(joinable.session);
		session.deleteJoinable(joinable);
	} catch(JoinableNotFoundException ex) {
		throw ex;
	} catch (MediaSessionNotFoundException ex) {
		JoinableNotFoundException e;
		e.__set_description("Joinable not found");
		w(e.description);
		throw e;
	} catch (MixerNotFoundException ex) {
		JoinableNotFoundException e;
		e.__set_description("Joinable not found");
		w(e.description);
		throw e;
	} catch (MediaServerException ex) {
		throw ex;
	} catch (...) {
		MediaServerException ex;
		ex.__set_description("Unkown exception found");
		ex.__set_code(ErrorCode::type::UNEXPECTED);
		throw ex;
	}
}
<|endoftext|>


<commit_before>#include <Poco/Exception.h>
#include <Poco/DateTime.h>
#include <Poco/DateTimeFormat.h>
#include <Poco/DateTimeFormatter.h>
#include <Poco/Logger.h>

#include <Poco/Net/HTTPServerParams.h>
#include <Poco/Net/HTTPServerRequest.h>
#include <Poco/Net/HTTPServerResponse.h>

#include "rest/PocoRestRequestHandler.h"
#include "rest/RestFlow.h"
#include "rest/RestRouter.h"
#include "rest/RestLinker.h"
#include "server/SessionVerifier.h"

using namespace std;
using namespace Poco;
using namespace Poco::Net;
using namespace BeeeOn;

PocoRestRequestHandler::PocoRestRequestHandler(
		RestAction::Ptr action,
		const MappedRestAction::Params &params,
		ExpirableSession::Ptr session,
		RestLinker &linker):
	m_action(action),
	m_params(params),
	m_session(session),
	m_linker(linker)
{
}

bool PocoRestRequestHandler::expectedContentLength(
		HTTPServerRequest &req,
		HTTPServerResponse &res)
{
	const string &method = req.getMethod();

	if (method != "POST" && method != "PUT" && method != "PATCH")
		return true;;

	if (!req.hasContentLength()) {
		res.setStatusAndReason(HTTPResponse::HTTP_LENGTH_REQUIRED);
		return false;
	}

	int inputMaxSize = m_action->inputMaxSize();
	if (inputMaxSize < 0)
		return true;

	auto contentLength = req.getContentLength();
	if (contentLength > inputMaxSize) {
		if (logger().warning()) {
			logger().warning(
				"too long input: "
				+ to_string(contentLength)
				+ " for "
				+ m_action->fullName(),
				__FILE__, __LINE__);
		}

		res.setStatusAndReason(HTTPResponse::HTTP_BAD_REQUEST);
		return false;
	}

	return true;
}

string PocoRestRequestHandler::asString(const MappedRestAction::Params &params) const
{
	string s("[");
	auto it = params.begin();

	for (; it != params.end(); ++it) {
		if (it != params.begin())
			s.append(", ");

		s.append(it->first);
		s.append(" => ");
		s.append(it->second);
	}

	s.append("]");
	return s;
}

void PocoRestRequestHandler::prepareInternalAction(
		RestAction::Ptr action,
		HTTPServerRequest &req,
		HTTPServerResponse &res) const
{
	req.set("Cache-Control", "public, no-cache");
}

void PocoRestRequestHandler::prepareMappedAction(
		MappedRestAction::Ptr action,
		HTTPServerRequest &req,
		HTTPServerResponse &res) const
{
	if (action->caching() == 0) {
		req.set("Cache-Control", "public, no-cache");
	}
	else {
		const Timespan shift(action->caching(), 0);
		const DateTime now;

		res.set("Expires",
			DateTimeFormatter::format(now + shift, DateTimeFormat::HTTP_FORMAT));
		res.set("Cache-Control",
			"max-age=" + to_string(shift.totalSeconds()) + ", must-revalidate");
	}
}

void PocoRestRequestHandler::handleRequest(
		HTTPServerRequest &req,
		HTTPServerResponse &res)
{
	if (logger().debug()) {
		logger().debug("serving request "
			+ req.getMethod()
			+ " "
			+ req.getURI()
			+ " via action "
			+ m_action->fullName()
			+ " "
			+ asString(m_params),
			__FILE__, __LINE__);
	}

	if (logger().trace()) {
		for (const auto &pair : req) {
			logger().trace(
				pair.first
				+ ": "
				+ pair.second,
				__FILE__, __LINE__);
		}
	}

	if (!expectedContentLength(req, res)) {
		res.send();
		return;
	}

	Poco::URI uri(req.getURI());

	RestFlow flow(
		m_linker,
		uri,
		m_params,
		PocoRequest(req),
		PocoResponse(res)
	);

	MappedRestAction::Ptr mapped = m_action.cast<MappedRestAction>();
	if (mapped.isNull())
		prepareInternalAction(m_action, req, res);
	else
		prepareMappedAction(mapped, req, res);

	const auto &call = m_action->call();

	try {
		flow.setSession(m_session);
		call(flow);
		return;
	}
	catch (const Exception &e) {
		logger().log(e, __FILE__, __LINE__);
	}
	catch (const exception &e) {
		logger().critical(e.what(), __FILE__, __LINE__);
	}
	catch (const char *m) {
		logger().fatal(m, __FILE__, __LINE__);
	}
	catch (...) {
		logger().fatal("unknown error occured", __FILE__, __LINE__);
	}

	if (res.sent())
		return;

	res.setStatusAndReason(HTTPResponse::HTTP_INTERNAL_SERVER_ERROR);
}

PocoRestRequestFactory::PocoRestRequestFactory(
		RestRouter &router,
		SessionVerifier &verifier):
	m_router(router),
	m_sessionVerifier(verifier)
{
}

HTTPRequestHandler *PocoRestRequestFactory::handleNoRoute(const HTTPServerRequest &request)
{
	if (logger().debug()) {
		logger().debug("no action resolved for "
			+ request.getMethod()
			+ " "
			+ request.getURI(),
			__FILE__, __LINE__);
	}

	RestAction::Ptr target = m_router.lookup("builtin", "noroute");
	if (target.isNull())
		throw Exception("missing handler builtin.noroute");

	return new PocoRestRequestHandler(
		target,
		{},
		NULL,
		static_cast<RestLinker &>(m_router)
	);
}

HTTPRequestHandler *PocoRestRequestFactory::handleNoSession()
{
	if (logger().debug()) {
		logger().debug("missing session, redirecting...",
			__FILE__, __LINE__);
	}

	RestAction::Ptr target = m_router.lookup("builtin", "unauthorized");
	if (target.isNull())
		throw Exception("missing handler builtin.unauthorized");

	return new PocoRestRequestHandler(
		target,
		{},
		NULL,
		static_cast<RestLinker &>(m_router)
	);
}

HTTPRequestHandler *PocoRestRequestFactory::createWithSession(
		RestAction::Ptr action,
		const MappedRestAction::Params &params,
		const HTTPServerRequest &request)
{
	ExpirableSession::Ptr session;

	if (action->sessionRequired()) {
		try {
			session = m_sessionVerifier.verifyAuthorized(request);
		} catch (const NotAuthenticatedException &e) {
			logger().log(e, __FILE__, __LINE__);
		}

		if (session.isNull())
			return handleNoSession();
	}

	return new PocoRestRequestHandler(
		action,
		params,
		session,
		static_cast<RestLinker &>(m_router)
	);
}

HTTPRequestHandler *PocoRestRequestFactory::createRequestHandler(
		const HTTPServerRequest &request)
{
	if (logger().debug()) {
		logger().debug("handling request "
			+ request.getMethod()
			+ " "
			+ request.getURI(),
			__FILE__, __LINE__);
	}

	Poco::URI uri(request.getURI());
	MappedRestAction::Params params;

	try {
		RestAction::Ptr action = m_router.route(
			request.getMethod(), uri, params
		);

		if (action.isNull())
			return handleNoRoute(request);

		return createWithSession(
			action,
			params,
			request
		);
	} catch (const Exception &e) {
		logger().log(e, __FILE__, __LINE__);
		e.rethrow();
	} catch (const exception &e) {
		logger().fatal(e.what(), __FILE__, __LINE__);
		throw e;
	} catch (...) {
		logger().fatal("something is terribly wrong",
				__FILE__, __LINE__);
		throw;
	}

	logger().fatal("should ben ever reached", __FILE__, __LINE__);
	return NULL;
}

<commit_msg>PocoRestRequestHandler: apply sanitization to request URIs<commit_after>#include <Poco/Exception.h>
#include <Poco/DateTime.h>
#include <Poco/DateTimeFormat.h>
#include <Poco/DateTimeFormatter.h>
#include <Poco/Logger.h>

#include <Poco/Net/HTTPServerParams.h>
#include <Poco/Net/HTTPServerRequest.h>
#include <Poco/Net/HTTPServerResponse.h>

#include "rest/PocoRestRequestHandler.h"
#include "rest/RestFlow.h"
#include "rest/RestRouter.h"
#include "rest/RestLinker.h"
#include "server/SessionVerifier.h"
#include "util/Sanitize.h"

using namespace std;
using namespace Poco;
using namespace Poco::Net;
using namespace BeeeOn;

PocoRestRequestHandler::PocoRestRequestHandler(
		RestAction::Ptr action,
		const MappedRestAction::Params &params,
		ExpirableSession::Ptr session,
		RestLinker &linker):
	m_action(action),
	m_params(params),
	m_session(session),
	m_linker(linker)
{
}

bool PocoRestRequestHandler::expectedContentLength(
		HTTPServerRequest &req,
		HTTPServerResponse &res)
{
	const string &method = req.getMethod();

	if (method != "POST" && method != "PUT" && method != "PATCH")
		return true;;

	if (!req.hasContentLength()) {
		res.setStatusAndReason(HTTPResponse::HTTP_LENGTH_REQUIRED);
		return false;
	}

	int inputMaxSize = m_action->inputMaxSize();
	if (inputMaxSize < 0)
		return true;

	auto contentLength = req.getContentLength();
	if (contentLength > inputMaxSize) {
		if (logger().warning()) {
			logger().warning(
				"too long input: "
				+ to_string(contentLength)
				+ " for "
				+ m_action->fullName(),
				__FILE__, __LINE__);
		}

		res.setStatusAndReason(HTTPResponse::HTTP_BAD_REQUEST);
		return false;
	}

	return true;
}

string PocoRestRequestHandler::asString(const MappedRestAction::Params &params) const
{
	string s("[");
	auto it = params.begin();

	for (; it != params.end(); ++it) {
		if (it != params.begin())
			s.append(", ");

		s.append(it->first);
		s.append(" => ");
		s.append(it->second);
	}

	s.append("]");
	return s;
}

void PocoRestRequestHandler::prepareInternalAction(
		RestAction::Ptr action,
		HTTPServerRequest &req,
		HTTPServerResponse &res) const
{
	req.set("Cache-Control", "public, no-cache");
}

void PocoRestRequestHandler::prepareMappedAction(
		MappedRestAction::Ptr action,
		HTTPServerRequest &req,
		HTTPServerResponse &res) const
{
	if (action->caching() == 0) {
		req.set("Cache-Control", "public, no-cache");
	}
	else {
		const Timespan shift(action->caching(), 0);
		const DateTime now;

		res.set("Expires",
			DateTimeFormatter::format(now + shift, DateTimeFormat::HTTP_FORMAT));
		res.set("Cache-Control",
			"max-age=" + to_string(shift.totalSeconds()) + ", must-revalidate");
	}
}

void PocoRestRequestHandler::handleRequest(
		HTTPServerRequest &req,
		HTTPServerResponse &res)
{
	if (logger().debug()) {
		logger().debug("serving request "
			+ req.getMethod()
			+ " "
			+ req.getURI()
			+ " via action "
			+ m_action->fullName()
			+ " "
			+ asString(m_params),
			__FILE__, __LINE__);
	}

	if (logger().trace()) {
		for (const auto &pair : req) {
			logger().trace(
				pair.first
				+ ": "
				+ pair.second,
				__FILE__, __LINE__);
		}
	}

	if (!expectedContentLength(req, res)) {
		res.send();
		return;
	}

	Poco::URI uri(req.getURI());

	RestFlow flow(
		m_linker,
		uri,
		m_params,
		PocoRequest(req),
		PocoResponse(res)
	);

	MappedRestAction::Ptr mapped = m_action.cast<MappedRestAction>();
	if (mapped.isNull())
		prepareInternalAction(m_action, req, res);
	else
		prepareMappedAction(mapped, req, res);

	const auto &call = m_action->call();

	try {
		flow.setSession(m_session);
		call(flow);
		return;
	}
	catch (const Exception &e) {
		logger().log(e, __FILE__, __LINE__);
	}
	catch (const exception &e) {
		logger().critical(e.what(), __FILE__, __LINE__);
	}
	catch (const char *m) {
		logger().fatal(m, __FILE__, __LINE__);
	}
	catch (...) {
		logger().fatal("unknown error occured", __FILE__, __LINE__);
	}

	if (res.sent())
		return;

	res.setStatusAndReason(HTTPResponse::HTTP_INTERNAL_SERVER_ERROR);
}

PocoRestRequestFactory::PocoRestRequestFactory(
		RestRouter &router,
		SessionVerifier &verifier):
	m_router(router),
	m_sessionVerifier(verifier)
{
}

HTTPRequestHandler *PocoRestRequestFactory::handleNoRoute(const HTTPServerRequest &request)
{
	if (logger().debug()) {
		logger().debug("no action resolved for "
			+ request.getMethod()
			+ " "
			+ request.getURI(),
			__FILE__, __LINE__);
	}

	RestAction::Ptr target = m_router.lookup("builtin", "noroute");
	if (target.isNull())
		throw Exception("missing handler builtin.noroute");

	return new PocoRestRequestHandler(
		target,
		{},
		NULL,
		static_cast<RestLinker &>(m_router)
	);
}

HTTPRequestHandler *PocoRestRequestFactory::handleNoSession()
{
	if (logger().debug()) {
		logger().debug("missing session, redirecting...",
			__FILE__, __LINE__);
	}

	RestAction::Ptr target = m_router.lookup("builtin", "unauthorized");
	if (target.isNull())
		throw Exception("missing handler builtin.unauthorized");

	return new PocoRestRequestHandler(
		target,
		{},
		NULL,
		static_cast<RestLinker &>(m_router)
	);
}

HTTPRequestHandler *PocoRestRequestFactory::createWithSession(
		RestAction::Ptr action,
		const MappedRestAction::Params &params,
		const HTTPServerRequest &request)
{
	ExpirableSession::Ptr session;

	if (action->sessionRequired()) {
		try {
			session = m_sessionVerifier.verifyAuthorized(request);
		} catch (const NotAuthenticatedException &e) {
			logger().log(e, __FILE__, __LINE__);
		}

		if (session.isNull())
			return handleNoSession();
	}

	return new PocoRestRequestHandler(
		action,
		params,
		session,
		static_cast<RestLinker &>(m_router)
	);
}

HTTPRequestHandler *PocoRestRequestFactory::createRequestHandler(
		const HTTPServerRequest &request)
{
	if (logger().debug()) {
		logger().debug("handling request "
			+ request.getMethod()
			+ " "
			+ request.getURI(),
			__FILE__, __LINE__);
	}

	Poco::URI uri(Sanitize::uri(request.getURI()));
	MappedRestAction::Params params;

	try {
		RestAction::Ptr action = m_router.route(
			request.getMethod(), uri, params
		);

		if (action.isNull())
			return handleNoRoute(request);

		return createWithSession(
			action,
			params,
			request
		);
	} catch (const Exception &e) {
		logger().log(e, __FILE__, __LINE__);
		e.rethrow();
	} catch (const exception &e) {
		logger().fatal(e.what(), __FILE__, __LINE__);
		throw e;
	} catch (...) {
		logger().fatal("something is terribly wrong",
				__FILE__, __LINE__);
		throw;
	}

	logger().fatal("should ben ever reached", __FILE__, __LINE__);
	return NULL;
}

<|endoftext|>


<commit_before>/*
    This file is part of Android File Transfer For Linux.
    Copyright (C) 2015-2018  Vladimir Menshakov

    Android File Transfer For Linux is free software: you can redistribute
    it and/or modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    Android File Transfer For Linux is distributed in the hope that it will
    be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
    of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Android File Transfer For Linux.
    If not, see <http://www.gnu.org/licenses/>.
 */

#include "mainwindow.h"
#include "utils.h"
#include <QApplication>
#include <QLibraryInfo>
#include <QLocale>
#include <QMessageBox>
#include <QTranslator>

namespace
{
	class Application : public QApplication
	{
	public:
		Application(int &argc, char **argv, int flags = ApplicationFlags):
			QApplication(argc, argv, flags)
		{ }

		virtual bool notify ( QObject * receiver, QEvent * e )
		{
			try {
				return QApplication::notify( receiver, e );
			} catch ( const std::exception& e ) {
				QMessageBox::warning(0, "Error", fromUtf8(e.what()));
				return false;
			}
		}
	};
}

int main(int argc, char *argv[])
{
	QApplication app(argc, argv);
	Q_INIT_RESOURCE(android_file_transfer);

	QCoreApplication::setApplicationName("mtp-ng-qt");
	QCoreApplication::setOrganizationDomain("whoozle.github.io");
	QCoreApplication::setOrganizationName("whoozle.github.io");

	QTranslator qtTranslator;

	qtTranslator.load("qt_" + QLocale::system().name(),
					QLibraryInfo::location(QLibraryInfo::TranslationsPath));
	app.installTranslator(&qtTranslator);

	QTranslator aTranslator;
	aTranslator.load(":/translations/android-file-transfer-linux_" + QLocale::system().name());
	app.installTranslator(&aTranslator);

	MainWindow w;
	w.show();

	if (!w.started())
		return 1;

	return app.exec();
}
<commit_msg>renamed config file<commit_after>/*
    This file is part of Android File Transfer For Linux.
    Copyright (C) 2015-2018  Vladimir Menshakov

    Android File Transfer For Linux is free software: you can redistribute
    it and/or modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    Android File Transfer For Linux is distributed in the hope that it will
    be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
    of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Android File Transfer For Linux.
    If not, see <http://www.gnu.org/licenses/>.
 */

#include "mainwindow.h"
#include "utils.h"
#include <QApplication>
#include <QLibraryInfo>
#include <QLocale>
#include <QMessageBox>
#include <QTranslator>

namespace
{
	class Application : public QApplication
	{
	public:
		Application(int &argc, char **argv, int flags = ApplicationFlags):
			QApplication(argc, argv, flags)
		{ }

		virtual bool notify ( QObject * receiver, QEvent * e )
		{
			try {
				return QApplication::notify( receiver, e );
			} catch ( const std::exception& e ) {
				QMessageBox::warning(0, "Error", fromUtf8(e.what()));
				return false;
			}
		}
	};
}

int main(int argc, char *argv[])
{
	QApplication app(argc, argv);
	Q_INIT_RESOURCE(android_file_transfer);

	QCoreApplication::setApplicationName("aft-linux-qt");
	QCoreApplication::setOrganizationDomain("whoozle.github.io");
	QCoreApplication::setOrganizationName("whoozle.github.io");

	QTranslator qtTranslator;

	qtTranslator.load("qt_" + QLocale::system().name(),
					QLibraryInfo::location(QLibraryInfo::TranslationsPath));
	app.installTranslator(&qtTranslator);

	QTranslator aTranslator;
	aTranslator.load(":/translations/android-file-transfer-linux_" + QLocale::system().name());
	app.installTranslator(&aTranslator);

	MainWindow w;
	w.show();

	if (!w.started())
		return 1;

	return app.exec();
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 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 "base/bind.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop_proxy.h"
#include "remoting/jingle_glue/mock_objects.h"
#include "remoting/host/capturer_fake.h"
#include "remoting/host/chromoting_host.h"
#include "remoting/host/chromoting_host_context.h"
#include "remoting/host/host_mock_objects.h"
#include "remoting/host/it2me_host_user_interface.h"
#include "remoting/proto/video.pb.h"
#include "remoting/protocol/protocol_mock_objects.h"
#include "remoting/protocol/session_config.h"
#include "testing/gmock_mutant.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

using ::remoting::protocol::MockClientStub;
using ::remoting::protocol::MockConnectionToClient;
using ::remoting::protocol::MockConnectionToClientEventHandler;
using ::remoting::protocol::MockHostStub;
using ::remoting::protocol::MockSession;
using ::remoting::protocol::MockVideoStub;
using ::remoting::protocol::SessionConfig;

using testing::_;
using testing::AnyNumber;
using testing::AtLeast;
using testing::CreateFunctor;
using testing::DeleteArg;
using testing::DoAll;
using testing::InSequence;
using testing::InvokeArgument;
using testing::InvokeWithoutArgs;
using testing::Return;
using testing::ReturnRef;
using testing::Sequence;

namespace remoting {

namespace {

void PostQuitTask(MessageLoop* message_loop) {
  message_loop->PostTask(FROM_HERE, MessageLoop::QuitClosure());
}

// Run the task and delete it afterwards. This action is used to deal with
// done callbacks.
ACTION(RunDoneTask) {
  arg1.Run();
}

}  // namespace

class ChromotingHostTest : public testing::Test {
 public:
  ChromotingHostTest() {
  }

  virtual void SetUp() OVERRIDE {
    message_loop_proxy_ = base::MessageLoopProxy::current();
    ON_CALL(context_, main_message_loop())
        .WillByDefault(Return(&message_loop_));
    ON_CALL(context_, encode_message_loop())
        .WillByDefault(Return(&message_loop_));
    ON_CALL(context_, network_message_loop())
        .WillByDefault(Return(message_loop_proxy_.get()));
    ON_CALL(context_, ui_message_loop())
        .WillByDefault(Return(message_loop_proxy_.get()));
    EXPECT_CALL(context_, main_message_loop())
        .Times(AnyNumber());
    EXPECT_CALL(context_, encode_message_loop())
        .Times(AnyNumber());
    EXPECT_CALL(context_, network_message_loop())
        .Times(AnyNumber());
    EXPECT_CALL(context_, ui_message_loop())
        .Times(AnyNumber());

    scoped_ptr<Capturer> capturer(new CapturerFake());
    event_executor_ = new MockEventExecutor();
    desktop_environment_ = DesktopEnvironment::CreateFake(
        &context_,
        capturer.Pass(),
        scoped_ptr<EventExecutor>(event_executor_));
    session_manager_ = new protocol::MockSessionManager();

    host_ = new ChromotingHost(
        &context_, &signal_strategy_, desktop_environment_.get(),
        scoped_ptr<protocol::SessionManager>(session_manager_));

    disconnect_window_ = new MockDisconnectWindow();
    continue_window_ = new MockContinueWindow();
    local_input_monitor_ = new MockLocalInputMonitor();
    it2me_host_user_interface_.reset(new It2MeHostUserInterface(&context_));
    it2me_host_user_interface_->StartForTest(
        host_,
        base::Bind(&ChromotingHost::Shutdown, host_, base::Closure()),
        scoped_ptr<DisconnectWindow>(disconnect_window_),
        scoped_ptr<ContinueWindow>(continue_window_),
        scoped_ptr<LocalInputMonitor>(local_input_monitor_));

    session_ = new MockSession();
    session2_ = new MockSession();
    session_config_ = SessionConfig::GetDefault();
    session_jid_ = "user@domain/rest-of-jid";
    session_config2_ = SessionConfig::GetDefault();
    session2_jid_ = "user2@domain/rest-of-jid";
    EXPECT_CALL(*session_, jid())
        .WillRepeatedly(ReturnRef(session_jid_));
    EXPECT_CALL(*session2_, jid())
        .WillRepeatedly(ReturnRef(session2_jid_));
    EXPECT_CALL(*session_, SetStateChangeCallback(_))
        .Times(AnyNumber());
    EXPECT_CALL(*session2_, SetStateChangeCallback(_))
        .Times(AnyNumber());
    EXPECT_CALL(*session_, SetRouteChangeCallback(_))
        .Times(AnyNumber());
    EXPECT_CALL(*session2_, SetRouteChangeCallback(_))
        .Times(AnyNumber());
    EXPECT_CALL(*session_, config())
        .WillRepeatedly(ReturnRef(session_config_));
    EXPECT_CALL(*session2_, config())
        .WillRepeatedly(ReturnRef(session_config2_));
    EXPECT_CALL(*session_, Close())
        .Times(AnyNumber());
    EXPECT_CALL(*session2_, Close())
        .Times(AnyNumber());

    owned_connection_.reset(new MockConnectionToClient(
        session_, &host_stub_, desktop_environment_->event_executor()));
    connection_ = owned_connection_.get();
    owned_connection2_.reset(new MockConnectionToClient(
        session2_, &host_stub2_, desktop_environment_->event_executor()));
    connection2_ = owned_connection2_.get();

    ON_CALL(video_stub_, ProcessVideoPacketPtr(_, _))
        .WillByDefault(DeleteArg<0>());
    ON_CALL(video_stub2_, ProcessVideoPacketPtr(_, _))
        .WillByDefault(DeleteArg<0>());
    ON_CALL(*connection_, video_stub())
        .WillByDefault(Return(&video_stub_));
    ON_CALL(*connection_, client_stub())
        .WillByDefault(Return(&client_stub_));
    ON_CALL(*connection_, session())
        .WillByDefault(Return(session_));
    ON_CALL(*connection2_, video_stub())
        .WillByDefault(Return(&video_stub2_));
    ON_CALL(*connection2_, client_stub())
        .WillByDefault(Return(&client_stub2_));
    ON_CALL(*connection2_, session())
        .WillByDefault(Return(session2_));
    EXPECT_CALL(*connection_, video_stub())
        .Times(AnyNumber());
    EXPECT_CALL(*connection_, client_stub())
        .Times(AnyNumber());
    EXPECT_CALL(*connection_, session())
        .Times(AnyNumber());
    EXPECT_CALL(*connection2_, video_stub())
        .Times(AnyNumber());
    EXPECT_CALL(*connection2_, client_stub())
        .Times(AnyNumber());
    EXPECT_CALL(*connection2_, session())
        .Times(AnyNumber());
  }

  // Helper method to pretend a client is connected to ChromotingHost.
  void SimulateClientConnection(int connection_index, bool authenticate) {
    scoped_ptr<protocol::ConnectionToClient> connection =
        ((connection_index == 0) ? owned_connection_ : owned_connection2_).
        PassAs<protocol::ConnectionToClient>();
    protocol::ConnectionToClient* connection_ptr = connection.get();
    ClientSession* client = new ClientSession(
        host_.get(), connection.Pass(), desktop_environment_->event_executor(),
        desktop_environment_->capturer());
    connection_ptr->set_host_stub(client);

    context_.network_message_loop()->PostTask(
        FROM_HERE, base::Bind(&ChromotingHostTest::AddClientToHost,
                              host_, client));
    if (authenticate) {
      context_.network_message_loop()->PostTask(
          FROM_HERE, base::Bind(&ClientSession::OnConnectionAuthenticated,
                                base::Unretained(client), connection_ptr));
      context_.network_message_loop()->PostTask(
          FROM_HERE,
          base::Bind(&ClientSession::OnConnectionChannelsConnected,
                     base::Unretained(client), connection_ptr));
    }

    if (connection_index == 0) {
      client_ = client;
    } else {
      client2_ = client;
    }
  }

  // Helper method to remove a client connection from ChromotingHost.
  void RemoveClientSession() {
    client_->OnConnectionClosed(connection_, protocol::OK);
  }

  // Notify |host_| that |client_| has closed.
  void ClientSessionClosed() {
    host_->OnSessionClosed(client_);
  }

  // Notify |host_| that |client2_| has closed.
  void ClientSession2Closed() {
    host_->OnSessionClosed(client2_);
  }

  static void AddClientToHost(scoped_refptr<ChromotingHost> host,
                              ClientSession* session) {
    host->clients_.push_back(session);
  }

  void ShutdownHost() {
    message_loop_.PostTask(
        FROM_HERE, base::Bind(&ChromotingHost::Shutdown, host_,
                              base::Bind(&PostQuitTask, &message_loop_)));
  }

  void QuitMainMessageLoop() {
    PostQuitTask(&message_loop_);
  }

 protected:
  MessageLoop message_loop_;
  scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
  MockConnectionToClientEventHandler handler_;
  MockSignalStrategy signal_strategy_;
  MockEventExecutor* event_executor_;
  scoped_ptr<DesktopEnvironment> desktop_environment_;
  scoped_ptr<It2MeHostUserInterface> it2me_host_user_interface_;
  scoped_refptr<ChromotingHost> host_;
  MockChromotingHostContext context_;
  protocol::MockSessionManager* session_manager_;
  MockConnectionToClient* connection_;
  scoped_ptr<MockConnectionToClient> owned_connection_;
  ClientSession* client_;
  std::string session_jid_;
  MockSession* session_;  // Owned by |connection_|.
  SessionConfig session_config_;
  MockVideoStub video_stub_;
  MockClientStub client_stub_;
  MockHostStub host_stub_;
  MockConnectionToClient* connection2_;
  scoped_ptr<MockConnectionToClient> owned_connection2_;
  ClientSession* client2_;
  std::string session2_jid_;
  MockSession* session2_;  // Owned by |connection2_|.
  SessionConfig session_config2_;
  MockVideoStub video_stub2_;
  MockClientStub client_stub2_;
  MockHostStub host_stub2_;

  // Owned by |host_|.
  MockDisconnectWindow* disconnect_window_;
  MockContinueWindow* continue_window_;
  MockLocalInputMonitor* local_input_monitor_;
};

TEST_F(ChromotingHostTest, StartAndShutdown) {
  EXPECT_CALL(*session_manager_, Init(_, host_.get()));
  EXPECT_CALL(*disconnect_window_, Hide());
  EXPECT_CALL(*continue_window_, Hide());

  host_->Start();

  message_loop_.PostTask(
      FROM_HERE, base::Bind(
          &ChromotingHost::Shutdown, host_.get(),
          base::Bind(&PostQuitTask, &message_loop_)));
  message_loop_.Run();
}

TEST_F(ChromotingHostTest, Connect) {
  EXPECT_CALL(*session_manager_, Init(_, host_.get()));
  EXPECT_CALL(*disconnect_window_, Hide());
  EXPECT_CALL(*continue_window_, Hide());

  host_->Start();

  // When the video packet is received we first shut down ChromotingHost,
  // then execute the done task.
  {
    InSequence s;
    EXPECT_CALL(*disconnect_window_, Show(_, _, _))
        .Times(0);
    EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _))
        .WillOnce(DoAll(
            InvokeWithoutArgs(this, &ChromotingHostTest::ShutdownHost),
            RunDoneTask()))
        .RetiresOnSaturation();
    EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _))
        .Times(AnyNumber())
        .WillRepeatedly(RunDoneTask());
    EXPECT_CALL(*connection_, Disconnect())
        .WillOnce(
            InvokeWithoutArgs(this, &ChromotingHostTest::ClientSessionClosed))
        .RetiresOnSaturation();
  }

  {
    InSequence s;
    EXPECT_CALL(*event_executor_, OnSessionStartedPtr(_));
    EXPECT_CALL(*event_executor_, OnSessionFinished());
  }

  SimulateClientConnection(0, true);
  message_loop_.Run();
}

TEST_F(ChromotingHostTest, Reconnect) {
  EXPECT_CALL(*session_manager_, Init(_, host_.get()));
  EXPECT_CALL(*disconnect_window_, Hide());
  EXPECT_CALL(*continue_window_, Hide());

  host_->Start();

  // When the video packet is received we first disconnect the mock
  // connection, then run the done task, then quit the message loop.
  {
    InSequence s;
    EXPECT_CALL(*disconnect_window_, Show(_, _, _))
        .Times(0);
    EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _))
        .WillOnce(DoAll(
            InvokeWithoutArgs(this, &ChromotingHostTest::RemoveClientSession),
            RunDoneTask(),
            InvokeWithoutArgs(this, &ChromotingHostTest::QuitMainMessageLoop)))
        .RetiresOnSaturation();
    EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _))
        .Times(AnyNumber())
        .WillRepeatedly(RunDoneTask());
  }

  {
    InSequence s;
    EXPECT_CALL(*event_executor_, OnSessionStartedPtr(_));
    EXPECT_CALL(*event_executor_, OnSessionFinished());
  }

  SimulateClientConnection(0, true);
  message_loop_.Run();

  // Connect the second client.
  {
    InSequence s;
    EXPECT_CALL(*disconnect_window_, Show(_, _, _))
        .Times(0);
    EXPECT_CALL(video_stub2_, ProcessVideoPacketPtr(_, _))
        .WillOnce(DoAll(
            InvokeWithoutArgs(this, &ChromotingHostTest::ShutdownHost),
            RunDoneTask()))
        .RetiresOnSaturation();
    EXPECT_CALL(video_stub2_, ProcessVideoPacketPtr(_, _))
        .Times(AnyNumber())
        .WillRepeatedly(RunDoneTask());
    EXPECT_CALL(*connection2_, Disconnect())
        .WillOnce(
            InvokeWithoutArgs(this, &ChromotingHostTest::ClientSession2Closed))
        .RetiresOnSaturation();
  }

  {
    InSequence s;
    EXPECT_CALL(*event_executor_, OnSessionStartedPtr(_));
    EXPECT_CALL(*event_executor_, OnSessionFinished());
  }

  SimulateClientConnection(1, true);
  message_loop_.Run();
}

TEST_F(ChromotingHostTest, ConnectWhenAnotherClientIsConnected) {
  EXPECT_CALL(*session_manager_, Init(_, host_.get()));
  EXPECT_CALL(*disconnect_window_, Hide());
  EXPECT_CALL(*continue_window_, Hide());

  host_->Start();

  // When a video packet is received we connect the second mock
  // connection.
  {
    InSequence s;
    EXPECT_CALL(*disconnect_window_, Show(_, _, _))
        .Times(0);
    EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _))
        .WillOnce(DoAll(
            InvokeWithoutArgs(
                CreateFunctor(
                    this,
                    &ChromotingHostTest::SimulateClientConnection, 1, true)),
            RunDoneTask()))
        .RetiresOnSaturation();
    EXPECT_CALL(*disconnect_window_, Show(_, _, _))
        .Times(0);
    EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _))
        .Times(AnyNumber())
        .WillRepeatedly(RunDoneTask());
    EXPECT_CALL(video_stub2_, ProcessVideoPacketPtr(_, _))
        .WillOnce(DoAll(
            InvokeWithoutArgs(this, &ChromotingHostTest::ShutdownHost),
            RunDoneTask()))
        .RetiresOnSaturation();
    EXPECT_CALL(video_stub2_, ProcessVideoPacketPtr(_, _))
        .Times(AnyNumber())
        .WillRepeatedly(RunDoneTask());
  }

  {
    InSequence s;
    EXPECT_CALL(*event_executor_, OnSessionStartedPtr(_));
    EXPECT_CALL(*event_executor_, OnSessionFinished());
    EXPECT_CALL(*event_executor_, OnSessionStartedPtr(_));
    EXPECT_CALL(*event_executor_, OnSessionFinished());
  }

  EXPECT_CALL(*connection_, Disconnect())
      .WillOnce(
          InvokeWithoutArgs(this, &ChromotingHostTest::ClientSessionClosed))
      .RetiresOnSaturation();
  EXPECT_CALL(*connection2_, Disconnect())
      .WillOnce(
          InvokeWithoutArgs(this, &ChromotingHostTest::ClientSession2Closed))
      .RetiresOnSaturation();

  SimulateClientConnection(0, true);
  message_loop_.Run();
}

}  // namespace remoting
<commit_msg>[Chromoting] Make the sequence expectations in the ChromotingHost unit tests more accurate.<commit_after>// Copyright (c) 2012 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 "base/bind.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop_proxy.h"
#include "remoting/jingle_glue/mock_objects.h"
#include "remoting/host/capturer_fake.h"
#include "remoting/host/chromoting_host.h"
#include "remoting/host/chromoting_host_context.h"
#include "remoting/host/host_mock_objects.h"
#include "remoting/host/it2me_host_user_interface.h"
#include "remoting/proto/video.pb.h"
#include "remoting/protocol/protocol_mock_objects.h"
#include "remoting/protocol/session_config.h"
#include "testing/gmock_mutant.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

using ::remoting::protocol::MockClientStub;
using ::remoting::protocol::MockConnectionToClient;
using ::remoting::protocol::MockConnectionToClientEventHandler;
using ::remoting::protocol::MockHostStub;
using ::remoting::protocol::MockSession;
using ::remoting::protocol::MockVideoStub;
using ::remoting::protocol::SessionConfig;

using testing::_;
using testing::AnyNumber;
using testing::AtLeast;
using testing::CreateFunctor;
using testing::DeleteArg;
using testing::DoAll;
using testing::Expectation;
using testing::InSequence;
using testing::InvokeArgument;
using testing::InvokeWithoutArgs;
using testing::Return;
using testing::ReturnRef;
using testing::Sequence;

namespace remoting {

namespace {

void PostQuitTask(MessageLoop* message_loop) {
  message_loop->PostTask(FROM_HERE, MessageLoop::QuitClosure());
}

// Run the task and delete it afterwards. This action is used to deal with
// done callbacks.
ACTION(RunDoneTask) {
  arg1.Run();
}

}  // namespace

class ChromotingHostTest : public testing::Test {
 public:
  ChromotingHostTest() {
  }

  virtual void SetUp() OVERRIDE {
    message_loop_proxy_ = base::MessageLoopProxy::current();
    ON_CALL(context_, main_message_loop())
        .WillByDefault(Return(&message_loop_));
    ON_CALL(context_, encode_message_loop())
        .WillByDefault(Return(&message_loop_));
    ON_CALL(context_, network_message_loop())
        .WillByDefault(Return(message_loop_proxy_.get()));
    ON_CALL(context_, ui_message_loop())
        .WillByDefault(Return(message_loop_proxy_.get()));
    EXPECT_CALL(context_, main_message_loop())
        .Times(AnyNumber());
    EXPECT_CALL(context_, encode_message_loop())
        .Times(AnyNumber());
    EXPECT_CALL(context_, network_message_loop())
        .Times(AnyNumber());
    EXPECT_CALL(context_, ui_message_loop())
        .Times(AnyNumber());

    scoped_ptr<Capturer> capturer(new CapturerFake());
    event_executor_ = new MockEventExecutor();
    desktop_environment_ = DesktopEnvironment::CreateFake(
        &context_,
        capturer.Pass(),
        scoped_ptr<EventExecutor>(event_executor_));
    session_manager_ = new protocol::MockSessionManager();

    host_ = new ChromotingHost(
        &context_, &signal_strategy_, desktop_environment_.get(),
        scoped_ptr<protocol::SessionManager>(session_manager_));

    disconnect_window_ = new MockDisconnectWindow();
    continue_window_ = new MockContinueWindow();
    local_input_monitor_ = new MockLocalInputMonitor();
    it2me_host_user_interface_.reset(new It2MeHostUserInterface(&context_));
    it2me_host_user_interface_->StartForTest(
        host_,
        base::Bind(&ChromotingHost::Shutdown, host_, base::Closure()),
        scoped_ptr<DisconnectWindow>(disconnect_window_),
        scoped_ptr<ContinueWindow>(continue_window_),
        scoped_ptr<LocalInputMonitor>(local_input_monitor_));

    session_ = new MockSession();
    session2_ = new MockSession();
    session_config_ = SessionConfig::GetDefault();
    session_jid_ = "user@domain/rest-of-jid";
    session_config2_ = SessionConfig::GetDefault();
    session2_jid_ = "user2@domain/rest-of-jid";
    EXPECT_CALL(*session_, jid())
        .WillRepeatedly(ReturnRef(session_jid_));
    EXPECT_CALL(*session2_, jid())
        .WillRepeatedly(ReturnRef(session2_jid_));
    EXPECT_CALL(*session_, SetStateChangeCallback(_))
        .Times(AnyNumber());
    EXPECT_CALL(*session2_, SetStateChangeCallback(_))
        .Times(AnyNumber());
    EXPECT_CALL(*session_, SetRouteChangeCallback(_))
        .Times(AnyNumber());
    EXPECT_CALL(*session2_, SetRouteChangeCallback(_))
        .Times(AnyNumber());
    EXPECT_CALL(*session_, config())
        .WillRepeatedly(ReturnRef(session_config_));
    EXPECT_CALL(*session2_, config())
        .WillRepeatedly(ReturnRef(session_config2_));
    EXPECT_CALL(*session_, Close())
        .Times(AnyNumber());
    EXPECT_CALL(*session2_, Close())
        .Times(AnyNumber());

    owned_connection_.reset(new MockConnectionToClient(
        session_, &host_stub_, desktop_environment_->event_executor()));
    connection_ = owned_connection_.get();
    owned_connection2_.reset(new MockConnectionToClient(
        session2_, &host_stub2_, desktop_environment_->event_executor()));
    connection2_ = owned_connection2_.get();

    ON_CALL(video_stub_, ProcessVideoPacketPtr(_, _))
        .WillByDefault(DeleteArg<0>());
    ON_CALL(video_stub2_, ProcessVideoPacketPtr(_, _))
        .WillByDefault(DeleteArg<0>());
    ON_CALL(*connection_, video_stub())
        .WillByDefault(Return(&video_stub_));
    ON_CALL(*connection_, client_stub())
        .WillByDefault(Return(&client_stub_));
    ON_CALL(*connection_, session())
        .WillByDefault(Return(session_));
    ON_CALL(*connection2_, video_stub())
        .WillByDefault(Return(&video_stub2_));
    ON_CALL(*connection2_, client_stub())
        .WillByDefault(Return(&client_stub2_));
    ON_CALL(*connection2_, session())
        .WillByDefault(Return(session2_));
    EXPECT_CALL(*connection_, video_stub())
        .Times(AnyNumber());
    EXPECT_CALL(*connection_, client_stub())
        .Times(AnyNumber());
    EXPECT_CALL(*connection_, session())
        .Times(AnyNumber());
    EXPECT_CALL(*connection2_, video_stub())
        .Times(AnyNumber());
    EXPECT_CALL(*connection2_, client_stub())
        .Times(AnyNumber());
    EXPECT_CALL(*connection2_, session())
        .Times(AnyNumber());
  }

  // Helper method to pretend a client is connected to ChromotingHost.
  void SimulateClientConnection(int connection_index, bool authenticate) {
    scoped_ptr<protocol::ConnectionToClient> connection =
        ((connection_index == 0) ? owned_connection_ : owned_connection2_).
        PassAs<protocol::ConnectionToClient>();
    protocol::ConnectionToClient* connection_ptr = connection.get();
    ClientSession* client = new ClientSession(
        host_.get(), connection.Pass(), desktop_environment_->event_executor(),
        desktop_environment_->capturer());
    connection_ptr->set_host_stub(client);

    context_.network_message_loop()->PostTask(
        FROM_HERE, base::Bind(&ChromotingHostTest::AddClientToHost,
                              host_, client));
    if (authenticate) {
      context_.network_message_loop()->PostTask(
          FROM_HERE, base::Bind(&ClientSession::OnConnectionAuthenticated,
                                base::Unretained(client), connection_ptr));
      context_.network_message_loop()->PostTask(
          FROM_HERE,
          base::Bind(&ClientSession::OnConnectionChannelsConnected,
                     base::Unretained(client), connection_ptr));
    }

    if (connection_index == 0) {
      client_ = client;
    } else {
      client2_ = client;
    }
  }

  // Helper method to remove a client connection from ChromotingHost.
  void RemoveClientSession() {
    client_->OnConnectionClosed(connection_, protocol::OK);
  }

  // Notify |host_| that |client_| has closed.
  void ClientSessionClosed() {
    host_->OnSessionClosed(client_);
  }

  // Notify |host_| that |client2_| has closed.
  void ClientSession2Closed() {
    host_->OnSessionClosed(client2_);
  }

  static void AddClientToHost(scoped_refptr<ChromotingHost> host,
                              ClientSession* session) {
    host->clients_.push_back(session);
  }

  void ShutdownHost() {
    message_loop_.PostTask(
        FROM_HERE, base::Bind(&ChromotingHost::Shutdown, host_,
                              base::Bind(&PostQuitTask, &message_loop_)));
  }

  void QuitMainMessageLoop() {
    PostQuitTask(&message_loop_);
  }

 protected:
  MessageLoop message_loop_;
  scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
  MockConnectionToClientEventHandler handler_;
  MockSignalStrategy signal_strategy_;
  MockEventExecutor* event_executor_;
  scoped_ptr<DesktopEnvironment> desktop_environment_;
  scoped_ptr<It2MeHostUserInterface> it2me_host_user_interface_;
  scoped_refptr<ChromotingHost> host_;
  MockChromotingHostContext context_;
  protocol::MockSessionManager* session_manager_;
  MockConnectionToClient* connection_;
  scoped_ptr<MockConnectionToClient> owned_connection_;
  ClientSession* client_;
  std::string session_jid_;
  MockSession* session_;  // Owned by |connection_|.
  SessionConfig session_config_;
  MockVideoStub video_stub_;
  MockClientStub client_stub_;
  MockHostStub host_stub_;
  MockConnectionToClient* connection2_;
  scoped_ptr<MockConnectionToClient> owned_connection2_;
  ClientSession* client2_;
  std::string session2_jid_;
  MockSession* session2_;  // Owned by |connection2_|.
  SessionConfig session_config2_;
  MockVideoStub video_stub2_;
  MockClientStub client_stub2_;
  MockHostStub host_stub2_;

  // Owned by |host_|.
  MockDisconnectWindow* disconnect_window_;
  MockContinueWindow* continue_window_;
  MockLocalInputMonitor* local_input_monitor_;
};

TEST_F(ChromotingHostTest, StartAndShutdown) {
  EXPECT_CALL(*session_manager_, Init(_, host_.get()));
  EXPECT_CALL(*disconnect_window_, Hide());
  EXPECT_CALL(*continue_window_, Hide());

  host_->Start();

  message_loop_.PostTask(
      FROM_HERE, base::Bind(
          &ChromotingHost::Shutdown, host_.get(),
          base::Bind(&PostQuitTask, &message_loop_)));
  message_loop_.Run();
}

TEST_F(ChromotingHostTest, Connect) {
  EXPECT_CALL(*session_manager_, Init(_, host_.get()));
  EXPECT_CALL(*disconnect_window_, Hide());
  EXPECT_CALL(*continue_window_, Hide());

  host_->Start();

  // When the video packet is received we first shut down ChromotingHost,
  // then execute the done task.
  Expectation start = EXPECT_CALL(*event_executor_, OnSessionStartedPtr(_));
  Expectation stop = EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _))
      .After(start)
      .WillOnce(DoAll(
          InvokeWithoutArgs(this, &ChromotingHostTest::ShutdownHost),
          RunDoneTask()))
      .RetiresOnSaturation();
  EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _))
      .Times(AnyNumber())
      .After(stop)
      .WillRepeatedly(RunDoneTask());
  EXPECT_CALL(*connection_, Disconnect())
      .After(stop)
      .WillOnce(
          InvokeWithoutArgs(this, &ChromotingHostTest::ClientSessionClosed))
      .RetiresOnSaturation();
  EXPECT_CALL(*event_executor_, OnSessionFinished())
      .After(stop);

  SimulateClientConnection(0, true);
  message_loop_.Run();
}

TEST_F(ChromotingHostTest, Reconnect) {
  EXPECT_CALL(*session_manager_, Init(_, host_.get()));
  EXPECT_CALL(*disconnect_window_, Hide());
  EXPECT_CALL(*continue_window_, Hide());

  host_->Start();

  // When the video packet is received we first disconnect the mock
  // connection, then run the done task, then quit the message loop.
  Expectation start1 = EXPECT_CALL(*event_executor_, OnSessionStartedPtr(_));
  Expectation stop1 = EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _))
      .After(start1)
      .WillOnce(DoAll(
          InvokeWithoutArgs(this, &ChromotingHostTest::RemoveClientSession),
          RunDoneTask(),
          InvokeWithoutArgs(this, &ChromotingHostTest::QuitMainMessageLoop)))
      .RetiresOnSaturation();
  EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _))
      .Times(AnyNumber())
      .After(stop1)
      .WillRepeatedly(RunDoneTask());
  EXPECT_CALL(*event_executor_, OnSessionFinished())
      .After(stop1);

  SimulateClientConnection(0, true);
  message_loop_.Run();

  Expectation start2 = EXPECT_CALL(*event_executor_, OnSessionStartedPtr(_))
      .After(stop1);
  Expectation stop2 = EXPECT_CALL(video_stub2_, ProcessVideoPacketPtr(_, _))
      .After(start2)
      .WillOnce(DoAll(
          InvokeWithoutArgs(this, &ChromotingHostTest::ShutdownHost),
          RunDoneTask()))
      .RetiresOnSaturation();
  EXPECT_CALL(video_stub2_, ProcessVideoPacketPtr(_, _))
      .Times(AnyNumber())
      .After(stop2)
      .WillRepeatedly(RunDoneTask());
  EXPECT_CALL(*connection2_, Disconnect())
      .After(stop2)
      .WillOnce(
          InvokeWithoutArgs(this, &ChromotingHostTest::ClientSession2Closed))
      .RetiresOnSaturation();
  EXPECT_CALL(*event_executor_, OnSessionFinished())
      .After(stop2);

  SimulateClientConnection(1, true);
  message_loop_.Run();
}

TEST_F(ChromotingHostTest, ConnectWhenAnotherClientIsConnected) {
  EXPECT_CALL(*session_manager_, Init(_, host_.get()));
  EXPECT_CALL(*disconnect_window_, Hide());
  EXPECT_CALL(*continue_window_, Hide());

  host_->Start();

  // When a video packet is received we connect the second mock
  // connection.
  Expectation start1 = EXPECT_CALL(*event_executor_, OnSessionStartedPtr(_));
  Expectation start2 = EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _))
      .After(start1)
      .WillOnce(DoAll(
          InvokeWithoutArgs(
              CreateFunctor(
                  this,
                  &ChromotingHostTest::SimulateClientConnection, 1, true)),
          RunDoneTask()))
      .RetiresOnSaturation();
  EXPECT_CALL(video_stub_, ProcessVideoPacketPtr(_, _))
      .Times(AnyNumber())
      .After(start2)
      .WillRepeatedly(RunDoneTask());
  EXPECT_CALL(*event_executor_, OnSessionFinished()).After(start2);
  EXPECT_CALL(*event_executor_, OnSessionStartedPtr(_)).After(start2);
  EXPECT_CALL(*connection_, Disconnect())
      .After(start2)
      .WillOnce(
          InvokeWithoutArgs(this, &ChromotingHostTest::ClientSessionClosed))
      .RetiresOnSaturation();
  Expectation stop2 = EXPECT_CALL(video_stub2_, ProcessVideoPacketPtr(_, _))
      .After(start2)
      .WillOnce(DoAll(
          InvokeWithoutArgs(this, &ChromotingHostTest::ShutdownHost),
          RunDoneTask()))
      .RetiresOnSaturation();
  EXPECT_CALL(video_stub2_, ProcessVideoPacketPtr(_, _))
      .Times(AnyNumber())
      .After(stop2)
      .WillRepeatedly(RunDoneTask());
  EXPECT_CALL(*event_executor_, OnSessionFinished()).After(stop2);
  EXPECT_CALL(*connection2_, Disconnect())
      .After(stop2)
      .WillOnce(
          InvokeWithoutArgs(this, &ChromotingHostTest::ClientSession2Closed))
      .RetiresOnSaturation();

  SimulateClientConnection(0, true);
  message_loop_.Run();
}

}  // namespace remoting
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2014-2015 Pavel Dolgov
 *
 * See the LICENSE file for terms of use.
 */

#ifndef MAINWINDOW_HPP
#define MAINWINDOW_HPP

#include "getModelIndex.hpp"
#include "desk_functions.hpp"
#include "IoView.hpp"
#include "GuiGame.hpp"
#include "GameOptions.hpp"

#include <QMainWindow>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow, IoView {
    Q_OBJECT
public:
    explicit MainWindow(QWidget* parent = 0);
    ~MainWindow();

protected:
    int getDeskSize_impl() const;

    int getWinNumber_impl() const;

    int getTimeNumber_impl() const;

    void finish_impl(bool fail, int score,
                     int steps_number) const;

    void sendHelpMessage_impl() const;

    void startGame_impl(int row_number);

    void errorHandling_impl(std::exception& e) const;

    void resizeBoardsContent(int boards_size);

    void resizeEvent(QResizeEvent* event);

private:
    Ui::MainWindow* ui;

    GuiGamePtr game_;

    GameOptionsPtr go_;

    void setBoardsModel();

    void configureBoard(int row_number);

    void preparingToPlay();

    void finishActions(int steps_number);

    bool endOfGame() const;

    void tryToMove();

    void settingOfScore();

    void settingOfTime();

    void settingOfSize();

    void setInitialParameters();

private slots:
    void on_quitButton_clicked();

    void on_winButton_clicked();

    void on_timeButton_clicked();

    void on_scoreButton_clicked();

    void on_startButton_clicked();

    void on_playButton_clicked();

    void on_playButton2_clicked();

    void on_gameBoard_clicked(const QModelIndex& index);

    void on_endButton_clicked();

    void resizeBoardsContent_deferred();
};

#endif
<commit_msg>MainWindow::default_font_<commit_after>/*
 * Copyright (C) 2014-2015 Pavel Dolgov
 *
 * See the LICENSE file for terms of use.
 */

#ifndef MAINWINDOW_HPP
#define MAINWINDOW_HPP

#include "getModelIndex.hpp"
#include "desk_functions.hpp"
#include "IoView.hpp"
#include "GuiGame.hpp"
#include "GameOptions.hpp"

#include <QMainWindow>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow, IoView {
    Q_OBJECT
public:
    explicit MainWindow(QWidget* parent = 0);
    ~MainWindow();

protected:
    int getDeskSize_impl() const;

    int getWinNumber_impl() const;

    int getTimeNumber_impl() const;

    void finish_impl(bool fail, int score,
                     int steps_number) const;

    void sendHelpMessage_impl() const;

    void startGame_impl(int row_number);

    void errorHandling_impl(std::exception& e) const;

    void resizeBoardsContent(int boards_size);

    void resizeEvent(QResizeEvent* event);

private:
    Ui::MainWindow* ui;

    GuiGamePtr game_;

    GameOptionsPtr go_;

    QFont default_font_;

    void setBoardsModel();

    void configureBoard(int row_number);

    void preparingToPlay();

    void finishActions(int steps_number);

    bool endOfGame() const;

    void tryToMove();

    void settingOfScore();

    void settingOfTime();

    void settingOfSize();

    void setInitialParameters();

private slots:
    void on_quitButton_clicked();

    void on_winButton_clicked();

    void on_timeButton_clicked();

    void on_scoreButton_clicked();

    void on_startButton_clicked();

    void on_playButton_clicked();

    void on_playButton2_clicked();

    void on_gameBoard_clicked(const QModelIndex& index);

    void on_endButton_clicked();

    void resizeBoardsContent_deferred();
};

#endif
<|endoftext|>