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

#include "chrome/browser/debugger/devtools_http_protocol_handler.h"

#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/message_loop_proxy.h"
#include "base/string_util.h"
#include "base/thread.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/debugger/devtools_client_host.h"
#include "chrome/browser/debugger/devtools_manager.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/devtools_messages.h"
#include "chrome/common/net/url_request_context_getter.h"
#include "googleurl/src/gurl.h"
#include "net/base/io_buffer.h"
#include "net/base/listen_socket.h"
#include "net/server/http_server_request_info.h"
#include "net/url_request/url_request_context.h"

const int kBufferSize = 16 * 1024;

namespace {

// An internal implementation of DevToolsClientHost that delegates
// messages sent for DevToolsClient to a DebuggerShell instance.
class DevToolsClientHostImpl : public DevToolsClientHost {
 public:
  explicit DevToolsClientHostImpl(HttpListenSocket* socket)
      : socket_(socket) {}
  ~DevToolsClientHostImpl() {}

  // DevToolsClientHost interface
  virtual void InspectedTabClosing() {
    ChromeThread::PostTask(
        ChromeThread::IO,
        FROM_HERE,
        NewRunnableMethod(socket_,
                          &HttpListenSocket::Close));
  }

  virtual void SendMessageToClient(const IPC::Message& msg) {
    IPC_BEGIN_MESSAGE_MAP(DevToolsClientHostImpl, msg)
      IPC_MESSAGE_HANDLER(DevToolsClientMsg_RpcMessage, OnRpcMessage);
      IPC_MESSAGE_UNHANDLED_ERROR()
    IPC_END_MESSAGE_MAP()
  }

  void NotifyCloseListener() {
    DevToolsClientHost::NotifyCloseListener();
  }
 private:
  // Message handling routines
  void OnRpcMessage(const DevToolsMessageData& data) {
    std::string message;
    message += "devtools$$dispatch(\"" + data.class_name + "\", \"" +
        data.method_name + "\"";
    for (std::vector<std::string>::const_iterator it = data.arguments.begin();
         it != data.arguments.end(); ++it) {
      std::string param = *it;
      if (!param.empty())
        message += ", " + param;
    }
    message += ")";
    socket_->SendOverWebSocket(message);
  }
  HttpListenSocket* socket_;
};

}

DevToolsHttpProtocolHandler::~DevToolsHttpProtocolHandler() {
  // Stop() must be called prior to this being called
  DCHECK(server_.get() == NULL);
}

void DevToolsHttpProtocolHandler::Start() {
  ChromeThread::PostTask(
      ChromeThread::IO, FROM_HERE,
      NewRunnableMethod(this, &DevToolsHttpProtocolHandler::Init));
}

void DevToolsHttpProtocolHandler::Stop() {
  ChromeThread::PostTask(
      ChromeThread::IO, FROM_HERE,
      NewRunnableMethod(this, &DevToolsHttpProtocolHandler::Teardown));
}

void DevToolsHttpProtocolHandler::OnHttpRequest(
    HttpListenSocket* socket,
    const HttpServerRequestInfo& info) {
  if (info.path == "" || info.path == "/") {
    // Pages discovery request.
    ChromeThread::PostTask(
        ChromeThread::UI,
        FROM_HERE,
        NewRunnableMethod(this,
                          &DevToolsHttpProtocolHandler::OnHttpRequestUI,
                          socket,
                          info));
    return;
  }

  size_t pos = info.path.find("/devtools/");
  if (pos != 0) {
    socket->Send404();
    return;
  }

  // Proxy static files from chrome://devtools/*.
  URLRequest* request = new URLRequest(GURL("chrome:/" + info.path), this);
  Bind(request, socket);
  request->set_context(
      Profile::GetDefaultRequestContext()->GetURLRequestContext());
  request->Start();
}

void DevToolsHttpProtocolHandler::OnWebSocketRequest(
    HttpListenSocket* socket,
    const HttpServerRequestInfo& request) {
  ChromeThread::PostTask(
      ChromeThread::UI,
      FROM_HERE,
      NewRunnableMethod(
          this,
          &DevToolsHttpProtocolHandler::OnWebSocketRequestUI,
          socket,
          request));
}

void DevToolsHttpProtocolHandler::OnWebSocketMessage(HttpListenSocket* socket,
                                                     const std::string& data) {
  ChromeThread::PostTask(
      ChromeThread::UI,
      FROM_HERE,
      NewRunnableMethod(
          this,
          &DevToolsHttpProtocolHandler::OnWebSocketMessageUI,
          socket,
          data));
}

void DevToolsHttpProtocolHandler::OnClose(HttpListenSocket* socket) {
  SocketToRequestsMap::iterator it = socket_to_requests_io_.find(socket);
  if (it != socket_to_requests_io_.end()) {
    // Dispose delegating socket.
    for (std::set<URLRequest*>::iterator it2 = it->second.begin();
         it2 != it->second.end(); ++it2) {
      URLRequest* request = *it2;
      request->Cancel();
      request_to_socket_io_.erase(request);
      request_to_buffer_io_.erase(request);
      delete request;
    }
    socket_to_requests_io_.erase(socket);
  }

  ChromeThread::PostTask(
      ChromeThread::UI,
      FROM_HERE,
      NewRunnableMethod(
          this,
          &DevToolsHttpProtocolHandler::OnCloseUI,
          socket));
}

void DevToolsHttpProtocolHandler::OnHttpRequestUI(
    HttpListenSocket* socket,
    const HttpServerRequestInfo& info) {
  std::string response = "";
  for (BrowserList::const_iterator it = BrowserList::begin(),
       end = BrowserList::end(); it != end; ++it) {
    TabStripModel* model = (*it)->tabstrip_model();
    for (int i = 0, size = model->count(); i < size; ++i) {
      TabContents* tab_contents = model->GetTabContentsAt(i);
      NavigationController& controller = tab_contents->controller();
      NavigationEntry* entry = controller.GetActiveEntry();
      if (entry == NULL)
        continue;

      if (!entry->url().is_valid())
        continue;

      DevToolsClientHost* client_host = DevToolsManager::GetInstance()->
          GetDevToolsClientHostFor(tab_contents->render_view_host());
      if (!client_host) {
        response += StringPrintf(
            "%s (%s)
",
            controller.session_id().id(),
            UTF16ToUTF8(entry->title()).c_str(),
            entry->url().spec().c_str());
      } else {
        response += StringPrintf(
            "%s (%s)
",
            UTF16ToUTF8(entry->title()).c_str(),
            entry->url().spec().c_str());
      }
    }
  }
  response += "";
  Send200(socket, response, "text/html");
}

void DevToolsHttpProtocolHandler::OnWebSocketRequestUI(
    HttpListenSocket* socket,
    const HttpServerRequestInfo& request) {
  std::string prefix = "/devtools/page/";
  size_t pos = request.path.find(prefix);
  if (pos != 0) {
    Send404(socket);
    return;
  }
  std::string page_id = request.path.substr(prefix.length());
  int id = 0;
  if (!StringToInt(page_id, &id)) {
    Send500(socket, "Invalid page id: " + page_id);
    return;
  }

  TabContents* tab_contents = GetTabContents(id);
  if (tab_contents == NULL) {
    Send500(socket, "No such page id: " + page_id);
    return;
  }

  DevToolsManager* manager = DevToolsManager::GetInstance();
  if (manager->GetDevToolsClientHostFor(tab_contents->render_view_host())) {
    Send500(socket, "Page with given id is being inspected: " + page_id);
    return;
  }

  DevToolsClientHostImpl* client_host = new DevToolsClientHostImpl(socket);
  socket_to_client_host_ui_[socket] = client_host;

  manager->RegisterDevToolsClientHostFor(
      tab_contents->render_view_host(),
      client_host);
  AcceptWebSocket(socket, request);
}

void DevToolsHttpProtocolHandler::OnWebSocketMessageUI(
    HttpListenSocket* socket,
    const std::string& d) {
  SocketToClientHostMap::iterator it = socket_to_client_host_ui_.find(socket);
  if (it == socket_to_client_host_ui_.end())
    return;

  std::string data = d;
  // TODO(pfeldman): Replace with proper parsing / dispatching.
  DevToolsMessageData message_data;
  message_data.class_name = "ToolsAgent";
  message_data.method_name = "dispatchOnInspectorController";

  size_t pos = data.find(" ");
  message_data.arguments.push_back(data.substr(0, pos));
  data = data.substr(pos + 1);

  message_data.arguments.push_back(data);

  DevToolsManager* manager = DevToolsManager::GetInstance();
  manager->ForwardToDevToolsAgent(it->second,
      DevToolsAgentMsg_RpcMessage(DevToolsMessageData(message_data)));
}

void DevToolsHttpProtocolHandler::OnCloseUI(HttpListenSocket* socket) {
  SocketToClientHostMap::iterator it = socket_to_client_host_ui_.find(socket);
  if (it == socket_to_client_host_ui_.end())
    return;
  DevToolsClientHostImpl* client_host =
      static_cast<DevToolsClientHostImpl*>(it->second);
  client_host->NotifyCloseListener();
  delete client_host;
  socket_to_client_host_ui_.erase(socket);
}

void DevToolsHttpProtocolHandler::OnResponseStarted(URLRequest* request) {
  RequestToSocketMap::iterator it = request_to_socket_io_.find(request);
  if (it == request_to_socket_io_.end())
    return;

  HttpListenSocket* socket = it->second;

  int expected_size = static_cast<int>(request->GetExpectedContentSize());

  std::string content_type;
  request->GetMimeType(&content_type);

  if (request->status().is_success()) {
    socket->Send(StringPrintf("HTTP/1.1 200 OK\r\n"
                              "Content-Type:%s\r\n"
                              "Content-Length:%d\r\n"
                              "\r\n",
                              content_type.c_str(),
                              expected_size));
  } else {
    socket->Send404();
  }

  int bytes_read = 0;
  // Some servers may treat HEAD requests as GET requests.  To free up the
  // network connection as soon as possible, signal that the request has
  // completed immediately, without trying to read any data back (all we care
  // about is the response code and headers, which we already have).
  net::IOBuffer* buffer = request_to_buffer_io_[request].get();
  if (request->status().is_success())
    request->Read(buffer, kBufferSize, &bytes_read);
  OnReadCompleted(request, bytes_read);
}

void DevToolsHttpProtocolHandler::OnReadCompleted(URLRequest* request,
                                                  int bytes_read) {
  RequestToSocketMap::iterator it = request_to_socket_io_.find(request);
  if (it == request_to_socket_io_.end())
    return;

  HttpListenSocket* socket = it->second;

  net::IOBuffer* buffer = request_to_buffer_io_[request].get();
  do {
    if (!request->status().is_success() || bytes_read <= 0)
      break;
    socket->Send(buffer->data(), bytes_read);
  } while (request->Read(buffer, kBufferSize, &bytes_read));

  // See comments re: HEAD requests in OnResponseStarted().
  if (!request->status().is_io_pending())
    RequestCompleted(request);
}

DevToolsHttpProtocolHandler::DevToolsHttpProtocolHandler(int port)
    : port_(port),
      server_(NULL) {
}

void DevToolsHttpProtocolHandler::Init() {
  server_ = HttpListenSocket::Listen("127.0.0.1", port_, this);
}

// Run on I/O thread
void DevToolsHttpProtocolHandler::Teardown() {
  server_ = NULL;
}

void DevToolsHttpProtocolHandler::Bind(URLRequest* request,
                                       HttpListenSocket* socket) {
  request_to_socket_io_[request] = socket;
  SocketToRequestsMap::iterator it = socket_to_requests_io_.find(socket);
  if (it == socket_to_requests_io_.end()) {
    std::pair<HttpListenSocket*, std::set<URLRequest*> > value(
        socket,
        std::set<URLRequest*>());
    it = socket_to_requests_io_.insert(value).first;
  }
  it->second.insert(request);
  request_to_buffer_io_[request] = new net::IOBuffer(kBufferSize);
}

void DevToolsHttpProtocolHandler::RequestCompleted(URLRequest* request) {
  RequestToSocketMap::iterator it = request_to_socket_io_.find(request);
  if (it == request_to_socket_io_.end())
    return;

  HttpListenSocket* socket = it->second;
  request_to_socket_io_.erase(request);
  SocketToRequestsMap::iterator it2 = socket_to_requests_io_.find(socket);
  it2->second.erase(request);
  request_to_buffer_io_.erase(request);
  delete request;
}

