renamed: Server/*/*.h -> server/*/*.hpp

This commit is contained in:
Dennis Luxen
2015-01-27 12:35:29 +01:00
parent 0c1101739d
commit 9672f00ec3
28 changed files with 2061 additions and 132 deletions
+130
View File
@@ -0,0 +1,130 @@
/*
Copyright (c) 2015, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "reply.hpp"
#include "../../Util/cast.hpp"
namespace http
{
const char ok_html[] = "";
const char bad_request_html[] = "{\"status\": 400,\"status_message\":\"Bad Request\"}";
const char internal_server_error_html[] =
"{\"status\": 500,\"status_message\":\"Internal Server Error\"}";
const char seperators[] = {':', ' '};
const char crlf[] = {'\r', '\n'};
const std::string http_ok_string = "HTTP/1.0 200 OK\r\n";
const std::string http_bad_request_string = "HTTP/1.0 400 Bad Request\r\n";
const std::string http_internal_server_error_string = "HTTP/1.0 500 Internal Server Error\r\n";
void reply::set_size(const std::size_t size)
{
for (header &h : headers)
{
if ("Content-Length" == h.name)
{
h.value = cast::integral_to_string(size);
}
}
}
void reply::set_uncompressed_size() { set_size(content.size()); }
std::vector<boost::asio::const_buffer> reply::to_buffers()
{
std::vector<boost::asio::const_buffer> buffers;
buffers.push_back(status_to_buffer(status));
for (const header &h : headers)
{
buffers.push_back(boost::asio::buffer(h.name));
buffers.push_back(boost::asio::buffer(seperators));
buffers.push_back(boost::asio::buffer(h.value));
buffers.push_back(boost::asio::buffer(crlf));
}
buffers.push_back(boost::asio::buffer(crlf));
buffers.push_back(boost::asio::buffer(content));
return buffers;
}
std::vector<boost::asio::const_buffer> reply::headers_to_buffers()
{
std::vector<boost::asio::const_buffer> buffers;
buffers.push_back(status_to_buffer(status));
for (const header &current_header : headers)
{
buffers.push_back(boost::asio::buffer(current_header.name));
buffers.push_back(boost::asio::buffer(seperators));
buffers.push_back(boost::asio::buffer(current_header.value));
buffers.push_back(boost::asio::buffer(crlf));
}
buffers.push_back(boost::asio::buffer(crlf));
return buffers;
}
reply reply::stock_reply(const reply::status_type status)
{
reply reply;
reply.status = status;
reply.content.clear();
const std::string status_string = reply.status_to_string(status);
reply.content.insert(reply.content.end(), status_string.begin(), status_string.end());
reply.headers.emplace_back("Access-Control-Allow-Origin", "*");
reply.headers.emplace_back("Content-Length", cast::integral_to_string(reply.content.size()));
reply.headers.emplace_back("Content-Type", "text/html");
return reply;
}
std::string reply::status_to_string(const reply::status_type status)
{
if (reply::ok == status)
{
return ok_html;
}
if (reply::bad_request == status)
{
return bad_request_html;
}
return internal_server_error_html;
}
boost::asio::const_buffer reply::status_to_buffer(const reply::status_type status)
{
if (reply::ok == status)
{
return boost::asio::buffer(http_ok_string);
}
if (reply::internal_server_error == status)
{
return boost::asio::buffer(http_internal_server_error_string);
}
return boost::asio::buffer(http_bad_request_string);
}
reply::reply() : status(ok) {}
}
+92
View File
@@ -0,0 +1,92 @@
/*
Copyright (c) 2013, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef API_GRAMMAR_HPP
#define API_GRAMMAR_HPP
#include <boost/bind.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/qi_action.hpp>
namespace qi = boost::spirit::qi;
template <typename Iterator, class HandlerT> struct APIGrammar : qi::grammar<Iterator>
{
explicit APIGrammar(HandlerT *h) : APIGrammar::base_type(api_call), handler(h)
{
api_call = qi::lit('/') >> string[boost::bind(&HandlerT::setService, handler, ::_1)] >>
*(query) >> -(uturns);
query = ('?') >> (+(zoom | output | jsonp | checksum | location | hint | u | cmp |
language | instruction | geometry | alt_route | old_API | num_results));
zoom = (-qi::lit('&')) >> qi::lit('z') >> '=' >>
qi::short_[boost::bind(&HandlerT::setZoomLevel, handler, ::_1)];
output = (-qi::lit('&')) >> qi::lit("output") >> '=' >>
string[boost::bind(&HandlerT::setOutputFormat, handler, ::_1)];
jsonp = (-qi::lit('&')) >> qi::lit("jsonp") >> '=' >>
stringwithPercent[boost::bind(&HandlerT::setJSONpParameter, handler, ::_1)];
checksum = (-qi::lit('&')) >> qi::lit("checksum") >> '=' >>
qi::uint_[boost::bind(&HandlerT::setChecksum, handler, ::_1)];
instruction = (-qi::lit('&')) >> qi::lit("instructions") >> '=' >>
qi::bool_[boost::bind(&HandlerT::setInstructionFlag, handler, ::_1)];
geometry = (-qi::lit('&')) >> qi::lit("geometry") >> '=' >>
qi::bool_[boost::bind(&HandlerT::setGeometryFlag, handler, ::_1)];
cmp = (-qi::lit('&')) >> qi::lit("compression") >> '=' >>
qi::bool_[boost::bind(&HandlerT::setCompressionFlag, handler, ::_1)];
location = (-qi::lit('&')) >> qi::lit("loc") >> '=' >>
(qi::double_ >> qi::lit(',') >>
qi::double_)[boost::bind(&HandlerT::addCoordinate, handler, ::_1)];
hint = (-qi::lit('&')) >> qi::lit("hint") >> '=' >>
stringwithDot[boost::bind(&HandlerT::addHint, handler, ::_1)];
u = (-qi::lit('&')) >> qi::lit("u") >> '=' >>
qi::bool_[boost::bind(&HandlerT::setUTurn, handler, ::_1)];
uturns = (-qi::lit('&')) >> qi::lit("uturns") >> '=' >>
qi::bool_[boost::bind(&HandlerT::setAllUTurns, handler, ::_1)];
language = (-qi::lit('&')) >> qi::lit("hl") >> '=' >>
string[boost::bind(&HandlerT::setLanguage, handler, ::_1)];
alt_route = (-qi::lit('&')) >> qi::lit("alt") >> '=' >>
qi::bool_[boost::bind(&HandlerT::setAlternateRouteFlag, handler, ::_1)];
old_API = (-qi::lit('&')) >> qi::lit("geomformat") >> '=' >>
string[boost::bind(&HandlerT::setDeprecatedAPIFlag, handler, ::_1)];
num_results = (-qi::lit('&')) >> qi::lit("num_results") >> '=' >>
qi::short_[boost::bind(&HandlerT::setNumberOfResults, handler, ::_1)];
string = +(qi::char_("a-zA-Z"));
stringwithDot = +(qi::char_("a-zA-Z0-9_.-"));
stringwithPercent = +(qi::char_("a-zA-Z0-9_.-") | qi::char_('[') | qi::char_(']') |
(qi::char_('%') >> qi::char_("0-9A-Z") >> qi::char_("0-9A-Z")));
}
qi::rule<Iterator> api_call, query;
qi::rule<Iterator, std::string()> service, zoom, output, string, jsonp, checksum, location,
hint, stringwithDot, stringwithPercent, language, instruction, geometry, cmp, alt_route, u,
uturns, old_API, num_results;
HandlerT *handler;
};
#endif /* API_GRAMMAR_HPP */
+168
View File
@@ -0,0 +1,168 @@
/*
Copyright (c) 2015, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "connection.hpp"
#include "request_handler.hpp"
#include "request_parser.hpp"
#include <boost/assert.hpp>
#include <boost/bind.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/filter/gzip.hpp>
#include <string>
#include <vector>
namespace http
{
Connection::Connection(boost::asio::io_service &io_service, RequestHandler &handler)
: strand(io_service), TCP_socket(io_service), request_handler(handler)
{
}
boost::asio::ip::tcp::socket &Connection::socket() { return TCP_socket; }
/// Start the first asynchronous operation for the connection.
void Connection::start()
{
TCP_socket.async_read_some(
boost::asio::buffer(incoming_data_buffer),
strand.wrap(boost::bind(&Connection::handle_read, this->shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred)));
}
void Connection::handle_read(const boost::system::error_code &error, std::size_t bytes_transferred)
{
if (error)
{
return;
}
// no error detected, let's parse the request
compression_type compression_type(no_compression);
osrm::tribool result;
std::tie(result, compression_type) = RequestParser().parse(
request, incoming_data_buffer.data(), incoming_data_buffer.data() + bytes_transferred);
// the request has been parsed
if (result == osrm::tribool::yes)
{
request.endpoint = TCP_socket.remote_endpoint().address();
request_handler.handle_request(request, reply);
// Header compression_header;
std::vector<char> compressed_output;
std::vector<boost::asio::const_buffer> output_buffer;
// compress the result w/ gzip/deflate if requested
switch (compression_type)
{
case deflate_rfc1951:
// use deflate for compression
reply.headers.insert(reply.headers.begin(), {"Content-Encoding", "deflate"});
compressed_output = compress_buffers(reply.content, compression_type);
reply.set_size(static_cast<unsigned>(compressed_output.size()));
output_buffer = reply.headers_to_buffers();
output_buffer.push_back(boost::asio::buffer(compressed_output));
break;
case gzip_rfc1952:
// use gzip for compression
reply.headers.insert(reply.headers.begin(), {"Content-Encoding", "gzip"});
compressed_output = compress_buffers(reply.content, compression_type);
reply.set_size(static_cast<unsigned>(compressed_output.size()));
output_buffer = reply.headers_to_buffers();
output_buffer.push_back(boost::asio::buffer(compressed_output));
break;
case no_compression:
// don't use any compression
reply.set_uncompressed_size();
output_buffer = reply.to_buffers();
break;
}
// write result to stream
boost::asio::async_write(
TCP_socket, output_buffer,
strand.wrap(boost::bind(&Connection::handle_write, this->shared_from_this(),
boost::asio::placeholders::error)));
}
else if (result == osrm::tribool::no)
{ // request is not parseable
reply = reply::stock_reply(reply::bad_request);
boost::asio::async_write(
TCP_socket, reply.to_buffers(),
strand.wrap(boost::bind(&Connection::handle_write, this->shared_from_this(),
boost::asio::placeholders::error)));
}
else
{
// we don't have a result yet, so continue reading
TCP_socket.async_read_some(
boost::asio::buffer(incoming_data_buffer),
strand.wrap(boost::bind(&Connection::handle_read, this->shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred)));
}
}
/// Handle completion of a write operation.
void Connection::handle_write(const boost::system::error_code &error)
{
if (!error)
{
// Initiate graceful connection closure.
boost::system::error_code ignore_error;
TCP_socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignore_error);
}
}
std::vector<char> Connection::compress_buffers(const std::vector<char> &uncompressed_data,
const compression_type compression_type)
{
boost::iostreams::gzip_params compression_parameters;
// there's a trade-off between speed and size. speed wins
compression_parameters.level = boost::iostreams::zlib::best_speed;
// check which compression flavor is used
if (deflate_rfc1951 == compression_type)
{
compression_parameters.noheader = true;
}
std::vector<char> compressed_data;
// plug data into boost's compression stream
boost::iostreams::filtering_ostream gzip_stream;
gzip_stream.push(boost::iostreams::gzip_compressor(compression_parameters));
gzip_stream.push(boost::iostreams::back_inserter(compressed_data));
gzip_stream.write(&uncompressed_data[0], uncompressed_data.size());
boost::iostreams::close(gzip_stream);
return compressed_data;
}
}
+92
View File
@@ -0,0 +1,92 @@
/*
Copyright (c) 2015, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CONNECTION_HPP
#define CONNECTION_HPP
#include "http/compression_type.hpp"
#include "http/reply.hpp"
#include "http/request.hpp"
#include <boost/array.hpp>
#include <boost/asio.hpp>
#include <boost/config.hpp>
#include <boost/version.hpp>
#include <memory>
#include <vector>
// workaround for incomplete std::shared_ptr compatibility in old boost versions
#if BOOST_VERSION < 105300 || defined BOOST_NO_CXX11_SMART_PTR
namespace boost
{
template <class T> const T *get_pointer(std::shared_ptr<T> const &p) { return p.get(); }
template <class T> T *get_pointer(std::shared_ptr<T> &p) { return p.get(); }
} // namespace boost
#endif
class RequestHandler;
namespace http
{
/// Represents a single connection from a client.
class Connection : public std::enable_shared_from_this<Connection>
{
public:
explicit Connection(boost::asio::io_service &io_service, RequestHandler &handler);
Connection(const Connection &) = delete;
Connection() = delete;
boost::asio::ip::tcp::socket &socket();
/// Start the first asynchronous operation for the connection.
void start();
private:
void handle_read(const boost::system::error_code &e, std::size_t bytes_transferred);
/// Handle completion of a write operation.
void handle_write(const boost::system::error_code &e);
std::vector<char> compress_buffers(const std::vector<char> &uncompressed_data,
const compression_type compression_type);
boost::asio::io_service::strand strand;
boost::asio::ip::tcp::socket TCP_socket;
RequestHandler &request_handler;
boost::array<char, 8192> incoming_data_buffer;
request request;
reply reply;
};
} // namespace http
#endif // CONNECTION_HPP
+126
View File
@@ -0,0 +1,126 @@
/*
Copyright (c) 2015, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef DATAFACADE_BASE_HPP
#define DATAFACADE_BASE_HPP
// Exposes all data access interfaces to the algorithms via base class ptr
#include "../../data_structures/edge_based_node.hpp"
#include "../../data_structures/external_memory_node.hpp"
#include "../../data_structures/phantom_node.hpp"
#include "../../data_structures/turn_instructions.hpp"
#include "../../Util/integer_range.hpp"
#include "../../Util/osrm_exception.hpp"
#include "../../Util/string_util.hpp"
#include "../../typedefs.h"
#include <osrm/coordinate.hpp>
#include <string>
typedef osrm::range<EdgeID> EdgeRange;
template <class EdgeDataT> class BaseDataFacade
{
public:
typedef EdgeBasedNode RTreeLeaf;
typedef EdgeDataT EdgeData;
BaseDataFacade() {}
virtual ~BaseDataFacade() {}
// search graph access
virtual unsigned GetNumberOfNodes() const = 0;
virtual unsigned GetNumberOfEdges() const = 0;
virtual unsigned GetOutDegree(const NodeID n) const = 0;
virtual NodeID GetTarget(const EdgeID e) const = 0;
// virtual EdgeDataT &GetEdgeData(const EdgeID e) = 0;
virtual const EdgeDataT &GetEdgeData(const EdgeID e) const = 0;
virtual EdgeID BeginEdges(const NodeID n) const = 0;
virtual EdgeID EndEdges(const NodeID n) const = 0;
virtual EdgeRange GetAdjacentEdgeRange(const NodeID node) const = 0;
// searches for a specific edge
virtual EdgeID FindEdge(const NodeID from, const NodeID to) const = 0;
virtual EdgeID FindEdgeInEitherDirection(const NodeID from, const NodeID to) const = 0;
virtual EdgeID
FindEdgeIndicateIfReverse(const NodeID from, const NodeID to, bool &result) const = 0;
// node and edge information access
virtual FixedPointCoordinate GetCoordinateOfNode(const unsigned id) const = 0;
virtual bool EdgeIsCompressed(const unsigned id) const = 0;
virtual unsigned GetGeometryIndexForEdgeID(const unsigned id) const = 0;
virtual void GetUncompressedGeometry(const unsigned id,
std::vector<unsigned> &result_nodes) const = 0;
virtual TurnInstruction GetTurnInstructionForEdgeID(const unsigned id) const = 0;
virtual TravelMode GetTravelModeForEdgeID(const unsigned id) const = 0;
virtual bool LocateClosestEndPointForCoordinate(const FixedPointCoordinate &input_coordinate,
FixedPointCoordinate &result,
const unsigned zoom_level = 18) = 0;
virtual bool
IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
std::vector<PhantomNode> &resulting_phantom_node_vector,
const unsigned number_of_results) = 0;
virtual bool
IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
PhantomNode &resulting_phantom_node) = 0;
virtual unsigned GetCheckSum() const = 0;
virtual unsigned GetNameIndexFromEdgeID(const unsigned id) const = 0;
virtual void GetName(const unsigned name_id, std::string &result) const = 0;
std::string GetEscapedNameForNameID(const unsigned name_id) const
{
std::string temporary_string;
GetName(name_id, temporary_string);
return EscapeJSONString(temporary_string);
}
virtual std::string GetTimestamp() const = 0;
};
#endif // DATAFACADE_BASE_HPP
@@ -0,0 +1,449 @@
/*
Copyright (c) 2015, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef INTERNAL_DATAFACADE_HPP
#define INTERNAL_DATAFACADE_HPP
// implements all data storage when shared memory is _NOT_ used
#include "datafacade_base.hpp"
#include "../../data_structures/original_edge_data.hpp"
#include "../../data_structures/query_node.hpp"
#include "../../data_structures/query_edge.hpp"
#include "../../data_structures/shared_memory_vector_wrapper.hpp"
#include "../../data_structures/static_graph.hpp"
#include "../../data_structures/static_rtree.hpp"
#include "../../data_structures/range_table.hpp"
#include "../../Util/BoostFileSystemFix.h"
#include "../../Util/graph_loader.hpp"
#include "../../Util/simple_logger.hpp"
#include <osrm/coordinate.hpp>
#include <osrm/server_paths.hpp>
template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<EdgeDataT>
{
private:
typedef BaseDataFacade<EdgeDataT> super;
typedef StaticGraph<typename super::EdgeData> QueryGraph;
typedef typename QueryGraph::InputEdge InputEdge;
typedef typename super::RTreeLeaf RTreeLeaf;
InternalDataFacade() {}
unsigned m_check_sum;
unsigned m_number_of_nodes;
QueryGraph *m_query_graph;
std::string m_timestamp;
std::shared_ptr<ShM<FixedPointCoordinate, false>::vector> m_coordinate_list;
ShM<NodeID, false>::vector m_via_node_list;
ShM<unsigned, false>::vector m_name_ID_list;
ShM<TurnInstruction, false>::vector m_turn_instruction_list;
ShM<TravelMode, false>::vector m_travel_mode_list;
ShM<char, false>::vector m_names_char_list;
ShM<bool, false>::vector m_edge_is_compressed;
ShM<unsigned, false>::vector m_geometry_indices;
ShM<unsigned, false>::vector m_geometry_list;
boost::thread_specific_ptr<
StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, false>::vector, false>> m_static_rtree;
boost::filesystem::path ram_index_path;
boost::filesystem::path file_index_path;
RangeTable<16, false> m_name_table;
void LoadTimestamp(const boost::filesystem::path &timestamp_path)
{
if (boost::filesystem::exists(timestamp_path))
{
SimpleLogger().Write() << "Loading Timestamp";
boost::filesystem::ifstream timestamp_stream(timestamp_path);
if (!timestamp_stream)
{
SimpleLogger().Write(logWARNING) << timestamp_path << " not found";
}
getline(timestamp_stream, m_timestamp);
timestamp_stream.close();
}
if (m_timestamp.empty())
{
m_timestamp = "n/a";
}
if (25 < m_timestamp.length())
{
m_timestamp.resize(25);
}
}
void LoadGraph(const boost::filesystem::path &hsgr_path)
{
typename ShM<typename QueryGraph::NodeArrayEntry, false>::vector node_list;
typename ShM<typename QueryGraph::EdgeArrayEntry, false>::vector edge_list;
SimpleLogger().Write() << "loading graph from " << hsgr_path.string();
m_number_of_nodes = readHSGRFromStream(hsgr_path, node_list, edge_list, &m_check_sum);
BOOST_ASSERT_MSG(0 != node_list.size(), "node list empty");
// BOOST_ASSERT_MSG(0 != edge_list.size(), "edge list empty");
SimpleLogger().Write() << "loaded " << node_list.size() << " nodes and " << edge_list.size()
<< " edges";
m_query_graph = new QueryGraph(node_list, edge_list);
BOOST_ASSERT_MSG(0 == node_list.size(), "node list not flushed");
BOOST_ASSERT_MSG(0 == edge_list.size(), "edge list not flushed");
SimpleLogger().Write() << "Data checksum is " << m_check_sum;
}
void LoadNodeAndEdgeInformation(const boost::filesystem::path &nodes_file,
const boost::filesystem::path &edges_file)
{
boost::filesystem::ifstream nodes_input_stream(nodes_file, std::ios::binary);
QueryNode current_node;
unsigned number_of_coordinates = 0;
nodes_input_stream.read((char *)&number_of_coordinates, sizeof(unsigned));
m_coordinate_list =
std::make_shared<std::vector<FixedPointCoordinate>>(number_of_coordinates);
for (unsigned i = 0; i < number_of_coordinates; ++i)
{
nodes_input_stream.read((char *)&current_node, sizeof(QueryNode));
m_coordinate_list->at(i) = FixedPointCoordinate(current_node.lat, current_node.lon);
BOOST_ASSERT((std::abs(m_coordinate_list->at(i).lat) >> 30) == 0);
BOOST_ASSERT((std::abs(m_coordinate_list->at(i).lon) >> 30) == 0);
}
nodes_input_stream.close();
boost::filesystem::ifstream edges_input_stream(edges_file, std::ios::binary);
unsigned number_of_edges = 0;
edges_input_stream.read((char *)&number_of_edges, sizeof(unsigned));
m_via_node_list.resize(number_of_edges);
m_name_ID_list.resize(number_of_edges);
m_turn_instruction_list.resize(number_of_edges);
m_travel_mode_list.resize(number_of_edges);
m_edge_is_compressed.resize(number_of_edges);
unsigned compressed = 0;
OriginalEdgeData current_edge_data;
for (unsigned i = 0; i < number_of_edges; ++i)
{
edges_input_stream.read((char *)&(current_edge_data), sizeof(OriginalEdgeData));
m_via_node_list[i] = current_edge_data.via_node;
m_name_ID_list[i] = current_edge_data.name_id;
m_turn_instruction_list[i] = current_edge_data.turn_instruction;
m_travel_mode_list[i] = current_edge_data.travel_mode;
m_edge_is_compressed[i] = current_edge_data.compressed_geometry;
if (m_edge_is_compressed[i])
{
++compressed;
}
}
edges_input_stream.close();
}
void LoadGeometries(const boost::filesystem::path &geometry_file)
{
std::ifstream geometry_stream(geometry_file.string().c_str(), std::ios::binary);
unsigned number_of_indices = 0;
unsigned number_of_compressed_geometries = 0;
geometry_stream.read((char *)&number_of_indices, sizeof(unsigned));
m_geometry_indices.resize(number_of_indices);
if (number_of_indices > 0)
{
geometry_stream.read((char *)&(m_geometry_indices[0]),
number_of_indices * sizeof(unsigned));
}
geometry_stream.read((char *)&number_of_compressed_geometries, sizeof(unsigned));
BOOST_ASSERT(m_geometry_indices.back() == number_of_compressed_geometries);
m_geometry_list.resize(number_of_compressed_geometries);
if (number_of_compressed_geometries > 0)
{
geometry_stream.read((char *)&(m_geometry_list[0]),
number_of_compressed_geometries * sizeof(unsigned));
}
geometry_stream.close();
}
void LoadRTree()
{
BOOST_ASSERT_MSG(!m_coordinate_list->empty(), "coordinates must be loaded before r-tree");
m_static_rtree.reset(
new StaticRTree<RTreeLeaf>(ram_index_path, file_index_path, m_coordinate_list));
}
void LoadStreetNames(const boost::filesystem::path &names_file)
{
boost::filesystem::ifstream name_stream(names_file, std::ios::binary);
name_stream >> m_name_table;
unsigned number_of_chars = 0;
name_stream.read((char *)&number_of_chars, sizeof(unsigned));
BOOST_ASSERT_MSG(0 != number_of_chars, "name file broken");
m_names_char_list.resize(number_of_chars + 1); //+1 gives sentinel element
name_stream.read((char *)&m_names_char_list[0], number_of_chars * sizeof(char));
if (0 == m_names_char_list.size())
{
SimpleLogger().Write(logWARNING) << "list of street names is empty";
}
name_stream.close();
}
public:
virtual ~InternalDataFacade()
{
delete m_query_graph;
m_static_rtree.reset();
}
explicit InternalDataFacade(const ServerPaths &server_paths)
{
// generate paths of data files
if (server_paths.find("hsgrdata") == server_paths.end())
{
throw osrm::exception("no hsgr file given in ini file");
}
if (server_paths.find("ramindex") == server_paths.end())
{
throw osrm::exception("no ram index file given in ini file");
}
if (server_paths.find("fileindex") == server_paths.end())
{
throw osrm::exception("no leaf index file given in ini file");
}
if (server_paths.find("geometries") == server_paths.end())
{
throw osrm::exception("no geometries file given in ini file");
}
if (server_paths.find("nodesdata") == server_paths.end())
{
throw osrm::exception("no nodes file given in ini file");
}
if (server_paths.find("edgesdata") == server_paths.end())
{
throw osrm::exception("no edges file given in ini file");
}
if (server_paths.find("namesdata") == server_paths.end())
{
throw osrm::exception("no names file given in ini file");
}
ServerPaths::const_iterator paths_iterator = server_paths.find("hsgrdata");
BOOST_ASSERT(server_paths.end() != paths_iterator);
const boost::filesystem::path &hsgr_path = paths_iterator->second;
paths_iterator = server_paths.find("timestamp");
BOOST_ASSERT(server_paths.end() != paths_iterator);
const boost::filesystem::path &timestamp_path = paths_iterator->second;
paths_iterator = server_paths.find("ramindex");
BOOST_ASSERT(server_paths.end() != paths_iterator);
ram_index_path = paths_iterator->second;
paths_iterator = server_paths.find("fileindex");
BOOST_ASSERT(server_paths.end() != paths_iterator);
file_index_path = paths_iterator->second;
paths_iterator = server_paths.find("nodesdata");
BOOST_ASSERT(server_paths.end() != paths_iterator);
const boost::filesystem::path &nodes_data_path = paths_iterator->second;
paths_iterator = server_paths.find("edgesdata");
BOOST_ASSERT(server_paths.end() != paths_iterator);
const boost::filesystem::path &edges_data_path = paths_iterator->second;
paths_iterator = server_paths.find("namesdata");
BOOST_ASSERT(server_paths.end() != paths_iterator);
const boost::filesystem::path &names_data_path = paths_iterator->second;
paths_iterator = server_paths.find("geometries");
BOOST_ASSERT(server_paths.end() != paths_iterator);
const boost::filesystem::path &geometries_path = paths_iterator->second;
// load data
SimpleLogger().Write() << "loading graph data";
AssertPathExists(hsgr_path);
LoadGraph(hsgr_path);
SimpleLogger().Write() << "loading edge information";
AssertPathExists(nodes_data_path);
AssertPathExists(edges_data_path);
LoadNodeAndEdgeInformation(nodes_data_path, edges_data_path);
SimpleLogger().Write() << "loading geometries";
AssertPathExists(geometries_path);
LoadGeometries(geometries_path);
SimpleLogger().Write() << "loading r-tree";
AssertPathExists(ram_index_path);
AssertPathExists(file_index_path);
SimpleLogger().Write() << "loading timestamp";
LoadTimestamp(timestamp_path);
SimpleLogger().Write() << "loading street names";
AssertPathExists(names_data_path);
LoadStreetNames(names_data_path);
}
// search graph access
unsigned GetNumberOfNodes() const final { return m_query_graph->GetNumberOfNodes(); }
unsigned GetNumberOfEdges() const final { return m_query_graph->GetNumberOfEdges(); }
unsigned GetOutDegree(const NodeID n) const final { return m_query_graph->GetOutDegree(n); }
NodeID GetTarget(const EdgeID e) const final { return m_query_graph->GetTarget(e); }
// EdgeDataT &GetEdgeData(const EdgeID e) final { return m_query_graph->GetEdgeData(e); }
EdgeDataT &GetEdgeData(const EdgeID e) const final { return m_query_graph->GetEdgeData(e); }
EdgeID BeginEdges(const NodeID n) const final { return m_query_graph->BeginEdges(n); }
EdgeID EndEdges(const NodeID n) const final { return m_query_graph->EndEdges(n); }
EdgeRange GetAdjacentEdgeRange(const NodeID node) const final
{
return m_query_graph->GetAdjacentEdgeRange(node);
};
// searches for a specific edge
EdgeID FindEdge(const NodeID from, const NodeID to) const final
{
return m_query_graph->FindEdge(from, to);
}
EdgeID FindEdgeInEitherDirection(const NodeID from, const NodeID to) const final
{
return m_query_graph->FindEdgeInEitherDirection(from, to);
}
EdgeID FindEdgeIndicateIfReverse(const NodeID from, const NodeID to, bool &result) const final
{
return m_query_graph->FindEdgeIndicateIfReverse(from, to, result);
}
// node and edge information access
FixedPointCoordinate GetCoordinateOfNode(const unsigned id) const final
{
return m_coordinate_list->at(id);
};
bool EdgeIsCompressed(const unsigned id) const { return m_edge_is_compressed.at(id); }
TurnInstruction GetTurnInstructionForEdgeID(const unsigned id) const final
{
return m_turn_instruction_list.at(id);
}
TravelMode GetTravelModeForEdgeID(const unsigned id) const { return m_travel_mode_list.at(id); }
bool LocateClosestEndPointForCoordinate(const FixedPointCoordinate &input_coordinate,
FixedPointCoordinate &result,
const unsigned zoom_level = 18) final
{
if (!m_static_rtree.get())
{
LoadRTree();
}
return m_static_rtree->LocateClosestEndPointForCoordinate(input_coordinate, result,
zoom_level);
}
bool IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
PhantomNode &resulting_phantom_node) final
{
std::vector<PhantomNode> resulting_phantom_node_vector;
auto result = IncrementalFindPhantomNodeForCoordinate(input_coordinate,
resulting_phantom_node_vector, 1);
if (result)
{
BOOST_ASSERT(!resulting_phantom_node_vector.empty());
resulting_phantom_node = resulting_phantom_node_vector.front();
}
return result;
}
bool
IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
std::vector<PhantomNode> &resulting_phantom_node_vector,
const unsigned number_of_results) final
{
if (!m_static_rtree.get())
{
LoadRTree();
}
return m_static_rtree->IncrementalFindPhantomNodeForCoordinate(
input_coordinate, resulting_phantom_node_vector, number_of_results);
}
unsigned GetCheckSum() const final { return m_check_sum; }
unsigned GetNameIndexFromEdgeID(const unsigned id) const final
{
return m_name_ID_list.at(id);
};
void GetName(const unsigned name_id, std::string &result) const final
{
if (UINT_MAX == name_id)
{
result = "";
return;
}
auto range = m_name_table.GetRange(name_id);
result.clear();
if (range.begin() != range.end())
{
result.resize(range.back() - range.front() + 1);
std::copy(m_names_char_list.begin() + range.front(),
m_names_char_list.begin() + range.back() + 1, result.begin());
}
}
virtual unsigned GetGeometryIndexForEdgeID(const unsigned id) const final
{
return m_via_node_list.at(id);
}
virtual void GetUncompressedGeometry(const unsigned id,
std::vector<unsigned> &result_nodes) const final
{
const unsigned begin = m_geometry_indices.at(id);
const unsigned end = m_geometry_indices.at(id + 1);
result_nodes.clear();
result_nodes.insert(result_nodes.begin(), m_geometry_list.begin() + begin,
m_geometry_list.begin() + end);
}
std::string GetTimestamp() const final { return m_timestamp; }
};
#endif // INTERNAL_DATAFACADE_HPP
@@ -0,0 +1,60 @@
/*
Copyright (c) 2015, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef SHARED_BARRIERS_HPP
#define SHARED_BARRIERS_HPP
#include <boost/interprocess/sync/named_mutex.hpp>
#include <boost/interprocess/sync/named_condition.hpp>
struct SharedBarriers
{
SharedBarriers()
: pending_update_mutex(boost::interprocess::open_or_create, "pending_update"),
update_mutex(boost::interprocess::open_or_create, "update"),
query_mutex(boost::interprocess::open_or_create, "query"),
no_running_queries_condition(boost::interprocess::open_or_create, "no_running_queries"),
update_ongoing(false), number_of_queries(0)
{
}
// Mutex to protect access to the boolean variable
boost::interprocess::named_mutex pending_update_mutex;
boost::interprocess::named_mutex update_mutex;
boost::interprocess::named_mutex query_mutex;
// Condition that no update is running
boost::interprocess::named_condition no_running_queries_condition;
// Is there an ongoing update?
bool update_ongoing;
// Is there any query?
int number_of_queries;
};
#endif // SHARED_BARRIERS_HPP
@@ -0,0 +1,423 @@
/*
Copyright (c) 2015, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef SHARED_DATAFACADE_HPP
#define SHARED_DATAFACADE_HPP
// implements all data storage when shared memory _IS_ used
#include "datafacade_base.hpp"
#include "shared_datatype.hpp"
#include "../../data_structures/range_table.hpp"
#include "../../data_structures/static_graph.hpp"
#include "../../data_structures/static_rtree.hpp"
#include "../../Util/BoostFileSystemFix.h"
#include "../../Util/make_unique.hpp"
#include "../../Util/simple_logger.hpp"
#include <algorithm>
#include <memory>
template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDataT>
{
private:
typedef EdgeDataT EdgeData;
typedef BaseDataFacade<EdgeData> super;
typedef StaticGraph<EdgeData, true> QueryGraph;
typedef typename StaticGraph<EdgeData, true>::NodeArrayEntry GraphNode;
typedef typename StaticGraph<EdgeData, true>::EdgeArrayEntry GraphEdge;
typedef typename RangeTable<16, true>::BlockT NameIndexBlock;
typedef typename QueryGraph::InputEdge InputEdge;
typedef typename super::RTreeLeaf RTreeLeaf;
using SharedRTree = StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, true>::vector, true>;
using TimeStampedRTreePair = std::pair<unsigned, std::shared_ptr<SharedRTree>>;
using RTreeNode = typename SharedRTree::TreeNode;
SharedDataLayout *data_layout;
char *shared_memory;
SharedDataTimestamp *data_timestamp_ptr;
SharedDataType CURRENT_LAYOUT;
SharedDataType CURRENT_DATA;
unsigned CURRENT_TIMESTAMP;
unsigned m_check_sum;
std::unique_ptr<QueryGraph> m_query_graph;
std::unique_ptr<SharedMemory> m_layout_memory;
std::unique_ptr<SharedMemory> m_large_memory;
std::string m_timestamp;
std::shared_ptr<ShM<FixedPointCoordinate, true>::vector> m_coordinate_list;
ShM<NodeID, true>::vector m_via_node_list;
ShM<unsigned, true>::vector m_name_ID_list;
ShM<TurnInstruction, true>::vector m_turn_instruction_list;
ShM<TravelMode, true>::vector m_travel_mode_list;
ShM<char, true>::vector m_names_char_list;
ShM<unsigned, true>::vector m_name_begin_indices;
ShM<bool, true>::vector m_edge_is_compressed;
ShM<unsigned, true>::vector m_geometry_indices;
ShM<unsigned, true>::vector m_geometry_list;
boost::thread_specific_ptr<std::pair<unsigned, std::shared_ptr<SharedRTree>>> m_static_rtree;
boost::filesystem::path file_index_path;
std::shared_ptr<RangeTable<16, true>> m_name_table;
void LoadChecksum()
{
m_check_sum =
*data_layout->GetBlockPtr<unsigned>(shared_memory, SharedDataLayout::HSGR_CHECKSUM);
SimpleLogger().Write() << "set checksum: " << m_check_sum;
}
void LoadTimestamp()
{
char *timestamp_ptr =
data_layout->GetBlockPtr<char>(shared_memory, SharedDataLayout::TIMESTAMP);
m_timestamp.resize(data_layout->GetBlockSize(SharedDataLayout::TIMESTAMP));
std::copy(timestamp_ptr,
timestamp_ptr + data_layout->GetBlockSize(SharedDataLayout::TIMESTAMP),
m_timestamp.begin());
}
void LoadRTree()
{
BOOST_ASSERT_MSG(!m_coordinate_list->empty(), "coordinates must be loaded before r-tree");
RTreeNode *tree_ptr =
data_layout->GetBlockPtr<RTreeNode>(shared_memory, SharedDataLayout::R_SEARCH_TREE);
m_static_rtree.reset(new TimeStampedRTreePair(
CURRENT_TIMESTAMP,
osrm::make_unique<SharedRTree>(
tree_ptr, data_layout->num_entries[SharedDataLayout::R_SEARCH_TREE],
file_index_path, m_coordinate_list)));
}
void LoadGraph()
{
GraphNode *graph_nodes_ptr =
data_layout->GetBlockPtr<GraphNode>(shared_memory, SharedDataLayout::GRAPH_NODE_LIST);
GraphEdge *graph_edges_ptr =
data_layout->GetBlockPtr<GraphEdge>(shared_memory, SharedDataLayout::GRAPH_EDGE_LIST);
typename ShM<GraphNode, true>::vector node_list(
graph_nodes_ptr, data_layout->num_entries[SharedDataLayout::GRAPH_NODE_LIST]);
typename ShM<GraphEdge, true>::vector edge_list(
graph_edges_ptr, data_layout->num_entries[SharedDataLayout::GRAPH_EDGE_LIST]);
m_query_graph.reset(new QueryGraph(node_list, edge_list));
}
void LoadNodeAndEdgeInformation()
{
FixedPointCoordinate *coordinate_list_ptr = data_layout->GetBlockPtr<FixedPointCoordinate>(
shared_memory, SharedDataLayout::COORDINATE_LIST);
m_coordinate_list = osrm::make_unique<ShM<FixedPointCoordinate, true>::vector>(
coordinate_list_ptr, data_layout->num_entries[SharedDataLayout::COORDINATE_LIST]);
TravelMode *travel_mode_list_ptr =
data_layout->GetBlockPtr<TravelMode>(shared_memory, SharedDataLayout::TRAVEL_MODE);
typename ShM<TravelMode, true>::vector travel_mode_list(
travel_mode_list_ptr, data_layout->num_entries[SharedDataLayout::TRAVEL_MODE]);
m_travel_mode_list.swap(travel_mode_list);
TurnInstruction *turn_instruction_list_ptr = data_layout->GetBlockPtr<TurnInstruction>(
shared_memory, SharedDataLayout::TURN_INSTRUCTION);
typename ShM<TurnInstruction, true>::vector turn_instruction_list(
turn_instruction_list_ptr,
data_layout->num_entries[SharedDataLayout::TURN_INSTRUCTION]);
m_turn_instruction_list.swap(turn_instruction_list);
unsigned *name_id_list_ptr =
data_layout->GetBlockPtr<unsigned>(shared_memory, SharedDataLayout::NAME_ID_LIST);
typename ShM<unsigned, true>::vector name_id_list(
name_id_list_ptr, data_layout->num_entries[SharedDataLayout::NAME_ID_LIST]);
m_name_ID_list.swap(name_id_list);
}
void LoadViaNodeList()
{
NodeID *via_node_list_ptr =
data_layout->GetBlockPtr<NodeID>(shared_memory, SharedDataLayout::VIA_NODE_LIST);
typename ShM<NodeID, true>::vector via_node_list(
via_node_list_ptr, data_layout->num_entries[SharedDataLayout::VIA_NODE_LIST]);
m_via_node_list.swap(via_node_list);
}
void LoadNames()
{
unsigned *offsets_ptr =
data_layout->GetBlockPtr<unsigned>(shared_memory, SharedDataLayout::NAME_OFFSETS);
NameIndexBlock *blocks_ptr =
data_layout->GetBlockPtr<NameIndexBlock>(shared_memory, SharedDataLayout::NAME_BLOCKS);
typename ShM<unsigned, true>::vector name_offsets(
offsets_ptr, data_layout->num_entries[SharedDataLayout::NAME_OFFSETS]);
typename ShM<NameIndexBlock, true>::vector name_blocks(
blocks_ptr, data_layout->num_entries[SharedDataLayout::NAME_BLOCKS]);
char *names_list_ptr =
data_layout->GetBlockPtr<char>(shared_memory, SharedDataLayout::NAME_CHAR_LIST);
typename ShM<char, true>::vector names_char_list(
names_list_ptr, data_layout->num_entries[SharedDataLayout::NAME_CHAR_LIST]);
m_name_table = osrm::make_unique<RangeTable<16, true>>(
name_offsets, name_blocks, static_cast<unsigned>(names_char_list.size()));
m_names_char_list.swap(names_char_list);
}
void LoadGeometries()
{
unsigned *geometries_compressed_ptr = data_layout->GetBlockPtr<unsigned>(
shared_memory, SharedDataLayout::GEOMETRIES_INDICATORS);
typename ShM<bool, true>::vector edge_is_compressed(
geometries_compressed_ptr,
data_layout->num_entries[SharedDataLayout::GEOMETRIES_INDICATORS]);
m_edge_is_compressed.swap(edge_is_compressed);
unsigned *geometries_index_ptr =
data_layout->GetBlockPtr<unsigned>(shared_memory, SharedDataLayout::GEOMETRIES_INDEX);
typename ShM<unsigned, true>::vector geometry_begin_indices(
geometries_index_ptr, data_layout->num_entries[SharedDataLayout::GEOMETRIES_INDEX]);
m_geometry_indices.swap(geometry_begin_indices);
unsigned *geometries_list_ptr =
data_layout->GetBlockPtr<unsigned>(shared_memory, SharedDataLayout::GEOMETRIES_LIST);
typename ShM<unsigned, true>::vector geometry_list(
geometries_list_ptr, data_layout->num_entries[SharedDataLayout::GEOMETRIES_LIST]);
m_geometry_list.swap(geometry_list);
}
public:
virtual ~SharedDataFacade() {}
SharedDataFacade()
{
data_timestamp_ptr = (SharedDataTimestamp *)SharedMemoryFactory::Get(
CURRENT_REGIONS, sizeof(SharedDataTimestamp), false, false)->Ptr();
CURRENT_LAYOUT = LAYOUT_NONE;
CURRENT_DATA = DATA_NONE;
CURRENT_TIMESTAMP = 0;
// load data
CheckAndReloadFacade();
}
void CheckAndReloadFacade()
{
if (CURRENT_LAYOUT != data_timestamp_ptr->layout ||
CURRENT_DATA != data_timestamp_ptr->data ||
CURRENT_TIMESTAMP != data_timestamp_ptr->timestamp)
{
// release the previous shared memory segments
SharedMemory::Remove(CURRENT_LAYOUT);
SharedMemory::Remove(CURRENT_DATA);
CURRENT_LAYOUT = data_timestamp_ptr->layout;
CURRENT_DATA = data_timestamp_ptr->data;
CURRENT_TIMESTAMP = data_timestamp_ptr->timestamp;
m_layout_memory.reset(SharedMemoryFactory::Get(CURRENT_LAYOUT));
data_layout = (SharedDataLayout *)(m_layout_memory->Ptr());
m_large_memory.reset(SharedMemoryFactory::Get(CURRENT_DATA));
shared_memory = (char *)(m_large_memory->Ptr());
const char *file_index_ptr =
data_layout->GetBlockPtr<char>(shared_memory, SharedDataLayout::FILE_INDEX_PATH);
file_index_path = boost::filesystem::path(file_index_ptr);
if (!boost::filesystem::exists(file_index_path))
{
SimpleLogger().Write(logDEBUG) << "Leaf file name " << file_index_path.string();
throw osrm::exception("Could not load leaf index file."
"Is any data loaded into shared memory?");
}
LoadGraph();
LoadChecksum();
LoadNodeAndEdgeInformation();
LoadGeometries();
LoadTimestamp();
LoadViaNodeList();
LoadNames();
data_layout->PrintInformation();
SimpleLogger().Write() << "number of geometries: " << m_coordinate_list->size();
for (unsigned i = 0; i < m_coordinate_list->size(); ++i)
{
if (!GetCoordinateOfNode(i).is_valid())
{
SimpleLogger().Write() << "coordinate " << i << " not valid";
}
}
}
}
// search graph access
unsigned GetNumberOfNodes() const final { return m_query_graph->GetNumberOfNodes(); }
unsigned GetNumberOfEdges() const final { return m_query_graph->GetNumberOfEdges(); }
unsigned GetOutDegree(const NodeID n) const final { return m_query_graph->GetOutDegree(n); }
NodeID GetTarget(const EdgeID e) const final { return m_query_graph->GetTarget(e); }
EdgeDataT &GetEdgeData(const EdgeID e) const final { return m_query_graph->GetEdgeData(e); }
EdgeID BeginEdges(const NodeID n) const final { return m_query_graph->BeginEdges(n); }
EdgeID EndEdges(const NodeID n) const final { return m_query_graph->EndEdges(n); }
EdgeRange GetAdjacentEdgeRange(const NodeID node) const final
{
return m_query_graph->GetAdjacentEdgeRange(node);
};
// searches for a specific edge
EdgeID FindEdge(const NodeID from, const NodeID to) const final
{
return m_query_graph->FindEdge(from, to);
}
EdgeID FindEdgeInEitherDirection(const NodeID from, const NodeID to) const final
{
return m_query_graph->FindEdgeInEitherDirection(from, to);
}
EdgeID FindEdgeIndicateIfReverse(const NodeID from, const NodeID to, bool &result) const final
{
return m_query_graph->FindEdgeIndicateIfReverse(from, to, result);
}
// node and edge information access
FixedPointCoordinate GetCoordinateOfNode(const NodeID id) const final
{
return m_coordinate_list->at(id);
};
virtual bool EdgeIsCompressed(const unsigned id) const final
{
return m_edge_is_compressed.at(id);
}
virtual void GetUncompressedGeometry(const unsigned id,
std::vector<unsigned> &result_nodes) const final
{
const unsigned begin = m_geometry_indices.at(id);
const unsigned end = m_geometry_indices.at(id + 1);
result_nodes.clear();
result_nodes.insert(result_nodes.begin(), m_geometry_list.begin() + begin,
m_geometry_list.begin() + end);
}
virtual unsigned GetGeometryIndexForEdgeID(const unsigned id) const final
{
return m_via_node_list.at(id);
}
TurnInstruction GetTurnInstructionForEdgeID(const unsigned id) const final
{
return m_turn_instruction_list.at(id);
}
TravelMode GetTravelModeForEdgeID(const unsigned id) const { return m_travel_mode_list.at(id); }
bool LocateClosestEndPointForCoordinate(const FixedPointCoordinate &input_coordinate,
FixedPointCoordinate &result,
const unsigned zoom_level = 18) final
{
if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
{
LoadRTree();
}
return m_static_rtree->second->LocateClosestEndPointForCoordinate(input_coordinate, result,
zoom_level);
}
bool IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
PhantomNode &resulting_phantom_node) final
{
std::vector<PhantomNode> resulting_phantom_node_vector;
auto result = IncrementalFindPhantomNodeForCoordinate(input_coordinate,
resulting_phantom_node_vector, 1);
if (result)
{
BOOST_ASSERT(!resulting_phantom_node_vector.empty());
resulting_phantom_node = resulting_phantom_node_vector.front();
}
return result;
}
bool
IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
std::vector<PhantomNode> &resulting_phantom_node_vector,
const unsigned number_of_results) final
{
if (!m_static_rtree.get() || CURRENT_TIMESTAMP != m_static_rtree->first)
{
LoadRTree();
}
return m_static_rtree->second->IncrementalFindPhantomNodeForCoordinate(
input_coordinate, resulting_phantom_node_vector, number_of_results);
}
unsigned GetCheckSum() const final { return m_check_sum; }
unsigned GetNameIndexFromEdgeID(const unsigned id) const final
{
return m_name_ID_list.at(id);
};
void GetName(const unsigned name_id, std::string &result) const final
{
if (UINT_MAX == name_id)
{
result = "";
return;
}
auto range = m_name_table->GetRange(name_id);
result.clear();
if (range.begin() != range.end())
{
result.resize(range.back() - range.front() + 1);
std::copy(m_names_char_list.begin() + range.front(),
m_names_char_list.begin() + range.back() + 1, result.begin());
}
}
std::string GetTimestamp() const final { return m_timestamp; }
};
#endif // SHARED_DATAFACADE_HPP
+227
View File
@@ -0,0 +1,227 @@
/*
Copyright (c) 2015, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef SHARED_DATA_TYPE_HPP
#define SHARED_DATA_TYPE_HPP
#include "../../Util/osrm_exception.hpp"
#include "../../Util/simple_logger.hpp"
#include <cstdint>
#include <array>
namespace
{
// Added at the start and end of each block as sanity check
constexpr static const char CANARY[] = "OSRM";
}
struct SharedDataLayout
{
enum BlockID
{
NAME_OFFSETS = 0,
NAME_BLOCKS,
NAME_CHAR_LIST,
NAME_ID_LIST,
VIA_NODE_LIST,
GRAPH_NODE_LIST,
GRAPH_EDGE_LIST,
COORDINATE_LIST,
TURN_INSTRUCTION,
TRAVEL_MODE,
R_SEARCH_TREE,
GEOMETRIES_INDEX,
GEOMETRIES_LIST,
GEOMETRIES_INDICATORS,
HSGR_CHECKSUM,
TIMESTAMP,
FILE_INDEX_PATH,
NUM_BLOCKS
};
std::array<uint64_t, NUM_BLOCKS> num_entries;
std::array<uint64_t, NUM_BLOCKS> entry_size;
SharedDataLayout() : num_entries(), entry_size() {}
void PrintInformation() const
{
SimpleLogger().Write(logDEBUG) << "-";
SimpleLogger().Write(logDEBUG)
<< "name_offsets_size: " << num_entries[NAME_OFFSETS];
SimpleLogger().Write(logDEBUG)
<< "name_blocks_size: " << num_entries[NAME_BLOCKS];
SimpleLogger().Write(logDEBUG)
<< "name_char_list_size: " << num_entries[NAME_CHAR_LIST];
SimpleLogger().Write(logDEBUG)
<< "name_id_list_size: " << num_entries[NAME_ID_LIST];
SimpleLogger().Write(logDEBUG)
<< "via_node_list_size: " << num_entries[VIA_NODE_LIST];
SimpleLogger().Write(logDEBUG)
<< "graph_node_list_size: " << num_entries[GRAPH_NODE_LIST];
SimpleLogger().Write(logDEBUG)
<< "graph_edge_list_size: " << num_entries[GRAPH_EDGE_LIST];
SimpleLogger().Write(logDEBUG) << "timestamp_length: " << num_entries[TIMESTAMP];
SimpleLogger().Write(logDEBUG)
<< "coordinate_list_size: " << num_entries[COORDINATE_LIST];
SimpleLogger().Write(logDEBUG)
<< "turn_instruction_list_size: " << num_entries[TURN_INSTRUCTION];
SimpleLogger().Write(logDEBUG)
<< "travel_mode_list_size: " << num_entries[TRAVEL_MODE];
SimpleLogger().Write(logDEBUG)
<< "r_search_tree_size: " << num_entries[R_SEARCH_TREE];
SimpleLogger().Write(logDEBUG)
<< "geometries_indicators: " << num_entries[GEOMETRIES_INDICATORS] << "/"
<< ((num_entries[GEOMETRIES_INDICATORS] / 8) + 1);
SimpleLogger().Write(logDEBUG)
<< "geometries_index_list_size: " << num_entries[GEOMETRIES_INDEX];
SimpleLogger().Write(logDEBUG)
<< "geometries_list_size: " << num_entries[GEOMETRIES_LIST];
SimpleLogger().Write(logDEBUG)
<< "sizeof(checksum): " << entry_size[HSGR_CHECKSUM];
SimpleLogger().Write(logDEBUG) << "NAME_OFFSETS "
<< ": " << GetBlockSize(NAME_OFFSETS);
SimpleLogger().Write(logDEBUG) << "NAME_BLOCKS "
<< ": " << GetBlockSize(NAME_BLOCKS);
SimpleLogger().Write(logDEBUG) << "NAME_CHAR_LIST "
<< ": " << GetBlockSize(NAME_CHAR_LIST);
SimpleLogger().Write(logDEBUG) << "NAME_ID_LIST "
<< ": " << GetBlockSize(NAME_ID_LIST);
SimpleLogger().Write(logDEBUG) << "VIA_NODE_LIST "
<< ": " << GetBlockSize(VIA_NODE_LIST);
SimpleLogger().Write(logDEBUG) << "GRAPH_NODE_LIST "
<< ": " << GetBlockSize(GRAPH_NODE_LIST);
SimpleLogger().Write(logDEBUG) << "GRAPH_EDGE_LIST "
<< ": " << GetBlockSize(GRAPH_EDGE_LIST);
SimpleLogger().Write(logDEBUG) << "COORDINATE_LIST "
<< ": " << GetBlockSize(COORDINATE_LIST);
SimpleLogger().Write(logDEBUG) << "TURN_INSTRUCTION "
<< ": " << GetBlockSize(TURN_INSTRUCTION);
SimpleLogger().Write(logDEBUG) << "TRAVEL_MODE "
<< ": " << GetBlockSize(TRAVEL_MODE);
SimpleLogger().Write(logDEBUG) << "R_SEARCH_TREE "
<< ": " << GetBlockSize(R_SEARCH_TREE);
SimpleLogger().Write(logDEBUG) << "GEOMETRIES_INDEX "
<< ": " << GetBlockSize(GEOMETRIES_INDEX);
SimpleLogger().Write(logDEBUG) << "GEOMETRIES_LIST "
<< ": " << GetBlockSize(GEOMETRIES_LIST);
SimpleLogger().Write(logDEBUG) << "GEOMETRIES_INDICATORS"
<< ": " << GetBlockSize(GEOMETRIES_INDICATORS);
SimpleLogger().Write(logDEBUG) << "HSGR_CHECKSUM "
<< ": " << GetBlockSize(HSGR_CHECKSUM);
SimpleLogger().Write(logDEBUG) << "TIMESTAMP "
<< ": " << GetBlockSize(TIMESTAMP);
SimpleLogger().Write(logDEBUG) << "FILE_INDEX_PATH "
<< ": " << GetBlockSize(FILE_INDEX_PATH);
}
template <typename T> inline void SetBlockSize(BlockID bid, uint64_t entries)
{
num_entries[bid] = entries;
entry_size[bid] = sizeof(T);
}
inline uint64_t GetBlockSize(BlockID bid) const
{
// special encoding
if (bid == GEOMETRIES_INDICATORS)
{
return (num_entries[GEOMETRIES_INDICATORS] / 32 + 1) *
entry_size[GEOMETRIES_INDICATORS];
}
return num_entries[bid] * entry_size[bid];
}
inline uint64_t GetSizeOfLayout() const
{
return GetBlockOffset(NUM_BLOCKS) + NUM_BLOCKS * 2 * sizeof(CANARY);
}
inline uint64_t GetBlockOffset(BlockID bid) const
{
uint64_t result = sizeof(CANARY);
for (auto i = 0; i < bid; i++)
{
result += GetBlockSize((BlockID)i) + 2 * sizeof(CANARY);
}
return result;
}
template <typename T, bool WRITE_CANARY = false>
inline T *GetBlockPtr(char *shared_memory, BlockID bid)
{
T *ptr = (T *)(shared_memory + GetBlockOffset(bid));
if (WRITE_CANARY)
{
char *start_canary_ptr = shared_memory + GetBlockOffset(bid) - sizeof(CANARY);
char *end_canary_ptr = shared_memory + GetBlockOffset(bid) + GetBlockSize(bid);
std::copy(CANARY, CANARY + sizeof(CANARY), start_canary_ptr);
std::copy(CANARY, CANARY + sizeof(CANARY), end_canary_ptr);
}
else
{
char *start_canary_ptr = shared_memory + GetBlockOffset(bid) - sizeof(CANARY);
char *end_canary_ptr = shared_memory + GetBlockOffset(bid) + GetBlockSize(bid);
bool start_canary_alive = std::equal(CANARY, CANARY + sizeof(CANARY), start_canary_ptr);
bool end_canary_alive = std::equal(CANARY, CANARY + sizeof(CANARY), end_canary_ptr);
if (!start_canary_alive)
{
throw osrm::exception("Start canary of block corrupted.");
}
if (!end_canary_alive)
{
throw osrm::exception("End canary of block corrupted.");
}
}
return ptr;
}
};
enum SharedDataType
{
CURRENT_REGIONS,
LAYOUT_1,
DATA_1,
LAYOUT_2,
DATA_2,
LAYOUT_NONE,
DATA_NONE
};
struct SharedDataTimestamp
{
SharedDataType layout;
SharedDataType data;
unsigned timestamp;
};
#endif /* SHARED_DATA_TYPE_HPP */
+42
View File
@@ -0,0 +1,42 @@
/*
Copyright (c) 2015, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef COMPRESSION_TYPE_HPP
#define COMPRESSION_TYPE_HPP
namespace http
{
enum compression_type
{
no_compression,
gzip_rfc1952,
deflate_rfc1951
};
}
#endif // COMPRESSION_TYPE_HPP
+54
View File
@@ -0,0 +1,54 @@
/*
Copyright (c) 2015, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef HEADER_HPP
#define HEADER_HPP
#include <string>
#include <algorithm>
namespace http
{
struct header
{
// explicitly use default copy c'tor as adding move c'tor
header &operator=(const header &other) = default;
header(const std::string &name, const std::string &value) : name(name), value(value) {}
header(header &&other) : name(std::move(other.name)), value(std::move(other.value)) {}
void clear()
{
name.clear();
value.clear();
}
std::string name;
std::string value;
};
}
#endif // HEADER_HPP
+130
View File
@@ -0,0 +1,130 @@
/*
Copyright (c) 2015, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "reply.hpp"
#include "../../Util/cast.hpp"
namespace http
{
const char ok_html[] = "";
const char bad_request_html[] = "{\"status\": 400,\"status_message\":\"Bad Request\"}";
const char internal_server_error_html[] =
"{\"status\": 500,\"status_message\":\"Internal Server Error\"}";
const char seperators[] = {':', ' '};
const char crlf[] = {'\r', '\n'};
const std::string http_ok_string = "HTTP/1.0 200 OK\r\n";
const std::string http_bad_request_string = "HTTP/1.0 400 Bad Request\r\n";
const std::string http_internal_server_error_string = "HTTP/1.0 500 Internal Server Error\r\n";
void reply::set_size(const std::size_t size)
{
for (header &h : headers)
{
if ("Content-Length" == h.name)
{
h.value = cast::integral_to_string(size);
}
}
}
void reply::set_uncompressed_size() { set_size(content.size()); }
std::vector<boost::asio::const_buffer> reply::to_buffers()
{
std::vector<boost::asio::const_buffer> buffers;
buffers.push_back(status_to_buffer(status));
for (const header &h : headers)
{
buffers.push_back(boost::asio::buffer(h.name));
buffers.push_back(boost::asio::buffer(seperators));
buffers.push_back(boost::asio::buffer(h.value));
buffers.push_back(boost::asio::buffer(crlf));
}
buffers.push_back(boost::asio::buffer(crlf));
buffers.push_back(boost::asio::buffer(content));
return buffers;
}
std::vector<boost::asio::const_buffer> reply::headers_to_buffers()
{
std::vector<boost::asio::const_buffer> buffers;
buffers.push_back(status_to_buffer(status));
for (const header &current_header : headers)
{
buffers.push_back(boost::asio::buffer(current_header.name));
buffers.push_back(boost::asio::buffer(seperators));
buffers.push_back(boost::asio::buffer(current_header.value));
buffers.push_back(boost::asio::buffer(crlf));
}
buffers.push_back(boost::asio::buffer(crlf));
return buffers;
}
reply reply::stock_reply(const reply::status_type status)
{
reply reply;
reply.status = status;
reply.content.clear();
const std::string status_string = reply.status_to_string(status);
reply.content.insert(reply.content.end(), status_string.begin(), status_string.end());
reply.headers.emplace_back("Access-Control-Allow-Origin", "*");
reply.headers.emplace_back("Content-Length", cast::integral_to_string(reply.content.size()));
reply.headers.emplace_back("Content-Type", "text/html");
return reply;
}
std::string reply::status_to_string(const reply::status_type status)
{
if (reply::ok == status)
{
return ok_html;
}
if (reply::bad_request == status)
{
return bad_request_html;
}
return internal_server_error_html;
}
boost::asio::const_buffer reply::status_to_buffer(const reply::status_type status)
{
if (reply::ok == status)
{
return boost::asio::buffer(http_ok_string);
}
if (reply::internal_server_error == status)
{
return boost::asio::buffer(http_internal_server_error_string);
}
return boost::asio::buffer(http_bad_request_string);
}
reply::reply() : status(ok) {}
}
+65
View File
@@ -0,0 +1,65 @@
/*
Copyright (c) 2015, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef REPLY_HPP
#define REPLY_HPP
#include "header.hpp"
#include <boost/asio.hpp>
#include <vector>
namespace http
{
class reply
{
public:
enum status_type
{
ok = 200,
bad_request = 400,
internal_server_error = 500
} status;
std::vector<header> headers;
std::vector<boost::asio::const_buffer> to_buffers();
std::vector<boost::asio::const_buffer> headers_to_buffers();
std::vector<char> content;
static reply stock_reply(const status_type status);
void set_size(const std::size_t size);
void set_uncompressed_size();
reply();
private:
std::string status_to_string(reply::status_type status);
boost::asio::const_buffer status_to_buffer(reply::status_type status);
};
}
#endif // REPLY_HPP
+48
View File
@@ -0,0 +1,48 @@
/*
Copyright (c) 2015, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef REQUEST_HPP
#define REQUEST_HPP
#include <boost/asio.hpp>
#include <string>
namespace http
{
struct request
{
std::string uri;
std::string referrer;
std::string agent;
boost::asio::ip::address endpoint;
};
} // namespace http
#endif // REQUEST_HPP
+169
View File
@@ -0,0 +1,169 @@
/*
Copyright (c) 2015, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "request_handler.hpp"
#include "api_grammar.hpp"
#include "http/reply.hpp"
#include "http/request.hpp"
#include "../Library/OSRM.h"
#include "../Util/json_renderer.hpp"
#include "../Util/simple_logger.hpp"
#include "../Util/string_util.hpp"
#include "../Util/xml_renderer.hpp"
#include "../typedefs.h"
#include <osrm/route_parameters.hpp>
#include <osrm/json_container.hpp>
#include <ctime>
#include <algorithm>
#include <iostream>
RequestHandler::RequestHandler() : routing_machine(nullptr) {}
void RequestHandler::handle_request(const http::request &current_request,
http::reply &current_reply)
{
// parse command
try
{
std::string request_string;
URIDecode(current_request.uri, request_string);
// deactivated as GCC apparently does not implement that, not even in 4.9
// std::time_t t = std::time(nullptr);
// SimpleLogger().Write() << std::put_time(std::localtime(&t), "%m-%d-%Y %H:%M:%S") <<
// " " << current_request.endpoint.to_string() << " " <<
// current_request.referrer << ( 0 == current_request.referrer.length() ? "- " :" ") <<
// current_request.agent << ( 0 == current_request.agent.length() ? "- " :" ") <<
// request;
time_t ltime;
struct tm *time_stamp;
ltime = time(nullptr);
time_stamp = localtime(&ltime);
// log timestamp
SimpleLogger().Write() << (time_stamp->tm_mday < 10 ? "0" : "") << time_stamp->tm_mday
<< "-" << (time_stamp->tm_mon + 1 < 10 ? "0" : "")
<< (time_stamp->tm_mon + 1) << "-" << 1900 + time_stamp->tm_year
<< " " << (time_stamp->tm_hour < 10 ? "0" : "")
<< time_stamp->tm_hour << ":" << (time_stamp->tm_min < 10 ? "0" : "")
<< time_stamp->tm_min << ":" << (time_stamp->tm_sec < 10 ? "0" : "")
<< time_stamp->tm_sec << " " << current_request.endpoint.to_string()
<< " " << current_request.referrer
<< (0 == current_request.referrer.length() ? "- " : " ")
<< current_request.agent
<< (0 == current_request.agent.length() ? "- " : " ")
<< request_string;
RouteParameters route_parameters;
APIGrammarParser api_parser(&route_parameters);
auto api_iterator = request_string.begin();
const bool result =
boost::spirit::qi::parse(api_iterator, request_string.end(), api_parser);
JSON::Object json_result;
// check if the was an error with the request
if (!result || (api_iterator != request_string.end()))
{
current_reply = http::reply::stock_reply(http::reply::bad_request);
current_reply.content.clear();
const auto position = std::distance(request_string.begin(), api_iterator);
json_result.values["status"] = 400;
std::string message = "Query string malformed close to position ";
message += cast::integral_to_string(position);
json_result.values["status_message"] = message;
JSON::render(current_reply.content, json_result);
return;
}
// parsing done, lets call the right plugin to handle the request
BOOST_ASSERT_MSG(routing_machine != nullptr, "pointer not init'ed");
if (!route_parameters.jsonp_parameter.empty())
{ // prepend response with jsonp parameter
const std::string json_p = (route_parameters.jsonp_parameter + "(");
current_reply.content.insert(current_reply.content.end(), json_p.begin(), json_p.end());
}
const auto return_code = routing_machine->RunQuery(route_parameters, json_result);
if (200 != return_code)
{
current_reply = http::reply::stock_reply(http::reply::bad_request);
current_reply.content.clear();
json_result.values["status"] = 400;
std::string message = "Bad Request";
json_result.values["status_message"] = message;
JSON::render(current_reply.content, json_result);
return;
}
// set headers
current_reply.headers.emplace_back("Content-Length",
cast::integral_to_string(current_reply.content.size()));
if ("gpx" == route_parameters.output_format)
{ // gpx file
JSON::gpx_render(current_reply.content, json_result.values["route"]);
current_reply.headers.emplace_back("Content-Type",
"application/gpx+xml; charset=UTF-8");
current_reply.headers.emplace_back("Content-Disposition",
"attachment; filename=\"route.gpx\"");
}
else if (route_parameters.jsonp_parameter.empty())
{ // json file
JSON::render(current_reply.content, json_result);
current_reply.headers.emplace_back("Content-Type", "application/json; charset=UTF-8");
current_reply.headers.emplace_back("Content-Disposition",
"inline; filename=\"response.json\"");
}
else
{ // jsonp
JSON::render(current_reply.content, json_result);
current_reply.headers.emplace_back("Content-Type", "text/javascript; charset=UTF-8");
current_reply.headers.emplace_back("Content-Disposition",
"inline; filename=\"response.js\"");
}
if (!route_parameters.jsonp_parameter.empty())
{ // append brace to jsonp response
current_reply.content.push_back(')');
}
}
catch (const std::exception &e)
{
current_reply = http::reply::stock_reply(http::reply::internal_server_error);
SimpleLogger().Write(logWARNING) << "[server error] code: " << e.what()
<< ", uri: " << current_request.uri;
return;
}
}
void RequestHandler::RegisterRoutingMachine(OSRM *osrm) { routing_machine = osrm; }
+59
View File
@@ -0,0 +1,59 @@
/*
Copyright (c) 2015, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef REQUEST_HANDLER_HPP
#define REQUEST_HANDLER_HPP
#include <string>
template <typename Iterator, class HandlerT> struct APIGrammar;
struct RouteParameters;
class OSRM;
namespace http
{
class reply;
struct request;
}
class RequestHandler
{
public:
using APIGrammarParser = APIGrammar<std::string::iterator, RouteParameters>;
RequestHandler();
RequestHandler(const RequestHandler &) = delete;
void handle_request(const http::request &current_request, http::reply &current_reply);
void RegisterRoutingMachine(OSRM *osrm);
private:
OSRM *routing_machine;
};
#endif // REQUEST_HANDLER_HPP
+316
View File
@@ -0,0 +1,316 @@
/*
Copyright (c) 2015, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "request_parser.hpp"
#include "http/request.hpp"
#include <boost/algorithm/string/predicate.hpp>
namespace http
{
RequestParser::RequestParser()
: state(internal_state::method_start), header({"", ""}), compression_type(no_compression)
{
}
std::tuple<osrm::tribool, compression_type>
RequestParser::parse(request &current_request, char *begin, char *end)
{
while (begin != end)
{
osrm::tribool result = consume(current_request, *begin++);
if (result != osrm::tribool::indeterminate)
{
return std::make_tuple(result, compression_type);
}
}
osrm::tribool result = osrm::tribool::indeterminate;
return std::make_tuple(result, compression_type);
}
osrm::tribool RequestParser::consume(request &current_request, const char input)
{
switch (state)
{
case internal_state::method_start:
if (!is_char(input) || is_CTL(input) || is_special(input))
{
return osrm::tribool::no;
}
state = internal_state::method;
return osrm::tribool::indeterminate;
case internal_state::method:
if (input == ' ')
{
state = internal_state::uri;
return osrm::tribool::indeterminate;
}
if (!is_char(input) || is_CTL(input) || is_special(input))
{
return osrm::tribool::no;
}
return osrm::tribool::indeterminate;
case internal_state::uri_start:
if (is_CTL(input))
{
return osrm::tribool::no;
}
state = internal_state::uri;
current_request.uri.push_back(input);
return osrm::tribool::indeterminate;
case internal_state::uri:
if (input == ' ')
{
state = internal_state::http_version_h;
return osrm::tribool::indeterminate;
}
if (is_CTL(input))
{
return osrm::tribool::no;
}
current_request.uri.push_back(input);
return osrm::tribool::indeterminate;
case internal_state::http_version_h:
if (input == 'H')
{
state = internal_state::http_version_t_1;
return osrm::tribool::indeterminate;
}
return osrm::tribool::no;
case internal_state::http_version_t_1:
if (input == 'T')
{
state = internal_state::http_version_t_2;
return osrm::tribool::indeterminate;
}
return osrm::tribool::no;
case internal_state::http_version_t_2:
if (input == 'T')
{
state = internal_state::http_version_p;
return osrm::tribool::indeterminate;
}
return osrm::tribool::no;
case internal_state::http_version_p:
if (input == 'P')
{
state = internal_state::http_version_slash;
return osrm::tribool::indeterminate;
}
return osrm::tribool::no;
case internal_state::http_version_slash:
if (input == '/')
{
state = internal_state::http_version_major_start;
return osrm::tribool::indeterminate;
}
return osrm::tribool::no;
case internal_state::http_version_major_start:
if (is_digit(input))
{
state = internal_state::http_version_major;
return osrm::tribool::indeterminate;
}
return osrm::tribool::no;
case internal_state::http_version_major:
if (input == '.')
{
state = internal_state::http_version_minor_start;
return osrm::tribool::indeterminate;
}
if (is_digit(input))
{
return osrm::tribool::indeterminate;
}
return osrm::tribool::no;
case internal_state::http_version_minor_start:
if (is_digit(input))
{
state = internal_state::http_version_minor;
return osrm::tribool::indeterminate;
}
return osrm::tribool::no;
case internal_state::http_version_minor:
if (input == '\r')
{
state = internal_state::expecting_newline_1;
return osrm::tribool::indeterminate;
}
if (is_digit(input))
{
return osrm::tribool::indeterminate;
}
return osrm::tribool::no;
case internal_state::expecting_newline_1:
if (input == '\n')
{
state = internal_state::header_line_start;
return osrm::tribool::indeterminate;
}
return osrm::tribool::no;
case internal_state::header_line_start:
if (boost::iequals(header.name, "Accept-Encoding"))
{
/* giving gzip precedence over deflate */
if (boost::icontains(header.value, "deflate"))
{
compression_type = deflate_rfc1951;
}
if (boost::icontains(header.value, "gzip"))
{
compression_type = gzip_rfc1952;
}
}
if (boost::iequals(header.name, "Referer"))
{
current_request.referrer = header.value;
}
if (boost::iequals(header.name, "User-Agent"))
{
current_request.agent = header.value;
}
if (input == '\r')
{
state = internal_state::expecting_newline_3;
return osrm::tribool::indeterminate;
}
if (!is_char(input) || is_CTL(input) || is_special(input))
{
return osrm::tribool::no;
}
state = internal_state::header_name;
header.clear();
header.name.push_back(input);
return osrm::tribool::indeterminate;
case internal_state::header_lws:
if (input == '\r')
{
state = internal_state::expecting_newline_2;
return osrm::tribool::indeterminate;
}
if (input == ' ' || input == '\t')
{
return osrm::tribool::indeterminate;
}
if (is_CTL(input))
{
return osrm::tribool::no;
}
state = internal_state::header_value;
return osrm::tribool::indeterminate;
case internal_state::header_name:
if (input == ':')
{
state = internal_state::space_before_header_value;
return osrm::tribool::indeterminate;
}
if (!is_char(input) || is_CTL(input) || is_special(input))
{
return osrm::tribool::no;
}
header.name.push_back(input);
return osrm::tribool::indeterminate;
case internal_state::space_before_header_value:
if (input == ' ')
{
state = internal_state::header_value;
return osrm::tribool::indeterminate;
}
return osrm::tribool::no;
case internal_state::header_value:
if (input == '\r')
{
state = internal_state::expecting_newline_2;
return osrm::tribool::indeterminate;
}
if (is_CTL(input))
{
return osrm::tribool::no;
}
header.value.push_back(input);
return osrm::tribool::indeterminate;
case internal_state::expecting_newline_2:
if (input == '\n')
{
state = internal_state::header_line_start;
return osrm::tribool::indeterminate;
}
return osrm::tribool::no;
default: // expecting_newline_3
return (input == '\n' ? osrm::tribool::yes : osrm::tribool::no);
}
}
bool RequestParser::is_char(const int character) const
{
return character >= 0 && character <= 127;
}
bool RequestParser::is_CTL(const int character) const
{
return (character >= 0 && character <= 31) || (character == 127);
}
bool RequestParser::is_special(const int character) const
{
switch (character)
{
case '(':
case ')':
case '<':
case '>':
case '@':
case ',':
case ';':
case ':':
case '\\':
case '"':
case '/':
case '[':
case ']':
case '?':
case '=':
case '{':
case '}':
case ' ':
case '\t':
return true;
default:
return false;
}
}
bool RequestParser::is_digit(const int character) const
{
return character >= '0' && character <= '9';
}
}
+92
View File
@@ -0,0 +1,92 @@
/*
Copyright (c) 2015, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef REQUEST_PARSER_HPP
#define REQUEST_PARSER_HPP
#include "http/compression_type.hpp"
#include "http/header.hpp"
#include "../data_structures/tribool.hpp"
#include <tuple>
namespace http
{
struct request;
class RequestParser
{
public:
RequestParser();
std::tuple<osrm::tribool, compression_type>
parse(request &current_request, char *begin, char *end);
private:
osrm::tribool consume(request &current_request, const char input);
bool is_char(const int character) const;
bool is_CTL(const int character) const;
bool is_special(const int character) const;
bool is_digit(const int character) const;
enum class internal_state : unsigned char
{
method_start,
method,
uri_start,
uri,
http_version_h,
http_version_t_1,
http_version_t_2,
http_version_p,
http_version_slash,
http_version_major_start,
http_version_major,
http_version_minor_start,
http_version_minor,
expecting_newline_1,
header_line_start,
header_lws,
header_name,
space_before_header_value,
header_value,
expecting_newline_2,
expecting_newline_3
} state;
header header;
compression_type compression_type;
};
} // namespace http
#endif // REQUEST_PARSER_HPP
+119
View File
@@ -0,0 +1,119 @@
/*
Copyright (c) 2015, Project OSRM, Dennis Luxen, others
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef SERVER_HPP
#define SERVER_HPP
#include "connection.hpp"
#include "request_handler.hpp"
#include "../Util/cast.hpp"
#include "../Util/integer_range.hpp"
#include "../Util/simple_logger.hpp"
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <zlib.h>
#include <functional>
#include <memory>
#include <thread>
#include <vector>
class Server
{
public:
// Note: returns a shared instead of a unique ptr as it is captured in a lambda somewhere else
static std::shared_ptr<Server>
CreateServer(std::string &ip_address, int ip_port, unsigned requested_num_threads)
{
SimpleLogger().Write() << "http 1.1 compression handled by zlib version " << zlibVersion();
const unsigned hardware_threads = std::max(1u, std::thread::hardware_concurrency());
const unsigned real_num_threads = std::min(hardware_threads, requested_num_threads);
return std::make_shared<Server>(ip_address, ip_port, real_num_threads);
}
explicit Server(const std::string &address, const int port, const unsigned thread_pool_size)
: thread_pool_size(thread_pool_size), acceptor(io_service),
new_connection(std::make_shared<http::Connection>(io_service, request_handler))
{
const std::string port_string = cast::integral_to_string(port);
boost::asio::ip::tcp::resolver resolver(io_service);
boost::asio::ip::tcp::resolver::query query(address, port_string);
boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query);
acceptor.open(endpoint.protocol());
acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
acceptor.bind(endpoint);
acceptor.listen();
acceptor.async_accept(
new_connection->socket(),
boost::bind(&Server::HandleAccept, this, boost::asio::placeholders::error));
}
void Run()
{
std::vector<std::shared_ptr<std::thread>> threads;
for (unsigned i = 0; i < thread_pool_size; ++i)
{
std::shared_ptr<std::thread> thread = std::make_shared<std::thread>(
boost::bind(&boost::asio::io_service::run, &io_service));
threads.push_back(thread);
}
for (auto thread : threads)
{
thread->join();
}
}
void Stop() { io_service.stop(); }
RequestHandler &GetRequestHandlerPtr() { return request_handler; }
private:
void HandleAccept(const boost::system::error_code &e)
{
if (!e)
{
new_connection->start();
new_connection = std::make_shared<http::Connection>(io_service, request_handler);
acceptor.async_accept(
new_connection->socket(),
boost::bind(&Server::HandleAccept, this, boost::asio::placeholders::error));
}
}
unsigned thread_pool_size;
boost::asio::io_service io_service;
boost::asio::ip::tcp::acceptor acceptor;
std::shared_ptr<http::Connection> new_connection;
RequestHandler request_handler;
};
#endif // SERVER_HPP