void DevToolsHttpProtocolHandler::Send200(HttpListenSocket* socket,
                                          const std::string& data,
                                          const std::string& mime_type) {
  ChromeThread::PostTask(
      ChromeThread::IO, FROM_HERE,
      NewRunnableMethod(socket,
                        &HttpListenSocket::Send200,
                        data,
                        mime_type));
}

void DevToolsHttpProtocolHandler::Send404(HttpListenSocket* socket) {
  ChromeThread::PostTask(
      ChromeThread::IO, FROM_HERE,
      NewRunnableMethod(socket,
                        &HttpListenSocket::Send404));
}

void DevToolsHttpProtocolHandler::Send500(HttpListenSocket* socket,
                                          const std::string& message) {
  ChromeThread::PostTask(
      ChromeThread::IO, FROM_HERE,
      NewRunnableMethod(socket,
                        &HttpListenSocket::Send500,
                        message));
}

void DevToolsHttpProtocolHandler::AcceptWebSocket(
    HttpListenSocket* socket,
    const HttpServerRequestInfo& request) {
  ChromeThread::PostTask(
      ChromeThread::IO, FROM_HERE,
      NewRunnableMethod(socket,
                        &HttpListenSocket::AcceptWebSocket,
                        request));
}

TabContents* DevToolsHttpProtocolHandler::GetTabContents(int session_id) {
  for (BrowserList::const_iterator it = BrowserList::begin(),
       end = BrowserList::end(); it != end; ++it) {
    TabStripModel* model = (*it)->tabstrip_model();
    for (int i = 0, size = model->count(); i < size; ++i) {
      NavigationController& controller =
          model->GetTabContentsAt(i)->controller();
      if (controller.session_id().id() == session_id)
        return controller.tab_contents();
    }
  }
  return NULL;
}
<commit_msg>DevTools: restore remote rebugging after upstream breakage.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/debugger/devtools_http_protocol_handler.h"

#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/message_loop_proxy.h"
#include "base/string_util.h"
#include "base/thread.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/debugger/devtools_client_host.h"
#include "chrome/browser/debugger/devtools_manager.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/devtools_messages.h"
#include "chrome/common/net/url_request_context_getter.h"
#include "googleurl/src/gurl.h"
#include "net/base/io_buffer.h"
#include "net/base/listen_socket.h"
#include "net/server/http_server_request_info.h"
#include "net/url_request/url_request_context.h"

const int kBufferSize = 16 * 1024;

namespace {

// An internal implementation of DevToolsClientHost that delegates
// messages sent for DevToolsClient to a DebuggerShell instance.
class DevToolsClientHostImpl : public DevToolsClientHost {
 public:
  explicit DevToolsClientHostImpl(HttpListenSocket* socket)
      : socket_(socket) {}
  ~DevToolsClientHostImpl() {}

  // DevToolsClientHost interface
  virtual void InspectedTabClosing() {
    ChromeThread::PostTask(
        ChromeThread::IO,
        FROM_HERE,
        NewRunnableMethod(socket_,
                          &HttpListenSocket::Close));
  }

  virtual void SendMessageToClient(const IPC::Message& msg) {
    IPC_BEGIN_MESSAGE_MAP(DevToolsClientHostImpl, msg)
      IPC_MESSAGE_HANDLER(DevToolsClientMsg_RpcMessage, OnRpcMessage);
      IPC_MESSAGE_UNHANDLED_ERROR()
    IPC_END_MESSAGE_MAP()
  }

  void NotifyCloseListener() {
    DevToolsClientHost::NotifyCloseListener();
  }
 private:
  // Message handling routines
  void OnRpcMessage(const DevToolsMessageData& data) {
    std::string message;
    message += "devtools$$dispatch(\"" + data.class_name + "\", \"" +
        data.method_name + "\"";
    for (std::vector<std::string>::const_iterator it = data.arguments.begin();
         it != data.arguments.end(); ++it) {
      std::string param = *it;
      if (!param.empty())
        message += ", " + param;
    }
    message += ")";
    socket_->SendOverWebSocket(message);
  }
  HttpListenSocket* socket_;
};

}

DevToolsHttpProtocolHandler::~DevToolsHttpProtocolHandler() {
  // Stop() must be called prior to this being called
  DCHECK(server_.get() == NULL);
}

void DevToolsHttpProtocolHandler::Start() {
  ChromeThread::PostTask(
      ChromeThread::IO, FROM_HERE,
      NewRunnableMethod(this, &DevToolsHttpProtocolHandler::Init));
}

void DevToolsHttpProtocolHandler::Stop() {
  ChromeThread::PostTask(
      ChromeThread::IO, FROM_HERE,
      NewRunnableMethod(this, &DevToolsHttpProtocolHandler::Teardown));
}

void DevToolsHttpProtocolHandler::OnHttpRequest(
    HttpListenSocket* socket,
    const HttpServerRequestInfo& info) {
  if (info.path == "" || info.path == "/") {
    // Pages discovery request.
    ChromeThread::PostTask(
        ChromeThread::UI,
        FROM_HERE,
        NewRunnableMethod(this,
                          &DevToolsHttpProtocolHandler::OnHttpRequestUI,
                          socket,
                          info));
    return;
  }

  size_t pos = info.path.find("/devtools/");
  if (pos != 0) {
    socket->Send404();
    return;
  }

  // Proxy static files from chrome://devtools/*.
  URLRequest* request = new URLRequest(GURL("chrome:/" + info.path), this);
  Bind(request, socket);
  request->set_context(
      Profile::GetDefaultRequestContext()->GetURLRequestContext());
  request->Start();
}

void DevToolsHttpProtocolHandler::OnWebSocketRequest(
    HttpListenSocket* socket,
    const HttpServerRequestInfo& request) {
  ChromeThread::PostTask(
      ChromeThread::UI,
      FROM_HERE,
      NewRunnableMethod(
          this,
          &DevToolsHttpProtocolHandler::OnWebSocketRequestUI,
          socket,
          request));
}

void DevToolsHttpProtocolHandler::OnWebSocketMessage(HttpListenSocket* socket,
                                                     const std::string& data) {
  ChromeThread::PostTask(
      ChromeThread::UI,
      FROM_HERE,
      NewRunnableMethod(
          this,
          &DevToolsHttpProtocolHandler::OnWebSocketMessageUI,
          socket,
          data));
}

void DevToolsHttpProtocolHandler::OnClose(HttpListenSocket* socket) {
  SocketToRequestsMap::iterator it = socket_to_requests_io_.find(socket);
  if (it != socket_to_requests_io_.end()) {
    // Dispose delegating socket.
    for (std::set<URLRequest*>::iterator it2 = it->second.begin();
         it2 != it->second.end(); ++it2) {
      URLRequest* request = *it2;
      request->Cancel();
      request_to_socket_io_.erase(request);
      request_to_buffer_io_.erase(request);
      delete request;
    }
    socket_to_requests_io_.erase(socket);
  }

  ChromeThread::PostTask(
      ChromeThread::UI,
      FROM_HERE,
      NewRunnableMethod(
          this,
          &DevToolsHttpProtocolHandler::OnCloseUI,
          socket));
}

void DevToolsHttpProtocolHandler::OnHttpRequestUI(
    HttpListenSocket* socket,
    const HttpServerRequestInfo& info) {
  std::string response = "";
  for (BrowserList::const_iterator it = BrowserList::begin(),
       end = BrowserList::end(); it != end; ++it) {
    TabStripModel* model = (*it)->tabstrip_model();
    for (int i = 0, size = model->count(); i < size; ++i) {
      TabContents* tab_contents = model->GetTabContentsAt(i);
      NavigationController& controller = tab_contents->controller();
      NavigationEntry* entry = controller.GetActiveEntry();
      if (entry == NULL)
        continue;

      if (!entry->url().is_valid())
        continue;

      DevToolsClientHost* client_host = DevToolsManager::GetInstance()->
          GetDevToolsClientHostFor(tab_contents->render_view_host());
      if (!client_host) {
        response += StringPrintf(
            "%s (%s)
",
            controller.session_id().id(),
            UTF16ToUTF8(entry->title()).c_str(),
            entry->url().spec().c_str());
      } else {
        response += StringPrintf(
            "%s (%s)
",
            UTF16ToUTF8(entry->title()).c_str(),
            entry->url().spec().c_str());
      }
    }
  }
  response += "";
  Send200(socket, response, "text/html");
}

void DevToolsHttpProtocolHandler::OnWebSocketRequestUI(
    HttpListenSocket* socket,
    const HttpServerRequestInfo& request) {
  std::string prefix = "/devtools/page/";
  size_t pos = request.path.find(prefix);
  if (pos != 0) {
    Send404(socket);
    return;
  }
  std::string page_id = request.path.substr(prefix.length());
  int id = 0;
  if (!StringToInt(page_id, &id)) {
    Send500(socket, "Invalid page id: " + page_id);
    return;
  }

  TabContents* tab_contents = GetTabContents(id);
  if (tab_contents == NULL) {
    Send500(socket, "No such page id: " + page_id);
    return;
  }

  DevToolsManager* manager = DevToolsManager::GetInstance();
  if (manager->GetDevToolsClientHostFor(tab_contents->render_view_host())) {
    Send500(socket, "Page with given id is being inspected: " + page_id);
    return;
  }

  DevToolsClientHostImpl* client_host = new DevToolsClientHostImpl(socket);
  socket_to_client_host_ui_[socket] = client_host;

  manager->RegisterDevToolsClientHostFor(
      tab_contents->render_view_host(),
      client_host);
  AcceptWebSocket(socket, request);
}

void DevToolsHttpProtocolHandler::OnWebSocketMessageUI(
    HttpListenSocket* socket,
    const std::string& data) {
  SocketToClientHostMap::iterator it = socket_to_client_host_ui_.find(socket);
  if (it == socket_to_client_host_ui_.end())
    return;

  // TODO(pfeldman): Replace with proper parsing / dispatching.
  DevToolsMessageData message_data;
  message_data.class_name = "ToolsAgent";
  message_data.method_name = "dispatchOnInspectorController";
  message_data.arguments.push_back(data);

  DevToolsManager* manager = DevToolsManager::GetInstance();
  manager->ForwardToDevToolsAgent(it->second,
      DevToolsAgentMsg_RpcMessage(DevToolsMessageData(message_data)));
}

void DevToolsHttpProtocolHandler::OnCloseUI(HttpListenSocket* socket) {
  SocketToClientHostMap::iterator it = socket_to_client_host_ui_.find(socket);
  if (it == socket_to_client_host_ui_.end())
    return;
  DevToolsClientHostImpl* client_host =
      static_cast<DevToolsClientHostImpl*>(it->second);
  client_host->NotifyCloseListener();
  delete client_host;
  socket_to_client_host_ui_.erase(socket);
}

void DevToolsHttpProtocolHandler::OnResponseStarted(URLRequest* request) {
  RequestToSocketMap::iterator it = request_to_socket_io_.find(request);
  if (it == request_to_socket_io_.end())
    return;

  HttpListenSocket* socket = it->second;

  int expected_size = static_cast<int>(request->GetExpectedContentSize());

  std::string content_type;
  request->GetMimeType(&content_type);

  if (request->status().is_success()) {
    socket->Send(StringPrintf("HTTP/1.1 200 OK\r\n"
                              "Content-Type:%s\r\n"
                              "Content-Length:%d\r\n"
                              "\r\n",
                              content_type.c_str(),
                              expected_size));
  } else {
    socket->Send404();
  }

  int bytes_read = 0;
  // Some servers may treat HEAD requests as GET requests.  To free up the
  // network connection as soon as possible, signal that the request has
  // completed immediately, without trying to read any data back (all we care
  // about is the response code and headers, which we already have).
  net::IOBuffer* buffer = request_to_buffer_io_[request].get();
  if (request->status().is_success())
    request->Read(buffer, kBufferSize, &bytes_read);
  OnReadCompleted(request, bytes_read);
}

void DevToolsHttpProtocolHandler::OnReadCompleted(URLRequest* request,
                                                  int bytes_read) {
  RequestToSocketMap::iterator it = request_to_socket_io_.find(request);
  if (it == request_to_socket_io_.end())
    return;

  HttpListenSocket* socket = it->second;

  net::IOBuffer* buffer = request_to_buffer_io_[request].get();
  do {
    if (!request->status().is_success() || bytes_read <= 0)
      break;
    socket->Send(buffer->data(), bytes_read);
  } while (request->Read(buffer, kBufferSize, &bytes_read));

  // See comments re: HEAD requests in OnResponseStarted().
  if (!request->status().is_io_pending())
    RequestCompleted(request);
}

DevToolsHttpProtocolHandler::DevToolsHttpProtocolHandler(int port)
    : port_(port),
      server_(NULL) {
}

void DevToolsHttpProtocolHandler::Init() {
  server_ = HttpListenSocket::Listen("127.0.0.1", port_, this);
}

// Run on I/O thread
void DevToolsHttpProtocolHandler::Teardown() {
  server_ = NULL;
}

void DevToolsHttpProtocolHandler::Bind(URLRequest* request,
                                       HttpListenSocket* socket) {
  request_to_socket_io_[request] = socket;
  SocketToRequestsMap::iterator it = socket_to_requests_io_.find(socket);
  if (it == socket_to_requests_io_.end()) {
    std::pair<HttpListenSocket*, std::set<URLRequest*> > value(
        socket,
        std::set<URLRequest*>());
    it = socket_to_requests_io_.insert(value).first;
  }
  it->second.insert(request);
  request_to_buffer_io_[request] = new net::IOBuffer(kBufferSize);
}

void DevToolsHttpProtocolHandler::RequestCompleted(URLRequest* request) {
  RequestToSocketMap::iterator it = request_to_socket_io_.find(request);
  if (it == request_to_socket_io_.end())
    return;

  HttpListenSocket* socket = it->second;
  request_to_socket_io_.erase(request);
  SocketToRequestsMap::iterator it2 = socket_to_requests_io_.find(socket);
  it2->second.erase(request);
  request_to_buffer_io_.erase(request);
  delete request;
}

void DevToolsHttpProtocolHandler::Send200(HttpListenSocket* socket,
                                          const std::string& data,
                                          const std::string& mime_type) {
  ChromeThread::PostTask(
      ChromeThread::IO, FROM_HERE,
      NewRunnableMethod(socket,
                        &HttpListenSocket::Send200,
                        data,
                        mime_type));
}

void DevToolsHttpProtocolHandler::Send404(HttpListenSocket* socket) {
  ChromeThread::PostTask(
      ChromeThread::IO, FROM_HERE,
      NewRunnableMethod(socket,
                        &HttpListenSocket::Send404));
}

void DevToolsHttpProtocolHandler::Send500(HttpListenSocket* socket,
                                          const std::string& message) {
  ChromeThread::PostTask(
      ChromeThread::IO, FROM_HERE,
      NewRunnableMethod(socket,
                        &HttpListenSocket::Send500,
                        message));
}

void DevToolsHttpProtocolHandler::AcceptWebSocket(
    HttpListenSocket* socket,
    const HttpServerRequestInfo& request) {
  ChromeThread::PostTask(
      ChromeThread::IO, FROM_HERE,
      NewRunnableMethod(socket,
                        &HttpListenSocket::AcceptWebSocket,
                        request));
}

TabContents* DevToolsHttpProtocolHandler::GetTabContents(int session_id) {
  for (BrowserList::const_iterator it = BrowserList::begin(),
       end = BrowserList::end(); it != end; ++it) {
    TabStripModel* model = (*it)->tabstrip_model();
    for (int i = 0, size = model->count(); i < size; ++i) {
      NavigationController& controller =
          model->GetTabContentsAt(i)->controller();
      if (controller.session_id().id() == session_id)
        return controller.tab_contents();
    }
  }
  return NULL;
}
<|endoftext|>


<commit_before>// library.C
//
// Copyright 1996-2001 Per Abrahamsen and Sren Hansen
// Copyright 2000-2001 KVL.
//
// This file is part of Daisy.
//
// Daisy is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser Public License as published by
// the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// Daisy 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 Lesser Public License for more details.
//
// You should have received a copy of the GNU Lesser Public License
// along with Daisy; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

#define BUILD_DLL

#include "library.h"
#include "block.h"
#include "alist.h"
#include "syntax.h"
#include "treelog.h"
#include <sstream>
#include "assertion.h"
#include "symbol.h"
#include "memutils.h"
#include <map>
#include <set>
#include <sstream>

struct Library::Implementation
{
  // Id.
  const symbol name;
  const char * description;

  // Types.
  typedef std::map<symbol, builder> bmap_type;
  typedef std::map<symbol, AttributeList*> alist_map;
  typedef std::map<symbol, const Syntax*> syntax_map;

  // Data (remember to update Library::clone if you change this).
  bmap_type builders;
  alist_map alists;
  syntax_map syntaxen;
  std::vector<doc_fun> doc_funs;

  // Accessors.
  AttributeList& lookup (symbol) const;
  bool check (symbol) const;
  void add_base (AttributeList&, const Syntax&);
  void add (symbol, AttributeList&, const Syntax&, builder);
  const Syntax& syntax (symbol) const;
  void entries (std::vector<symbol>&) const;
  void remove (symbol);
  void clear_parsed ();
  void refile_parsed (const std::string& from, const std::string& to);
  static void load_syntax (Syntax&, AttributeList&);
  Implementation (const char* n);
  ~Implementation ();
};

AttributeList&
Library::Implementation::lookup (const symbol key) const
{
  alist_map::const_iterator i = alists.find (key);

  if (i == alists.end ())
    daisy_notreached ();

  return *(*i).second;
}

bool
Library::Implementation::check (const symbol key) const
{
  alist_map::const_iterator i = alists.find (key);

  if (i == alists.end ())
    return false;

  return true;
}

void
Library::Implementation::add_base (AttributeList& value,
			      const Syntax& syntax)
{
  daisy_assert (value.check ("base_model"));
  const symbol key = value.identifier ("base_model");
  alists[key] = &value;
  syntaxen[key] = &syntax;
}

void
Library::Implementation::add (const symbol key, AttributeList& value,
			      const Syntax& syntax, builder build)
{
  alists[key] = &value;
  syntaxen[key] = &syntax;
  // builders.insert (std::make_pair (key, build));
  builders[key] = build;
}

const Syntax&
Library::Implementation::syntax (const symbol key) const
{
  syntax_map::const_iterator i = syntaxen.find (key);

  if (i == syntaxen.end ())
    daisy_panic ("'" + key + "' not found");

  return *(*i).second;
}

void
Library::Implementation::entries (std::vector<symbol>& result) const
{
  for (syntax_map::const_iterator i = syntaxen.begin ();
       i != syntaxen.end ();
       i++)
    {
      result.push_back ((*i).first);
    }
}

void
Library::Implementation::remove (const symbol key)
{
  alists.erase (alists.find (key));
  syntaxen.erase (syntaxen.find (key));
}

void
Library::Implementation::clear_parsed ()
{
 retry:
  for (alist_map::iterator i = alists.begin (); i != alists.end (); i++)
    {
      AttributeList& alist = *((*i).second);
      if (alist.check ("parsed_from_file"))
	{
	  const symbol key = (*i).first;
	  syntax_map::iterator j = syntaxen.find (key);
	  daisy_assert (j != syntaxen.end ());
	  syntaxen.erase (j);
	  alists.erase (i);
	  delete &alist;
	  goto retry;
	}
    }
}

void
Library::Implementation::refile_parsed (const std::string& from, const std::string& to)
{
  daisy_assert (from != to);
  for (alist_map::iterator i = alists.begin (); i != alists.end (); i++)
    {
      AttributeList& alist = *((*i).second);
      if (alist.check ("parsed_from_file")
	  && alist.name ("parsed_from_file") == from)
	{
	  alist.add ("parsed_from_file", to);
	}
    }
}

Library::Implementation::Implementation (const char* n)
  : name (symbol (n)),
    description (NULL)
{ }

Library::Implementation::~Implementation ()
{
  // Delete alists.
  map_delete (alists.begin (), alists.end ());

  // Delete unique syntaxen.
  std::set<const Syntax*> unique;
  for (syntax_map::iterator i = syntaxen.begin ();
       i != syntaxen.end ();
       i++)
    {
      daisy_assert ((*i).second);
      unique.insert ((*i).second);
      (*i).second = NULL;
    }
  sequence_delete (unique.begin (), unique.end ());
}

void
Library::clear_parsed ()
{ impl->clear_parsed (); }

void
Library::refile_parsed (const std::string& from, const std::string& to)
{ impl->refile_parsed (from, to); }

symbol
Library::name () const
{ return impl->name; }

const char*
Library::description () const
{ return impl->description; }

AttributeList&
Library::lookup (const symbol key) const
{ return impl->lookup (key); }

bool
Library::check (const symbol key) const
{ return impl->check (key); }

bool
Library::complete (const Metalib& metalib, const symbol key) const
{
  if (!check (key))
    return false;

  if (!syntax (key).check (metalib, lookup (key), Treelog::null ()))
    return false;

  return true;
}

void
Library::add_base (AttributeList& value, const Syntax& syntax)
{ impl->add_base (value, syntax); }

void
Library::add (const symbol key, AttributeList& value, const Syntax& syntax,
              builder build)
{ impl->add (key, value, syntax, build); }

void
Library::add_derived (const symbol name, AttributeList& al,
		      const symbol super)
{
  add_derived (name, syntax (super), al, super);
}

void
Library::add_derived (const symbol name, const Syntax& syn, AttributeList& al,
		      const symbol super)
{
  al.add ("type", super);
  add (name, al, syn, impl->builders[super]);
}

const Syntax&
Library::syntax (const symbol key) const
{ return impl->syntax (key); }

void
Library::entries (std::vector<symbol>& result) const
{ impl->entries (result); }

bool
Library::is_derived_from (const symbol a, const symbol b) const
{
  if (a == b)
    return true;

  const AttributeList& al = lookup (a);

  if (!al.check ("type") && !al.check ("base_model"))
    return false;

  const symbol type = al.check ("type")
    ? al.identifier ("type")
    : al.identifier ("base_model");

  if (type == b)
    return true;

  daisy_assert (check (type));

  if (type == a)
    return false;

  return is_derived_from (type, b);
}

const symbol
Library::base_model (const symbol parameterization) const
{
  const AttributeList& al = lookup (parameterization);

  if (al.check ("type"))
    return base_model (al.identifier ("type"));
  if (al.check ("base_model")
      && al.identifier ("base_model") != parameterization)
    return  base_model (al.identifier ("base_model"));

  return parameterization;
}

bool
Library::has_interesting_description (const AttributeList& alist) const
{
  // A missing description is boring.
  if (!alist.check ("description"))
    return false;

  // The description of models are always interesting.
  if (!alist.check ("type"))
    return true;

  // If the model has no description, this one is interesting.
  const symbol type = alist.identifier ("type");
  if (!check (type))
    {
      daisy_bug (name () + " does not have " + type.name ());
      return false;
    }
  daisy_assert (check (type));
  const AttributeList& super = lookup (type);
  if (!super.check ("description"))
    return true;

  // If the model description is different, this one is interesting.
  return alist.name ("description") != super.name ("description");
}

void
Library::add_doc_fun (doc_fun fun)
{ impl->doc_funs.push_back (fun); }

std::vector<Library::doc_fun>&
Library::doc_funs () const
{ return impl->doc_funs; }

void
Library::remove (const symbol key)
{ impl->remove (key); }

Model*
Library::build_raw (const symbol type, Block& block) const
{
  const Implementation::bmap_type::const_iterator i
    = impl->builders.find (type);
  if  (i == impl->builders.end ())
    {
      std::ostringstream tmp;
      tmp << "No '" << type.name () << "' found in '"  << impl->name.name()
          << "' library";
      daisy_panic (tmp.str ());
    }
  return &(*i).second (block);
}

void
Library::set_description (const char *const description)
{
  daisy_assert (!impl->description);
  impl->description = description;
}

Library*
Library::clone () const
{
  Library *const lib = new Library (impl->name.name ().c_str ());
  lib->set_description (impl->description);
  lib->impl->builders = impl->builders;
  for (Implementation::alist_map::const_iterator i = impl->alists.begin ();
       i != impl->alists.end ();
       i++)
    lib->impl->alists[(*i).first] = new AttributeList (*(*i).second);
  for (Implementation::syntax_map::const_iterator i = impl->syntaxen.begin ();
       i != impl->syntaxen.end ();
       i++)
    lib->impl->syntaxen[(*i).first] = new Syntax (*(*i).second);
  lib->impl->doc_funs = impl->doc_funs;

  return lib;
}

Library::Library (const char* name)
  : impl (new Implementation (name))
{ }

Library::~Library ()
{ }

// library.C ends here
<commit_msg>Version 4.16<commit_after>// library.C
//
// Copyright 1996-2001 Per Abrahamsen and Sren Hansen
// Copyright 2000-2001 KVL.
//
// This file is part of Daisy.
//
// Daisy is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser Public License as published by
// the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// Daisy 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 Lesser Public License for more details.
//
// You should have received a copy of the GNU Lesser Public License
// along with Daisy; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

#define BUILD_DLL

#include "library.h"
#include "block.h"
#include "alist.h"
#include "syntax.h"
#include "treelog.h"
#include <sstream>
#include "assertion.h"
#include "symbol.h"
#include "memutils.h"
#include <map>
#include <set>
#include <sstream>

struct Library::Implementation
{
  // Id.
  const symbol name;
  const char * description;

  // Types.
  typedef std::map<symbol, builder> bmap_type;
  typedef std::map<symbol, AttributeList*> alist_map;
  typedef std::map<symbol, const Syntax*> syntax_map;

  // Data (remember to update Library::clone if you change this).
  bmap_type builders;
  alist_map alists;
  syntax_map syntaxen;
  std::vector<doc_fun> doc_funs;

  // Accessors.
  AttributeList& lookup (symbol) const;
  bool check (symbol) const;
  void add_base (AttributeList&, const Syntax&);
  void add (symbol, AttributeList&, const Syntax&, builder);
  const Syntax& syntax (symbol) const;
  void entries (std::vector<symbol>&) const;
  void remove (symbol);
  void clear_parsed ();
  void refile_parsed (const std::string& from, const std::string& to);
  static void load_syntax (Syntax&, AttributeList&);
  Implementation (const char* n);
  ~Implementation ();
};

AttributeList&
Library::Implementation::lookup (const symbol key) const
{
  alist_map::const_iterator i = alists.find (key);

  if (i == alists.end ())
    daisy_panic ("Model '" + key.name ()
                 + "' not in library '" + name.name () + "'");
  return *(*i).second;
}

bool
Library::Implementation::check (const symbol key) const
{
  alist_map::const_iterator i = alists.find (key);

  if (i == alists.end ())
    return false;

  return true;
}

void
Library::Implementation::add_base (AttributeList& value,
			      const Syntax& syntax)
{
  daisy_assert (value.check ("base_model"));
  const symbol key = value.identifier ("base_model");
  alists[key] = &value;
  syntaxen[key] = &syntax;
}

void
Library::Implementation::add (const symbol key, AttributeList& value,
			      const Syntax& syntax, builder build)
{
  alists[key] = &value;
  syntaxen[key] = &syntax;
  // builders.insert (std::make_pair (key, build));
  builders[key] = build;
}

const Syntax&
Library::Implementation::syntax (const symbol key) const
{
  syntax_map::const_iterator i = syntaxen.find (key);

  if (i == syntaxen.end ())
    daisy_panic ("'" + key + "' not found");

  return *(*i).second;
}

void
Library::Implementation::entries (std::vector<symbol>& result) const
{
  for (syntax_map::const_iterator i = syntaxen.begin ();
       i != syntaxen.end ();
       i++)
    {
      result.push_back ((*i).first);
    }
}

void
Library::Implementation::remove (const symbol key)
{
  alists.erase (alists.find (key));
  syntaxen.erase (syntaxen.find (key));
}

void
Library::Implementation::clear_parsed ()
{
 retry:
  for (alist_map::iterator i = alists.begin (); i != alists.end (); i++)
    {
      AttributeList& alist = *((*i).second);
      if (alist.check ("parsed_from_file"))
	{
	  const symbol key = (*i).first;
	  syntax_map::iterator j = syntaxen.find (key);
	  daisy_assert (j != syntaxen.end ());
	  syntaxen.erase (j);
	  alists.erase (i);
	  delete &alist;
	  goto retry;
	}
    }
}

void
Library::Implementation::refile_parsed (const std::string& from, const std::string& to)
{
  daisy_assert (from != to);
  for (alist_map::iterator i = alists.begin (); i != alists.end (); i++)
    {
      AttributeList& alist = *((*i).second);
      if (alist.check ("parsed_from_file")
	  && alist.name ("parsed_from_file") == from)
	{
	  alist.add ("parsed_from_file", to);
	}
    }
}

Library::Implementation::Implementation (const char* n)
  : name (symbol (n)),
    description (NULL)
{ }

Library::Implementation::~Implementation ()
{
  // Delete alists.
  map_delete (alists.begin (), alists.end ());

  // Delete unique syntaxen.
  std::set<const Syntax*> unique;
  for (syntax_map::iterator i = syntaxen.begin ();
       i != syntaxen.end ();
       i++)
    {
      daisy_assert ((*i).second);
      unique.insert ((*i).second);
      (*i).second = NULL;
    }
  sequence_delete (unique.begin (), unique.end ());
}

void
Library::clear_parsed ()
{ impl->clear_parsed (); }

void
Library::refile_parsed (const std::string& from, const std::string& to)
{ impl->refile_parsed (from, to); }

symbol
Library::name () const
{ return impl->name; }

const char*
Library::description () const
{ return impl->description; }

AttributeList&
Library::lookup (const symbol key) const
{ return impl->lookup (key); }

bool
Library::check (const symbol key) const
{ return impl->check (key); }

bool
Library::complete (const Metalib& metalib, const symbol key) const
{
  if (!check (key))
    return false;

  if (!syntax (key).check (metalib, lookup (key), Treelog::null ()))
    return false;

  return true;
}

void
Library::add_base (AttributeList& value, const Syntax& syntax)
{ impl->add_base (value, syntax); }

void
Library::add (const symbol key, AttributeList& value, const Syntax& syntax,
              builder build)
{ impl->add (key, value, syntax, build); }

void
Library::add_derived (const symbol name, AttributeList& al,
		      const symbol super)
{
  add_derived (name, syntax (super), al, super);
}

void
Library::add_derived (const symbol name, const Syntax& syn, AttributeList& al,
		      const symbol super)
{
  al.add ("type", super);
  add (name, al, syn, impl->builders[super]);
}

const Syntax&
Library::syntax (const symbol key) const
{ return impl->syntax (key); }

void
Library::entries (std::vector<symbol>& result) const
{ impl->entries (result); }

bool
Library::is_derived_from (const symbol a, const symbol b) const
{
  if (a == b)
    return true;

  const AttributeList& al = lookup (a);

  if (!al.check ("type") && !al.check ("base_model"))
    return false;

  const symbol type = al.check ("type")
    ? al.identifier ("type")
    : al.identifier ("base_model");

  if (type == b)
    return true;

  daisy_assert (check (type));

  if (type == a)
    return false;

  return is_derived_from (type, b);
}

const symbol
Library::base_model (const symbol parameterization) const
{
  const AttributeList& al = lookup (parameterization);

  if (al.check ("type"))
    return base_model (al.identifier ("type"));
  if (al.check ("base_model")
      && al.identifier ("base_model") != parameterization)
    return  base_model (al.identifier ("base_model"));

  return parameterization;
}

bool
Library::has_interesting_description (const AttributeList& alist) const
{
  // A missing description is boring.
  if (!alist.check ("description"))
    return false;

  // The description of models are always interesting.
  if (!alist.check ("type"))
    return true;

  // If the model has no description, this one is interesting.
  const symbol type = alist.identifier ("type");
  if (!check (type))
    {
      daisy_bug (name () + " does not have " + type.name ());
      return false;
    }
  daisy_assert (check (type));
  const AttributeList& super = lookup (type);
  if (!super.check ("description"))
    return true;

  // If the model description is different, this one is interesting.
  return alist.name ("description") != super.name ("description");
}

void
Library::add_doc_fun (doc_fun fun)
{ impl->doc_funs.push_back (fun); }

std::vector<Library::doc_fun>&
Library::doc_funs () const
{ return impl->doc_funs; }

void
Library::remove (const symbol key)
{ impl->remove (key); }

Model*
Library::build_raw (const symbol type, Block& block) const
{
  const Implementation::bmap_type::const_iterator i
    = impl->builders.find (type);
  if  (i == impl->builders.end ())
    {
      std::ostringstream tmp;
      tmp << "No '" << type.name () << "' found in '"  << impl->name.name()
          << "' library";
      daisy_panic (tmp.str ());
    }
  return &(*i).second (block);
}

void
Library::set_description (const char *const description)
{
  daisy_assert (!impl->description);
  impl->description = description;
}

Library*
Library::clone () const
{
  Library *const lib = new Library (impl->name.name ().c_str ());
  lib->set_description (impl->description);
  lib->impl->builders = impl->builders;
  for (Implementation::alist_map::const_iterator i = impl->alists.begin ();
       i != impl->alists.end ();
       i++)
    lib->impl->alists[(*i).first] = new AttributeList (*(*i).second);
  for (Implementation::syntax_map::const_iterator i = impl->syntaxen.begin ();
       i != impl->syntaxen.end ();
       i++)
    lib->impl->syntaxen[(*i).first] = new Syntax (*(*i).second);
  lib->impl->doc_funs = impl->doc_funs;

  return lib;
}

Library::Library (const char* name)
  : impl (new Implementation (name))
{ }

Library::~Library ()
{ }

// library.C ends here
<|endoftext|>


<commit_before>/* For copyright information please refer to files in the COPYRIGHT directory
 */
#include "debug.hpp"
#include "locks.hpp"
#include "filesystem.hpp"
#include "utils.hpp"
#include "irods_log.hpp"
#include "initServer.hpp"
#include "irods_server_properties.hpp"

int lockMutex( mutex_type **mutex ) {
    std::string mutex_name;
    irods::error ret = getMutexName( mutex_name );
    if ( !ret.ok() ) {
        rodsLog( LOG_ERROR, "lockMutex: call to getMutexName failed" );
        return -1;
    }

    try {
        *mutex = new boost::interprocess::named_mutex( boost::interprocess::open_or_create, mutex_name.c_str() );
    }
    catch ( const boost::interprocess::interprocess_exception& ) {
        rodsLog( LOG_ERROR, "boost::interprocess::named_mutex threw a boost::interprocess::interprocess_exception." );
        return -1;
    }
    try {
        ( *mutex )->lock();
    }
    catch ( const boost::interprocess::interprocess_exception& ) {
        rodsLog( LOG_ERROR, "lock threw a boost::interprocess::interprocess_exception." );
        return -1;
    }
    return 0;
}

void unlockMutex( mutex_type **mutex ) {
    ( *mutex )->unlock();
    delete *mutex;
}

/* This function can be used during initialization to remove a previously held mutex that has not been released.
 * This should only be used when there is no other process using the mutex */
void resetMutex() {
    std::string mutex_name;
    irods::error ret = getMutexName( mutex_name );
    if ( !ret.ok() ) {
        rodsLog( LOG_ERROR, "resetMutex: call to getMutexName failed" );
    }

    boost::interprocess::named_mutex::remove( mutex_name.c_str() );
}

irods::error getMutexName( std::string &mutex_name ) {
    std::string mutex_name_salt;
    irods::error ret = irods::server_properties::getInstance().get_property<std::string>( RE_CACHE_SALT_KW, mutex_name_salt );
    if ( !ret.ok() ) {
        rodsLog( LOG_ERROR, "getMutexName: failed to retrieve re cache salt from server_properties\n%s", ret.result().c_str() );
        return PASS( ret );
    }

    getResourceName( mutex_name, mutex_name_salt.c_str() );
    mutex_name = "re_cache_mutex_" + mutex_name;

    return SUCCESS();
}
<commit_msg>[#2212] CID26297:<commit_after>/* For copyright information please refer to files in the COPYRIGHT directory
 */
#include "debug.hpp"
#include "locks.hpp"
#include "filesystem.hpp"
#include "utils.hpp"
#include "irods_log.hpp"
#include "initServer.hpp"
#include "irods_server_properties.hpp"

int lockMutex( mutex_type **mutex ) {
    std::string mutex_name;
    irods::error ret = getMutexName( mutex_name );
    if ( !ret.ok() ) {
        rodsLog( LOG_ERROR, "lockMutex: call to getMutexName failed" );
        return -1;
    }

    try {
        *mutex = new boost::interprocess::named_mutex( boost::interprocess::open_or_create, mutex_name.c_str() );
    }
    catch ( const boost::interprocess::interprocess_exception& ) {
        rodsLog( LOG_ERROR, "boost::interprocess::named_mutex threw a boost::interprocess::interprocess_exception." );
        return -1;
    }
    try {
        ( *mutex )->lock();
    }
    catch ( const boost::interprocess::interprocess_exception& ) {
        rodsLog( LOG_ERROR, "lock threw a boost::interprocess::interprocess_exception." );
        return -1;
    }
    return 0;
}

void unlockMutex( mutex_type **mutex ) {
    try {
        ( *mutex )->unlock();
    }
    catch ( const boost::interprocess::interprocess_exception& ) {
        rodsLog( LOG_ERROR, "unlock threw a boost::interprocess::interprocess_exception." );
    }
    delete *mutex;
}

/* This function can be used during initialization to remove a previously held mutex that has not been released.
 * This should only be used when there is no other process using the mutex */
void resetMutex() {
    std::string mutex_name;
    irods::error ret = getMutexName( mutex_name );
    if ( !ret.ok() ) {
        rodsLog( LOG_ERROR, "resetMutex: call to getMutexName failed" );
    }

    boost::interprocess::named_mutex::remove( mutex_name.c_str() );
}

irods::error getMutexName( std::string &mutex_name ) {
    std::string mutex_name_salt;
    irods::error ret = irods::server_properties::getInstance().get_property<std::string>( RE_CACHE_SALT_KW, mutex_name_salt );
    if ( !ret.ok() ) {
        rodsLog( LOG_ERROR, "getMutexName: failed to retrieve re cache salt from server_properties\n%s", ret.result().c_str() );
        return PASS( ret );
    }

    getResourceName( mutex_name, mutex_name_salt.c_str() );
    mutex_name = "re_cache_mutex_" + mutex_name;

    return SUCCESS();
}
<|endoftext|>


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

#include "asylo/platform/core/trusted_application.h"

#include <stdio.h>
#include <stdlib.h>
#include <sys/ucontext.h>
#include <unistd.h>
#include <cerrno>
#include <string>

#include "absl/memory/memory.h"
#include "absl/strings/str_cat.h"
#include "absl/synchronization/mutex.h"
#include "asylo/util/logging.h"
#include "asylo/identity/init.h"
#include "asylo/platform/arch/include/trusted/host_calls.h"
#include "asylo/platform/arch/include/trusted/time.h"
#include "asylo/platform/common/bridge_types.h"
#include "asylo/platform/core/shared_name_kind.h"
#include "asylo/platform/core/trusted_global_state.h"
#include "asylo/platform/posix/io/io_manager.h"
#include "asylo/platform/posix/io/native_paths.h"
#include "asylo/platform/posix/io/random_devices.h"
#include "asylo/platform/posix/signal/signal_manager.h"
#include "asylo/platform/posix/threading/thread_manager.h"
#include "asylo/util/posix_error_space.h"
#include "asylo/util/status.h"

using EnclaveState = ::asylo::TrustedApplication::State;
using google::protobuf::RepeatedPtrField;

namespace asylo {
namespace {

void LogError(const Status &status) {
  EnclaveState state = GetApplicationInstance()->GetState();
  if (state < EnclaveState::kUserInitializing) {
    // LOG() is unavailable here because the I/O subsystem has not yet been
    // initialized.
    enc_untrusted_puts(status.ToString().c_str());
  } else {
    LOG(ERROR) << status;
  }
}

// StatusSerializer can be used to serialize a given proto2 message to an
// untrusted buffer.
//
// OutputProto must be a proto2 message type.
template <class OutputProto>
class StatusSerializer {
 public:
  // Creates a new StatusSerializer that saves Status objects to |status_proto|,
  // which is a nested message within |output_proto|. StatusSerializer does not
  // take ownership of any of the input pointers. Input pointers must remain
  // valid for the lifetime of the StatusSerializer.
  StatusSerializer(const OutputProto *output_proto, StatusProto *status_proto,
                   char **output, size_t *output_len)
      : output_proto_{output_proto},
        status_proto_{status_proto},
        output_{output},
        output_len_{output_len} {}

  // Creates a new StatusSerializer that saves Status objects to |status_proto|.
  // StatusSerializer does not take ownership of any of the input pointers.
  // Input pointers must remain valid for the lifetime of the StatusSerializer.
  StatusSerializer(char **output, size_t *output_len)
      : output_proto_{&proto},
        status_proto_{&proto},
        output_{output},
        output_len_{output_len} {}

  // Saves the given |status| into the StatusSerializer's status_proto_. Then
  // serializes its output_proto_ into a buffer. On success 0 is returned, else
  // 1 is returned and the StatusSerializer logs the error.
  int Serialize(const Status &status) {
    status.SaveTo(status_proto_);

    // Serialize to a trusted buffer instead of an untrusted buffer because the
    // serialization routine may rely on read backs for correctness.
    *output_len_ = output_proto_->ByteSize();
    std::unique_ptr<char[]> trusted_output(new char[*output_len_]);
    if (!output_proto_->SerializeToArray(trusted_output.get(), *output_len_)) {
      *output_ = nullptr;
      *output_len_ = 0;
      LogError(status);
      return 1;
    }
    *output_ = reinterpret_cast<char *>(enc_untrusted_malloc(*output_len_));
    memcpy(*output_, trusted_output.get(), *output_len_);
    return 0;
  }

 private:
  OutputProto proto;
  const OutputProto *output_proto_;
  StatusProto *status_proto_;
  char **output_;
  size_t *output_len_;
};

}  // namespace

Status TrustedApplication::VerifyAndSetState(const EnclaveState &expected_state,
                                             const EnclaveState &new_state) {
  absl::MutexLock lock(&mutex_);
  if (enclave_state_ != expected_state) {
    return Status(error::GoogleError::FAILED_PRECONDITION,
                  ::absl::StrCat("Enclave is in state: ", enclave_state_,
                                 " expected state: ", expected_state));
  }
  enclave_state_ = new_state;
  return Status::OkStatus();
}

EnclaveState TrustedApplication::GetState() {
  absl::MutexLock lock(&mutex_);
  return enclave_state_;
}

void TrustedApplication::SetState(const EnclaveState &state) {
  absl::MutexLock lock(&mutex_);
  enclave_state_ = state;
}

Status VerifyOutputArguments(char **output, size_t *output_len) {
  if (!output || !output_len) {
    Status status =
        Status(error::GoogleError::INVALID_ARGUMENT,
               "Invalid input parameter passed to __asylo_user...()");
    LogError(status);
    return status;
  }
  return Status::OkStatus();
}

// Application instance returned by BuildTrustedApplication.
static TrustedApplication *global_trusted_application = nullptr;

// A mutex that avoids race condition when getting |global_trusted_application|.
static absl::Mutex get_application_lock;

// Initialize IO subsystem.
static void InitializeIO(const EnclaveConfig &config);

TrustedApplication *GetApplicationInstance() {
  absl::MutexLock lock(&get_application_lock);
  if (!global_trusted_application) {
    global_trusted_application = BuildTrustedApplication();
  }
  return global_trusted_application;
}

Status InitializeEnvironmentVariables(
    const RepeatedPtrField<EnvironmentVariable> &variables) {
  for (const auto &variable : variables) {
    if (!variable.has_name() || !variable.has_value()) {
      return Status(error::GoogleError::INVALID_ARGUMENT,
                    "Environment variables should set both name and value "
                    "fields");
    }
    setenv(variable.name().c_str(), variable.value().c_str(), /*overwrite=*/0);
  }
  return Status::OkStatus();
}

Status TrustedApplication::InitializeInternal(const EnclaveConfig &config) {
  InitializeIO(config);
  Status status =
      InitializeEnvironmentVariables(config.environment_variables());
  const char *log_directory = config.logging_config().log_directory().c_str();
  int vlog_level = config.logging_config().vlog_level();
  if(!InitLogging(log_directory, GetEnclaveName().c_str(), vlog_level)) {
    fprintf(stderr, "Initialization of enclave logging failed\n");
  }
  if (!status.ok()) {
    LOG(WARNING) << "Initialization of enclave environment variables failed: "
                 << status;
  }
  SetEnclaveConfig(config);
  // This call can fail, but it should not stop the enclave from running.
  status = InitializeEnclaveAssertionAuthorities(
      config.enclave_assertion_authority_configs().begin(),
      config.enclave_assertion_authority_configs().end());
  if (!status.ok()) {
    LOG(WARNING) << "Initialization of enclave assertion authorities failed: "
                 << status;
  }

  status = VerifyAndSetState(EnclaveState::kInternalInitializing,
                             EnclaveState::kUserInitializing);
  if (!status.ok()) {
    return status;
  }

  return Initialize(config);
}

void InitializeIO(const EnclaveConfig &config) {
  auto &io_manager = io::IOManager::GetInstance();

  // Register host file descriptors as stdin, stdout, and stderr. The order of
  // initialization is significant since we need to match the convention that
  // these refer to descriptors 0, 1, and 2 respectively.
  if (config.stdin_fd() >= 0) {
    io_manager.RegisterHostFileDescriptor(config.stdin_fd());
  }
  if (config.stdout_fd() >= 0) {
    io_manager.RegisterHostFileDescriptor(config.stdout_fd());
  }
  if (config.stderr_fd() >= 0) {
    io_manager.RegisterHostFileDescriptor(config.stderr_fd());
  }

  // Register handler for / so paths without other handlers are forwarded on to
  // the host system. Paths are registered without the trailing slash, so an
  // empty string is used.
  io_manager.RegisterVirtualPathHandler(
      "", ::absl::make_unique<io::NativePathHandler>());

  // Register handlers for /dev/random and /dev/urandom so they can be opened
  // and read like regular files without exiting the enclave.
  io_manager.RegisterVirtualPathHandler(
      RandomPathHandler::kRandomPath, ::absl::make_unique<RandomPathHandler>());
  io_manager.RegisterVirtualPathHandler(
      RandomPathHandler::kURandomPath,
      ::absl::make_unique<RandomPathHandler>());

  // Set the current working directory so that relative paths can be handled.
  io_manager.SetCurrentWorkingDirectory(config.current_working_directory());
}

// Asylo enclave entry points.
//
// See asylo/platform/arch/include/trusted/entry_points.h for detailed
// documentation for each function.
extern "C" {

int __asylo_user_init(const char *name, const char *config, size_t config_len,
                      char **output, size_t *output_len) {
  Status status = VerifyOutputArguments(output, output_len);
  if (!status.ok()) {
    return 1;
  }

  StatusSerializer<StatusProto> status_serializer(output, output_len);

  EnclaveConfig enclave_config;
  if (!enclave_config.ParseFromArray(config, config_len)) {
    status = Status(error::GoogleError::INVALID_ARGUMENT,
                    "Failed to parse EnclaveConfig");
    return status_serializer.Serialize(status);
  }

  TrustedApplication *trusted_application = GetApplicationInstance();
  status = trusted_application->VerifyAndSetState(
      EnclaveState::kUninitialized, EnclaveState::kInternalInitializing);
  if (!status.ok()) {
    return status_serializer.Serialize(status);
  }

  SetEnclaveName(name);
  // Invoke the enclave entry-point.
  status = trusted_application->InitializeInternal(enclave_config);
  if (!status.ok()) {
    trusted_application->SetState(EnclaveState::kUninitialized);
    return status_serializer.Serialize(status);
  }

  trusted_application->SetState(EnclaveState::kRunning);
  return status_serializer.Serialize(status);
}

int __asylo_user_run(const char *input, size_t input_len, char **output,
                     size_t *output_len) {
  Status status = VerifyOutputArguments(output, output_len);
  if (!status.ok()) {
    return 1;
  }

  EnclaveOutput enclave_output;
  StatusSerializer<EnclaveOutput> status_serializer(
      &enclave_output, enclave_output.mutable_status(), output, output_len);

  EnclaveInput enclave_input;
  if (!enclave_input.ParseFromArray(input, input_len)) {
    status = Status(error::GoogleError::INVALID_ARGUMENT,
                    "Failed to parse EnclaveInput");
    return status_serializer.Serialize(status);
  }

  TrustedApplication *trusted_application = GetApplicationInstance();
  if (trusted_application->GetState() != EnclaveState::kRunning) {
    status = Status(error::GoogleError::FAILED_PRECONDITION,
                    "Enclave not in state RUNNING");
    return status_serializer.Serialize(status);
  }

  // Invoke the enclave entry-point.
  status = trusted_application->Run(enclave_input, &enclave_output);
  return status_serializer.Serialize(status);
}

int __asylo_user_fini(const char *input, size_t input_len, char **output,
                      size_t *output_len) {
  Status status = VerifyOutputArguments(output, output_len);
  if (!status.ok()) {
    return 1;
  }

  StatusSerializer<StatusProto> status_serializer(output, output_len);

  asylo::EnclaveFinal enclave_final;
  if (!enclave_final.ParseFromArray(input, input_len)) {
    status = Status(error::GoogleError::INVALID_ARGUMENT,
                    "Failed to parse EnclaveFinal");
  }

  TrustedApplication *trusted_application = GetApplicationInstance();
  status = trusted_application->VerifyAndSetState(EnclaveState::kRunning,
                                                  EnclaveState::kFinalizing);
  if (!status.ok()) {
    return status_serializer.Serialize(status);
  }

  // Invoke the enclave entry-point.
  status = trusted_application->Finalize(enclave_final);
  if (!status.ok()) {
    trusted_application->SetState(EnclaveState::kRunning);
    return status_serializer.Serialize(status);
  }

  trusted_application->SetState(EnclaveState::kFinalized);
  return status_serializer.Serialize(status);
}

int __asylo_threading_donate() {
  TrustedApplication *trusted_application = GetApplicationInstance();
  EnclaveState current_state = trusted_application->GetState();
  if (current_state < EnclaveState::kUserInitializing ||
      current_state > EnclaveState::kFinalizing) {
    Status status = Status(error::GoogleError::FAILED_PRECONDITION,
                           "Enclave ThreadManager has not been initialized");
    LOG(ERROR) << status;
    return EPERM;
  }

  ThreadManager *thread_manager = ThreadManager::GetInstance();
  return thread_manager->StartThread();
}

int __asylo_handle_signal(const char *input, size_t input_len) {
  asylo::EnclaveSignal signal;
  if (!signal.ParseFromArray(input, input_len)) {
    return -1;
  }
  TrustedApplication *trusted_application = GetApplicationInstance();
  EnclaveState current_state = trusted_application->GetState();
  if (current_state < EnclaveState::kRunning ||
      current_state > EnclaveState::kFinalizing) {
    enc_untrusted_puts("Enclave signal handling internals not available");
    return EPERM;
  }
  int signum = FromBridgeSignal(signal.signum());
  if (signum < 0) {
    return -1;
  }
  siginfo_t info;
  info.si_signo = signum;
  info.si_code = signal.code();
  ucontext_t ucontext;
  for (int greg_index = 0;
       greg_index < NGREG && greg_index < signal.gregs_size(); ++greg_index) {
    ucontext.uc_mcontext.gregs[greg_index] =
        static_cast<greg_t>(signal.gregs(greg_index));
  }
  SignalManager *signal_manager = SignalManager::GetInstance();
  const sigset_t mask = signal_manager->GetSignalMask();

  // If the signal is blocked and still passed into the enclave. The signal
  // masks inside the enclave is out of sync with the untrusted signal mask.
  if (sigismember(&mask, signum)) {
    return EPERM;
  }
  if (!signal_manager->HandleSignal(signum, &info, &ucontext).ok()) {
    return -1;
  }
  return 0;
}

}  // extern "C"

}  // namespace asylo
<commit_msg>Fix a bug in error propagation from Finalize<commit_after>/*
 *
 * Copyright 2017 Asylo authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include "asylo/platform/core/trusted_application.h"

#include <stdio.h>
#include <stdlib.h>
#include <sys/ucontext.h>
#include <unistd.h>
#include <cerrno>
#include <string>

#include "absl/memory/memory.h"
#include "absl/strings/str_cat.h"
#include "absl/synchronization/mutex.h"
#include "asylo/util/logging.h"
#include "asylo/identity/init.h"
#include "asylo/platform/arch/include/trusted/host_calls.h"
#include "asylo/platform/arch/include/trusted/time.h"
#include "asylo/platform/common/bridge_types.h"
#include "asylo/platform/core/shared_name_kind.h"
#include "asylo/platform/core/trusted_global_state.h"
#include "asylo/platform/posix/io/io_manager.h"
#include "asylo/platform/posix/io/native_paths.h"
#include "asylo/platform/posix/io/random_devices.h"
#include "asylo/platform/posix/signal/signal_manager.h"
#include "asylo/platform/posix/threading/thread_manager.h"
#include "asylo/util/posix_error_space.h"
#include "asylo/util/status.h"

using EnclaveState = ::asylo::TrustedApplication::State;
using google::protobuf::RepeatedPtrField;

namespace asylo {
namespace {

void LogError(const Status &status) {
  EnclaveState state = GetApplicationInstance()->GetState();
  if (state < EnclaveState::kUserInitializing) {
    // LOG() is unavailable here because the I/O subsystem has not yet been
    // initialized.
    enc_untrusted_puts(status.ToString().c_str());
  } else {
    LOG(ERROR) << status;
  }
}

// StatusSerializer can be used to serialize a given proto2 message to an
// untrusted buffer.
//
// OutputProto must be a proto2 message type.
template <class OutputProto>
class StatusSerializer {
 public:
  // Creates a new StatusSerializer that saves Status objects to |status_proto|,
  // which is a nested message within |output_proto|. StatusSerializer does not
  // take ownership of any of the input pointers. Input pointers must remain
  // valid for the lifetime of the StatusSerializer.
  StatusSerializer(const OutputProto *output_proto, StatusProto *status_proto,
                   char **output, size_t *output_len)
      : output_proto_{output_proto},
        status_proto_{status_proto},
        output_{output},
        output_len_{output_len} {}

  // Creates a new StatusSerializer that saves Status objects to |status_proto|.
  // StatusSerializer does not take ownership of any of the input pointers.
  // Input pointers must remain valid for the lifetime of the StatusSerializer.
  StatusSerializer(char **output, size_t *output_len)
      : output_proto_{&proto},
        status_proto_{&proto},
        output_{output},
        output_len_{output_len} {}

  // Saves the given |status| into the StatusSerializer's status_proto_. Then
  // serializes its output_proto_ into a buffer. On success 0 is returned, else
  // 1 is returned and the StatusSerializer logs the error.
  int Serialize(const Status &status) {
    status.SaveTo(status_proto_);

    // Serialize to a trusted buffer instead of an untrusted buffer because the
    // serialization routine may rely on read backs for correctness.
    *output_len_ = output_proto_->ByteSize();
    std::unique_ptr<char[]> trusted_output(new char[*output_len_]);
    if (!output_proto_->SerializeToArray(trusted_output.get(), *output_len_)) {
      *output_ = nullptr;
      *output_len_ = 0;
      LogError(status);
      return 1;
    }
    *output_ = reinterpret_cast<char *>(enc_untrusted_malloc(*output_len_));
    memcpy(*output_, trusted_output.get(), *output_len_);
    return 0;
  }

 private:
  OutputProto proto;
  const OutputProto *output_proto_;
  StatusProto *status_proto_;
  char **output_;
  size_t *output_len_;
};

}  // namespace

Status TrustedApplication::VerifyAndSetState(const EnclaveState &expected_state,
                                             const EnclaveState &new_state) {
  absl::MutexLock lock(&mutex_);
  if (enclave_state_ != expected_state) {
    return Status(error::GoogleError::FAILED_PRECONDITION,
                  ::absl::StrCat("Enclave is in state: ", enclave_state_,
                                 " expected state: ", expected_state));
  }
  enclave_state_ = new_state;
  return Status::OkStatus();
}

EnclaveState TrustedApplication::GetState() {
  absl::MutexLock lock(&mutex_);
  return enclave_state_;
}

void TrustedApplication::SetState(const EnclaveState &state) {
  absl::MutexLock lock(&mutex_);
  enclave_state_ = state;
}

Status VerifyOutputArguments(char **output, size_t *output_len) {
  if (!output || !output_len) {
    Status status =
        Status(error::GoogleError::INVALID_ARGUMENT,
               "Invalid input parameter passed to __asylo_user...()");
    LogError(status);
    return status;
  }
  return Status::OkStatus();
}

// Application instance returned by BuildTrustedApplication.
static TrustedApplication *global_trusted_application = nullptr;

// A mutex that avoids race condition when getting |global_trusted_application|.
static absl::Mutex get_application_lock;

// Initialize IO subsystem.
static void InitializeIO(const EnclaveConfig &config);

TrustedApplication *GetApplicationInstance() {
  absl::MutexLock lock(&get_application_lock);
  if (!global_trusted_application) {
    global_trusted_application = BuildTrustedApplication();
  }
  return global_trusted_application;
}

Status InitializeEnvironmentVariables(
    const RepeatedPtrField<EnvironmentVariable> &variables) {
  for (const auto &variable : variables) {
    if (!variable.has_name() || !variable.has_value()) {
      return Status(error::GoogleError::INVALID_ARGUMENT,
                    "Environment variables should set both name and value "
                    "fields");
    }
    setenv(variable.name().c_str(), variable.value().c_str(), /*overwrite=*/0);
  }
  return Status::OkStatus();
}

Status TrustedApplication::InitializeInternal(const EnclaveConfig &config) {
  InitializeIO(config);
  Status status =
      InitializeEnvironmentVariables(config.environment_variables());
  const char *log_directory = config.logging_config().log_directory().c_str();
  int vlog_level = config.logging_config().vlog_level();
  if(!InitLogging(log_directory, GetEnclaveName().c_str(), vlog_level)) {
    fprintf(stderr, "Initialization of enclave logging failed\n");
  }
  if (!status.ok()) {
    LOG(WARNING) << "Initialization of enclave environment variables failed: "
                 << status;
  }
  SetEnclaveConfig(config);
  // This call can fail, but it should not stop the enclave from running.
  status = InitializeEnclaveAssertionAuthorities(
      config.enclave_assertion_authority_configs().begin(),
      config.enclave_assertion_authority_configs().end());
  if (!status.ok()) {
    LOG(WARNING) << "Initialization of enclave assertion authorities failed: "
                 << status;
  }

  status = VerifyAndSetState(EnclaveState::kInternalInitializing,
                             EnclaveState::kUserInitializing);
  if (!status.ok()) {
    return status;
  }

  return Initialize(config);
}

void InitializeIO(const EnclaveConfig &config) {
  auto &io_manager = io::IOManager::GetInstance();

  // Register host file descriptors as stdin, stdout, and stderr. The order of
  // initialization is significant since we need to match the convention that
  // these refer to descriptors 0, 1, and 2 respectively.
  if (config.stdin_fd() >= 0) {
    io_manager.RegisterHostFileDescriptor(config.stdin_fd());
  }
  if (config.stdout_fd() >= 0) {
    io_manager.RegisterHostFileDescriptor(config.stdout_fd());
  }
  if (config.stderr_fd() >= 0) {
    io_manager.RegisterHostFileDescriptor(config.stderr_fd());
  }

  // Register handler for / so paths without other handlers are forwarded on to
  // the host system. Paths are registered without the trailing slash, so an
  // empty string is used.
  io_manager.RegisterVirtualPathHandler(
      "", ::absl::make_unique<io::NativePathHandler>());

  // Register handlers for /dev/random and /dev/urandom so they can be opened
  // and read like regular files without exiting the enclave.
  io_manager.RegisterVirtualPathHandler(
      RandomPathHandler::kRandomPath, ::absl::make_unique<RandomPathHandler>());
  io_manager.RegisterVirtualPathHandler(
      RandomPathHandler::kURandomPath,
      ::absl::make_unique<RandomPathHandler>());

  // Set the current working directory so that relative paths can be handled.
  io_manager.SetCurrentWorkingDirectory(config.current_working_directory());
}

// Asylo enclave entry points.
//
// See asylo/platform/arch/include/trusted/entry_points.h for detailed
// documentation for each function.
extern "C" {

int __asylo_user_init(const char *name, const char *config, size_t config_len,
                      char **output, size_t *output_len) {
  Status status = VerifyOutputArguments(output, output_len);
  if (!status.ok()) {
    return 1;
  }

  StatusSerializer<StatusProto> status_serializer(output, output_len);

  EnclaveConfig enclave_config;
  if (!enclave_config.ParseFromArray(config, config_len)) {
    status = Status(error::GoogleError::INVALID_ARGUMENT,
                    "Failed to parse EnclaveConfig");
    return status_serializer.Serialize(status);
  }

  TrustedApplication *trusted_application = GetApplicationInstance();
  status = trusted_application->VerifyAndSetState(
      EnclaveState::kUninitialized, EnclaveState::kInternalInitializing);
  if (!status.ok()) {
    return status_serializer.Serialize(status);
  }

  SetEnclaveName(name);
  // Invoke the enclave entry-point.
  status = trusted_application->InitializeInternal(enclave_config);
  if (!status.ok()) {
    trusted_application->SetState(EnclaveState::kUninitialized);
    return status_serializer.Serialize(status);
  }

  trusted_application->SetState(EnclaveState::kRunning);
  return status_serializer.Serialize(status);
}

int __asylo_user_run(const char *input, size_t input_len, char **output,
                     size_t *output_len) {
  Status status = VerifyOutputArguments(output, output_len);
  if (!status.ok()) {
    return 1;
  }

  EnclaveOutput enclave_output;
  StatusSerializer<EnclaveOutput> status_serializer(
      &enclave_output, enclave_output.mutable_status(), output, output_len);

  EnclaveInput enclave_input;
  if (!enclave_input.ParseFromArray(input, input_len)) {
    status = Status(error::GoogleError::INVALID_ARGUMENT,
                    "Failed to parse EnclaveInput");
    return status_serializer.Serialize(status);
  }

  TrustedApplication *trusted_application = GetApplicationInstance();
  if (trusted_application->GetState() != EnclaveState::kRunning) {
    status = Status(error::GoogleError::FAILED_PRECONDITION,
                    "Enclave not in state RUNNING");
    return status_serializer.Serialize(status);
  }

  // Invoke the enclave entry-point.
  status = trusted_application->Run(enclave_input, &enclave_output);
  return status_serializer.Serialize(status);
}

int __asylo_user_fini(const char *input, size_t input_len, char **output,
                      size_t *output_len) {
  Status status = VerifyOutputArguments(output, output_len);
  if (!status.ok()) {
    return 1;
  }

  StatusSerializer<StatusProto> status_serializer(output, output_len);

  asylo::EnclaveFinal enclave_final;
  if (!enclave_final.ParseFromArray(input, input_len)) {
    status = Status(error::GoogleError::INVALID_ARGUMENT,
                    "Failed to parse EnclaveFinal");
    return status_serializer.Serialize(status);
  }

  TrustedApplication *trusted_application = GetApplicationInstance();
  status = trusted_application->VerifyAndSetState(EnclaveState::kRunning,
                                                  EnclaveState::kFinalizing);
  if (!status.ok()) {
    return status_serializer.Serialize(status);
  }

  // Invoke the enclave entry-point.
  status = trusted_application->Finalize(enclave_final);
  if (!status.ok()) {
    trusted_application->SetState(EnclaveState::kRunning);
    return status_serializer.Serialize(status);
  }

  trusted_application->SetState(EnclaveState::kFinalized);
  return status_serializer.Serialize(status);
}

int __asylo_threading_donate() {
  TrustedApplication *trusted_application = GetApplicationInstance();
  EnclaveState current_state = trusted_application->GetState();
  if (current_state < EnclaveState::kUserInitializing ||
      current_state > EnclaveState::kFinalizing) {
    Status status = Status(error::GoogleError::FAILED_PRECONDITION,
                           "Enclave ThreadManager has not been initialized");
    LOG(ERROR) << status;
    return EPERM;
  }

  ThreadManager *thread_manager = ThreadManager::GetInstance();
  return thread_manager->StartThread();
}

int __asylo_handle_signal(const char *input, size_t input_len) {
  asylo::EnclaveSignal signal;
  if (!signal.ParseFromArray(input, input_len)) {
    return -1;
  }
  TrustedApplication *trusted_application = GetApplicationInstance();
  EnclaveState current_state = trusted_application->GetState();
  if (current_state < EnclaveState::kRunning ||
      current_state > EnclaveState::kFinalizing) {
    enc_untrusted_puts("Enclave signal handling internals not available");
    return EPERM;
  }
  int signum = FromBridgeSignal(signal.signum());
  if (signum < 0) {
    return -1;
  }
  siginfo_t info;
  info.si_signo = signum;
  info.si_code = signal.code();
  ucontext_t ucontext;
  for (int greg_index = 0;
       greg_index < NGREG && greg_index < signal.gregs_size(); ++greg_index) {
    ucontext.uc_mcontext.gregs[greg_index] =
        static_cast<greg_t>(signal.gregs(greg_index));
  }
  SignalManager *signal_manager = SignalManager::GetInstance();
  const sigset_t mask = signal_manager->GetSignalMask();

  // If the signal is blocked and still passed into the enclave. The signal
  // masks inside the enclave is out of sync with the untrusted signal mask.
  if (sigismember(&mask, signum)) {
    return EPERM;
  }
  if (!signal_manager->HandleSignal(signum, &info, &ucontext).ok()) {
    return -1;
  }
  return 0;
}

}  // extern "C"

}  // namespace asylo
<|endoftext|>


<commit_before>#include <node.h>
#include <nan.h>
#include <secp256k1.h>
#include <lax_der_privatekey_parsing.h>

#include "messages.h"
#include "util.h"

extern secp256k1_context* secp256k1ctx;

NAN_METHOD(secretKeyVerify) {
  Nan::HandleScope scope;

  v8::Local<v8::Object> seckey_buffer = info[0].As<v8::Object>();
  CHECK_TYPE_BUFFER(seckey_buffer, EC_PRIVKEY_TYPE_INVALID);
  const unsigned char* seckey = (const unsigned char*) node::Buffer::Data(seckey_buffer);

  if (node::Buffer::Length(seckey_buffer) != 32) {
    return info.GetReturnValue().Set(Nan::New<v8::Boolean>(false));
  }

  int result = secp256k1_ec_seckey_verify(secp256k1ctx, seckey);

  info.GetReturnValue().Set(Nan::New<v8::Boolean>(result));
}

NAN_METHOD(secretKeyExport) {
  Nan::HandleScope scope;

  v8::Local<v8::Object> seckey_buffer = info[0].As<v8::Object>();
  CHECK_TYPE_BUFFER(seckey_buffer, EC_PRIVKEY_TYPE_INVALID);
  CHECK_BUFFER_LENGTH(seckey_buffer, 32, EC_PRIVKEY_LENGTH_INVALID);
  const unsigned char* seckey = (const unsigned char*) node::Buffer::Data(seckey_buffer);

  int compressed = 1;
  v8::Local<v8::Value> compressed_value = info[1];
  if (!compressed_value->IsUndefined()) {
    CHECK_TYPE_BOOLEAN(compressed_value, COMPRESSED_TYPE_INVALID);
    if (!compressed_value->BooleanValue()) {
      compressed = 0;
    }
  }

  unsigned char privkey[279];
  size_t privkeylen;
  if (ec_privkey_export_der(secp256k1ctx, &privkey[0], &privkeylen, seckey, compressed) == 0) {
    return Nan::ThrowError(EC_PRIVKEY_EXPORT_DER_FAIL);
  }

  info.GetReturnValue().Set(COPY_BUFFER(privkey, privkeylen));
}

NAN_METHOD(secretKeyImport) {
  Nan::HandleScope scope;

  v8::Local<v8::Object> privkey_buffer = info[0].As<v8::Object>();
  CHECK_TYPE_BUFFER(privkey_buffer, EC_PRIVKEY_TYPE_INVALID);
  CHECK_BUFFER_LENGTH_GT_ZERO(privkey_buffer, EC_PRIVKEY_LENGTH_INVALID);
  const unsigned char* privkey = (const unsigned char*) node::Buffer::Data(privkey_buffer);
  size_t privkeylen = node::Buffer::Length(privkey_buffer);

  unsigned char seckey[32];
  if (ec_privkey_import_der(secp256k1ctx, &seckey[0], privkey, privkeylen) == 0) {
    return Nan::ThrowError(EC_PRIVKEY_IMPORT_DER_FAIL);
  }

  info.GetReturnValue().Set(COPY_BUFFER(seckey, 32));
}

NAN_METHOD(secretKeyTweakAdd) {
  Nan::HandleScope scope;

  v8::Local<v8::Object> seckey_buffer = info[0].As<v8::Object>();
  CHECK_TYPE_BUFFER(seckey_buffer, EC_PRIVKEY_TYPE_INVALID);
  CHECK_BUFFER_LENGTH(seckey_buffer, 32, EC_PRIVKEY_LENGTH_INVALID);
  unsigned char* seckey = (unsigned char *) node::Buffer::Data(seckey_buffer);

  v8::Local<v8::Object> tweak_buffer = info[1].As<v8::Object>();
  CHECK_TYPE_BUFFER(tweak_buffer, TWEAK_TYPE_INVALID);
  CHECK_BUFFER_LENGTH(tweak_buffer, 32, TWEAK_LENGTH_INVALID);
  const unsigned char* tweak = (unsigned char *) node::Buffer::Data(tweak_buffer);

  if (secp256k1_ec_privkey_tweak_add(secp256k1ctx, seckey, tweak) == 0) {
    return Nan::ThrowError(EC_PRIVKEY_TWEAK_ADD_FAIL);
  }

  info.GetReturnValue().Set(COPY_BUFFER(seckey, 32));
}

NAN_METHOD(secretKeyTweakMul) {
  Nan::HandleScope scope;

  v8::Local<v8::Object> seckey_buffer = info[0].As<v8::Object>();
  CHECK_TYPE_BUFFER(seckey_buffer, EC_PRIVKEY_TYPE_INVALID);
  CHECK_BUFFER_LENGTH(seckey_buffer, 32, EC_PRIVKEY_LENGTH_INVALID);
  unsigned char* seckey = (unsigned char *) node::Buffer::Data(seckey_buffer);

  v8::Local<v8::Object> tweak_buffer = info[1].As<v8::Object>();
  CHECK_TYPE_BUFFER(tweak_buffer, TWEAK_TYPE_INVALID);
  CHECK_BUFFER_LENGTH(tweak_buffer, 32, TWEAK_LENGTH_INVALID);
  const unsigned char* tweak = (unsigned char *) node::Buffer::Data(tweak_buffer);

  if (secp256k1_ec_privkey_tweak_mul(secp256k1ctx, seckey, tweak) == 0) {
    return Nan::ThrowError(EC_PRIVKEY_TWEAK_MUL_FAIL);
  }

  info.GetReturnValue().Set(COPY_BUFFER(seckey, 32));
}
<commit_msg>Fix bug with rewriting secret key<commit_after>#include <node.h>
#include <nan.h>
#include <secp256k1.h>
#include <lax_der_privatekey_parsing.h>

#include "messages.h"
#include "util.h"

extern secp256k1_context* secp256k1ctx;

NAN_METHOD(secretKeyVerify) {
  Nan::HandleScope scope;

  v8::Local<v8::Object> seckey_buffer = info[0].As<v8::Object>();
  CHECK_TYPE_BUFFER(seckey_buffer, EC_PRIVKEY_TYPE_INVALID);
  const unsigned char* seckey = (const unsigned char*) node::Buffer::Data(seckey_buffer);

  if (node::Buffer::Length(seckey_buffer) != 32) {
    return info.GetReturnValue().Set(Nan::New<v8::Boolean>(false));
  }

  int result = secp256k1_ec_seckey_verify(secp256k1ctx, seckey);

  info.GetReturnValue().Set(Nan::New<v8::Boolean>(result));
}

NAN_METHOD(secretKeyExport) {
  Nan::HandleScope scope;

  v8::Local<v8::Object> seckey_buffer = info[0].As<v8::Object>();
  CHECK_TYPE_BUFFER(seckey_buffer, EC_PRIVKEY_TYPE_INVALID);
  CHECK_BUFFER_LENGTH(seckey_buffer, 32, EC_PRIVKEY_LENGTH_INVALID);
  const unsigned char* seckey = (const unsigned char*) node::Buffer::Data(seckey_buffer);

  int compressed = 1;
  v8::Local<v8::Value> compressed_value = info[1];
  if (!compressed_value->IsUndefined()) {
    CHECK_TYPE_BOOLEAN(compressed_value, COMPRESSED_TYPE_INVALID);
    if (!compressed_value->BooleanValue()) {
      compressed = 0;
    }
  }

  unsigned char privkey[279];
  size_t privkeylen;
  if (ec_privkey_export_der(secp256k1ctx, &privkey[0], &privkeylen, seckey, compressed) == 0) {
    return Nan::ThrowError(EC_PRIVKEY_EXPORT_DER_FAIL);
  }

  info.GetReturnValue().Set(COPY_BUFFER(privkey, privkeylen));
}

NAN_METHOD(secretKeyImport) {
  Nan::HandleScope scope;

  v8::Local<v8::Object> privkey_buffer = info[0].As<v8::Object>();
  CHECK_TYPE_BUFFER(privkey_buffer, EC_PRIVKEY_TYPE_INVALID);
  CHECK_BUFFER_LENGTH_GT_ZERO(privkey_buffer, EC_PRIVKEY_LENGTH_INVALID);
  const unsigned char* privkey = (const unsigned char*) node::Buffer::Data(privkey_buffer);
  size_t privkeylen = node::Buffer::Length(privkey_buffer);

  unsigned char seckey[32];
  if (ec_privkey_import_der(secp256k1ctx, &seckey[0], privkey, privkeylen) == 0) {
    return Nan::ThrowError(EC_PRIVKEY_IMPORT_DER_FAIL);
  }

  info.GetReturnValue().Set(COPY_BUFFER(seckey, 32));
}

NAN_METHOD(secretKeyTweakAdd) {
  Nan::HandleScope scope;

  v8::Local<v8::Object> seckey_buffer = info[0].As<v8::Object>();
  CHECK_TYPE_BUFFER(seckey_buffer, EC_PRIVKEY_TYPE_INVALID);
  CHECK_BUFFER_LENGTH(seckey_buffer, 32, EC_PRIVKEY_LENGTH_INVALID);
  unsigned char seckey[32];
  memcpy(&seckey[0], node::Buffer::Data(seckey_buffer), 32);

  v8::Local<v8::Object> tweak_buffer = info[1].As<v8::Object>();
  CHECK_TYPE_BUFFER(tweak_buffer, TWEAK_TYPE_INVALID);
  CHECK_BUFFER_LENGTH(tweak_buffer, 32, TWEAK_LENGTH_INVALID);
  const unsigned char* tweak = (unsigned char *) node::Buffer::Data(tweak_buffer);

  if (secp256k1_ec_privkey_tweak_add(secp256k1ctx, &seckey[0], tweak) == 0) {
    return Nan::ThrowError(EC_PRIVKEY_TWEAK_ADD_FAIL);
  }

  info.GetReturnValue().Set(COPY_BUFFER(&seckey[0], 32));
}

NAN_METHOD(secretKeyTweakMul) {
  Nan::HandleScope scope;

  v8::Local<v8::Object> seckey_buffer = info[0].As<v8::Object>();
  CHECK_TYPE_BUFFER(seckey_buffer, EC_PRIVKEY_TYPE_INVALID);
  CHECK_BUFFER_LENGTH(seckey_buffer, 32, EC_PRIVKEY_LENGTH_INVALID);
  unsigned char seckey[32];
  memcpy(&seckey[0], node::Buffer::Data(seckey_buffer), 32);

  v8::Local<v8::Object> tweak_buffer = info[1].As<v8::Object>();
  CHECK_TYPE_BUFFER(tweak_buffer, TWEAK_TYPE_INVALID);
  CHECK_BUFFER_LENGTH(tweak_buffer, 32, TWEAK_LENGTH_INVALID);
  const unsigned char* tweak = (unsigned char *) node::Buffer::Data(tweak_buffer);

  if (secp256k1_ec_privkey_tweak_mul(secp256k1ctx, &seckey[0], tweak) == 0) {
    return Nan::ThrowError(EC_PRIVKEY_TWEAK_MUL_FAIL);
  }

  info.GetReturnValue().Set(COPY_BUFFER(&seckey[0], 32));
}
<|endoftext|>


<commit_before>/*
 * This is an example client for relation-finder-client, demonstrating its
 * protocol using Boost.Asio for network communication.
 *
 * The protocol is pretty simple, the only data send is a couple of
 * 32 bit unsigned integers. It basically works like this:
 * 1. Connect to relation-finder via TCP.
 * 2. Send the user ID of the first person (user A).
 * 3. Send the user ID of the second person (user B).
 * 4. Read the length of path.
 *    If that number is 0, no path could be found.
 * 5. Read as many user IDs as the path was long.
 *    This is the result, the path from user A to user B.
 */

#include <string>
#include <iostream>
#include <boost/array.hpp>
#include <asio.hpp>

using asio::ip::tcp;

uint32_t read_uint(tcp::socket& socket)
{
    asio::error_code error;
    uint32_t uint;
    socket.read_some(asio::buffer((void*) &uint, sizeof(uint)), error);
    if (error)
        throw asio::system_error(error);
    return uint;
}

void write_uint(tcp::socket& socket, uint32_t uint)
{
    asio::error_code error;
    socket.write_some(asio::buffer((void*) &uint, sizeof(uint)), error);
    if (error)
        throw asio::system_error(error);
}

int main(int argc, char* argv[])
{
    // Read address and request parameters from the commandline
    if (argc < 5) {
        std::cerr << "relation-finder-client - asks relation-finder for a "
                  << "connection between two people" << std::endl
                  << "Usage: relation-finder-client HOST PORT PERSON1 PERSON2"
                  << std::endl;
        return 1;
    }

    std::string host = argv[1];
    std::string port = argv[2];
    unsigned int pid1 = atoi(argv[3]);
    unsigned int pid2 = atoi(argv[4]);

    try {
        // Resolve the host
        asio::io_service io_service;
        tcp::resolver resolver(io_service);
        tcp::resolver::query query(host, port);
        tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
        tcp::resolver::iterator end;

        // Connect to the server
        tcp::socket socket(io_service);
        asio::error_code error = asio::error::host_not_found;
        while (error && endpoint_iterator != end) {
            socket.close();
            socket.connect(*endpoint_iterator++, error);
        }
        if (error)
            throw asio::system_error(error);

        // Write the person's id
        write_uint(socket, pid1);

        // Write the other person's id
        write_uint(socket, pid2);

        // Read the length of the path
        int path_length = read_uint(socket);
        if (path_length == 0) {
            std::cout << "No path was found." << std::endl;
        } else {
            std::cout << "Found a path: ";

            // Read the path
            for (int i = 0; i < path_length; i++) {
                unsigned int node = read_uint(socket);
                std::cout << node;
                if (i != path_length - 1)
                    std::cout << " -> ";
            }
            std::cout << std::endl;
        }
    } catch (std::exception& e) {
        std::cerr << e.what() << std::endl;
    }

    return 0;
}
<commit_msg>Improved comment.<commit_after>/*
 * This is an example client for relation-finder, demonstrating its protocol
 * using Boost.Asio for network communication.
 *
 * The protocol is pretty simple, the only data send is a couple of unsigned
 * 32-bit integers. It basically works like this:
 * 1. Connect to relation-finder via TCP.
 * 2. Send the user ID of the first person (user A).
 * 3. Send the user ID of the second person (user B).
 * 4. Read the length of path. If that number is 0, no path could be found.
 * 5. Read as many user IDs as the path was long.
 *    This is the result, the path from user A to user B.
 */

#include <string>
#include <iostream>
#include <boost/array.hpp>
#include <asio.hpp>

using asio::ip::tcp;

uint32_t read_uint(tcp::socket& socket)
{
    asio::error_code error;
    uint32_t uint;
    socket.read_some(asio::buffer((void*) &uint, sizeof(uint)), error);
    if (error)
        throw asio::system_error(error);
    return uint;
}

void write_uint(tcp::socket& socket, uint32_t uint)
{
    asio::error_code error;
    socket.write_some(asio::buffer((void*) &uint, sizeof(uint)), error);
    if (error)
        throw asio::system_error(error);
}

int main(int argc, char* argv[])
{
    // Read address and request parameters from the commandline
    if (argc < 5) {
        std::cerr << "relation-finder-client - asks relation-finder for a "
                  << "connection between two people" << std::endl
                  << "Usage: relation-finder-client HOST PORT PERSON1 PERSON2"
                  << std::endl;
        return 1;
    }

    std::string host = argv[1];
    std::string port = argv[2];
    unsigned int pid1 = atoi(argv[3]);
    unsigned int pid2 = atoi(argv[4]);

    try {
        // Resolve the host
        asio::io_service io_service;
        tcp::resolver resolver(io_service);
        tcp::resolver::query query(host, port);
        tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
        tcp::resolver::iterator end;

        // Connect to the server
        tcp::socket socket(io_service);
        asio::error_code error = asio::error::host_not_found;
        while (error && endpoint_iterator != end) {
            socket.close();
            socket.connect(*endpoint_iterator++, error);
        }
        if (error)
            throw asio::system_error(error);

        // Write the person's id
        write_uint(socket, pid1);

        // Write the other person's id
        write_uint(socket, pid2);

        // Read the length of the path
        int path_length = read_uint(socket);
        if (path_length == 0) {
            std::cout << "No path was found." << std::endl;
        } else {
            std::cout << "Found a path: ";

            // Read the path
            for (int i = 0; i < path_length; i++) {
                unsigned int node = read_uint(socket);
                std::cout << node;
                if (i != path_length - 1)
                    std::cout << " -> ";
            }
            std::cout << std::endl;
        }
    } catch (std::exception& e) {
        std::cerr << e.what() << std::endl;
    }

    return 0;
}
<|endoftext|>


<commit_before>#include "pch.h"
#include "json_rpc_debug_logger.h"

#include <QDebug>

namespace jcon {

void JsonRpcDebugLogger::logInfo(const QString& message)
{
    qDebug().noquote() << message;
}

void JsonRpcDebugLogger::logWarning(const QString& message)
{
    qDebug().noquote() << message;
}

void JsonRpcDebugLogger::logError(const QString& message)
{
    qDebug().noquote() << message;
}

}
<commit_msg>Remove inclusion of non-existing precompiled header<commit_after>#include "json_rpc_debug_logger.h"

#include <QDebug>

namespace jcon {

void JsonRpcDebugLogger::logInfo(const QString& message)
{
    qDebug().noquote() << message;
}

void JsonRpcDebugLogger::logWarning(const QString& message)
{
    qDebug().noquote() << message;
}

void JsonRpcDebugLogger::logError(const QString& message)
{
    qDebug().noquote() << message;
}

}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#ifndef COMPILER_EXCEPTION_H
#define COMPILER_EXCEPTION_H

#include <string>

#include "Token.hpp"

namespace eddic {

class CompilerException: public std::exception {
    protected:
        std::string m_message;
        Token* m_token;

    public:
        CompilerException(const std::string& message) : m_message(message) {};
        CompilerException(const std::string& message, Token* token) : m_message(message), m_token(token) {};
        ~CompilerException() throw() {};

        virtual const char* what() const throw();
};

class TokenException: public CompilerException {
    private:
        Token* m_token;

    public:
        TokenException(const std::string& message, Token* token) : CompilerException(message), m_token(token) {}
        ~TokenException() throw() {};

        const char* what() const throw();
};

} //end of eddic

#endif
<commit_msg>Put the Token* as const<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#ifndef COMPILER_EXCEPTION_H
#define COMPILER_EXCEPTION_H

#include <string>

#include "Token.hpp"

namespace eddic {

class CompilerException: public std::exception {
    protected:
        std::string m_message;
        const Token* m_token;

    public:
        CompilerException(const std::string& message) : m_message(message) {};
        CompilerException(const std::string& message, const Token* token) : m_message(message), m_token(token) {};
        ~CompilerException() throw() {};

        virtual const char* what() const throw();
};

class TokenException: public CompilerException {
    private:
        Token* m_token;

    public:
        TokenException(const std::string& message, Token* token) : CompilerException(message), m_token(token) {}
        ~TokenException() throw() {};

        const char* what() const throw();
};

} //end of eddic

#endif
<|endoftext|>