This is a large update that brings many internal and architectural changes. The most obvious change to the user is the presence of configuration files for extractLargeNetwork and routed. Optimistically speaking, it should not break anything. Thanks to rskr for support patches and suggestions.
This commit is contained in:
parent
f45af2ba72
commit
bfd2a8aee2
@ -2,6 +2,4 @@ The following people contributed code to the Open Source Routing Machine:
|
||||
|
||||
Christian Vetter
|
||||
Dennis Luxen
|
||||
|
||||
Note:
|
||||
http server ripped from Boost http example 3
|
||||
Ruslan Krenzler
|
@ -301,7 +301,7 @@ public:
|
||||
_LogData log;
|
||||
Percent p (numberOfNodes);
|
||||
|
||||
int maxThreads = omp_get_max_threads();
|
||||
unsigned maxThreads = omp_get_max_threads();
|
||||
std::vector < _ThreadData* > threadData;
|
||||
for ( int threadNum = 0; threadNum < maxThreads; ++threadNum ) {
|
||||
threadData.push_back( new _ThreadData( numberOfNodes ) );
|
||||
|
274
DataStructures/BinaryHeap.h
Normal file
274
DataStructures/BinaryHeap.h
Normal file
@ -0,0 +1,274 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef BINARYHEAP_H_INCLUDED
|
||||
#define BINARYHEAP_H_INCLUDED
|
||||
|
||||
//Not compatible with non contiguous node ids
|
||||
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <google/dense_hash_map>
|
||||
#include <google/sparse_hash_map>
|
||||
|
||||
template< typename NodeID, typename Key >
|
||||
class ArrayStorage {
|
||||
public:
|
||||
|
||||
ArrayStorage( size_t size )
|
||||
: positions( new Key[size] ) {}
|
||||
|
||||
~ArrayStorage() {
|
||||
delete[] positions;
|
||||
}
|
||||
|
||||
Key &operator[]( NodeID node ) {
|
||||
return positions[node];
|
||||
}
|
||||
|
||||
void Clear() {}
|
||||
|
||||
private:
|
||||
Key* positions;
|
||||
};
|
||||
|
||||
template< typename NodeID, typename Key >
|
||||
class MapStorage {
|
||||
public:
|
||||
|
||||
MapStorage( size_t size = 0 ) {}
|
||||
|
||||
Key &operator[]( NodeID node ) {
|
||||
return nodes[node];
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
nodes.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
std::map< NodeID, Key > nodes;
|
||||
|
||||
};
|
||||
|
||||
template< typename NodeID, typename Key >
|
||||
class DenseStorage {
|
||||
public:
|
||||
|
||||
DenseStorage( size_t size = 0 ) { nodes.set_empty_key(UINT_MAX); }
|
||||
|
||||
Key &operator[]( NodeID node ) {
|
||||
return nodes[node];
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
nodes.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
google::dense_hash_map< NodeID, Key > nodes;
|
||||
};
|
||||
|
||||
template< typename NodeID, typename Key >
|
||||
class SparseStorage {
|
||||
public:
|
||||
|
||||
SparseStorage( size_t size = 0 ) { }
|
||||
|
||||
Key &operator[]( NodeID node ) {
|
||||
return nodes[node];
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
nodes.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
google::sparse_hash_map< NodeID, Key > nodes;
|
||||
};
|
||||
|
||||
|
||||
template < typename NodeID, typename Key, typename Weight, typename Data, typename IndexStorage = ArrayStorage< NodeID, Key > >
|
||||
class BinaryHeap {
|
||||
private:
|
||||
BinaryHeap( const BinaryHeap& right );
|
||||
void operator=( const BinaryHeap& right );
|
||||
public:
|
||||
typedef Weight WeightType;
|
||||
typedef Data DataType;
|
||||
|
||||
BinaryHeap( size_t maxID )
|
||||
: nodeIndex( maxID ) {
|
||||
Clear();
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
heap.resize( 1 );
|
||||
insertedNodes.clear();
|
||||
heap[0].weight = 0;
|
||||
nodeIndex.Clear();
|
||||
}
|
||||
|
||||
Key Size() const {
|
||||
return ( Key )( heap.size() - 1 );
|
||||
}
|
||||
|
||||
void Insert( NodeID node, Weight weight, const Data &data ) {
|
||||
HeapElement element;
|
||||
element.index = ( NodeID ) insertedNodes.size();
|
||||
element.weight = weight;
|
||||
const Key key = ( Key ) heap.size();
|
||||
heap.push_back( element );
|
||||
insertedNodes.push_back( HeapNode( node, key, weight, data ) );
|
||||
nodeIndex[node] = element.index;
|
||||
Upheap( key );
|
||||
CheckHeap();
|
||||
}
|
||||
|
||||
Data& GetData( NodeID node ) {
|
||||
const Key index = nodeIndex[node];
|
||||
return insertedNodes[index].data;
|
||||
}
|
||||
|
||||
Weight& GetKey( NodeID node ) {
|
||||
const Key index = nodeIndex[node];
|
||||
return insertedNodes[index].weight;
|
||||
}
|
||||
|
||||
bool WasRemoved( NodeID node ) {
|
||||
assert( WasInserted( node ) );
|
||||
const Key index = nodeIndex[node];
|
||||
return insertedNodes[index].key == 0;
|
||||
}
|
||||
|
||||
bool WasInserted( NodeID node ) {
|
||||
const Key index = nodeIndex[node];
|
||||
if ( index >= ( Key ) insertedNodes.size() )
|
||||
return false;
|
||||
return insertedNodes[index].node == node;
|
||||
}
|
||||
|
||||
NodeID Min() const {
|
||||
assert( heap.size() > 1 );
|
||||
return insertedNodes[heap[1].index].node;
|
||||
}
|
||||
|
||||
NodeID DeleteMin() {
|
||||
assert( heap.size() > 1 );
|
||||
const Key removedIndex = heap[1].index;
|
||||
heap[1] = heap[heap.size()-1];
|
||||
heap.pop_back();
|
||||
if ( heap.size() > 1 )
|
||||
Downheap( 1 );
|
||||
insertedNodes[removedIndex].key = 0;
|
||||
CheckHeap();
|
||||
return insertedNodes[removedIndex].node;
|
||||
}
|
||||
|
||||
void DeleteAll() {
|
||||
for ( typename std::vector< HeapElement >::iterator i = heap.begin() + 1, iend = heap.end(); i != iend; ++i )
|
||||
insertedNodes[i->index].key = 0;
|
||||
heap.resize( 1 );
|
||||
heap[0].weight = 0;
|
||||
}
|
||||
|
||||
void DecreaseKey( NodeID node, Weight weight ) {
|
||||
const Key index = nodeIndex[node];
|
||||
Key key = insertedNodes[index].key;
|
||||
assert ( key != 0 );
|
||||
|
||||
insertedNodes[index].weight = weight;
|
||||
heap[key].weight = weight;
|
||||
Upheap( key );
|
||||
CheckHeap();
|
||||
}
|
||||
|
||||
private:
|
||||
class HeapNode {
|
||||
public:
|
||||
HeapNode() {
|
||||
}
|
||||
HeapNode( NodeID n, Key k, Weight w, Data d )
|
||||
: node( n ), key( k ), weight( w ), data( d ) {
|
||||
}
|
||||
|
||||
NodeID node;
|
||||
Key key;
|
||||
Weight weight;
|
||||
Data data;
|
||||
};
|
||||
struct HeapElement {
|
||||
Key index;
|
||||
Weight weight;
|
||||
};
|
||||
|
||||
std::vector< HeapNode > insertedNodes;
|
||||
std::vector< HeapElement > heap;
|
||||
IndexStorage nodeIndex;
|
||||
|
||||
void Downheap( Key key ) {
|
||||
const Key droppingIndex = heap[key].index;
|
||||
const Weight weight = heap[key].weight;
|
||||
Key nextKey = key << 1;
|
||||
while ( nextKey < ( Key ) heap.size() ) {
|
||||
const Key nextKeyOther = nextKey + 1;
|
||||
if ( ( nextKeyOther < ( Key ) heap.size() ) )
|
||||
if ( heap[nextKey].weight > heap[nextKeyOther].weight )
|
||||
nextKey = nextKeyOther;
|
||||
|
||||
if ( weight <= heap[nextKey].weight )
|
||||
break;
|
||||
|
||||
heap[key] = heap[nextKey];
|
||||
insertedNodes[heap[key].index].key = key;
|
||||
key = nextKey;
|
||||
nextKey <<= 1;
|
||||
}
|
||||
heap[key].index = droppingIndex;
|
||||
heap[key].weight = weight;
|
||||
insertedNodes[droppingIndex].key = key;
|
||||
}
|
||||
|
||||
void Upheap( Key key ) {
|
||||
const Key risingIndex = heap[key].index;
|
||||
const Weight weight = heap[key].weight;
|
||||
Key nextKey = key >> 1;
|
||||
while ( heap[nextKey].weight > weight ) {
|
||||
assert( nextKey != 0 );
|
||||
heap[key] = heap[nextKey];
|
||||
insertedNodes[heap[key].index].key = key;
|
||||
key = nextKey;
|
||||
nextKey >>= 1;
|
||||
}
|
||||
heap[key].index = risingIndex;
|
||||
heap[key].weight = weight;
|
||||
insertedNodes[risingIndex].key = key;
|
||||
}
|
||||
|
||||
void CheckHeap() {
|
||||
/*for ( Key i = 2; i < heap.size(); ++i ) {
|
||||
assert( heap[i].weight >= heap[i >> 1].weight );
|
||||
}*/
|
||||
}
|
||||
};
|
||||
|
||||
#endif //#ifndef BINARYHEAP_H_INCLUDED
|
@ -37,9 +37,23 @@ public:
|
||||
void Add(const keyT& key, const valueT& value){
|
||||
table[key] = value;
|
||||
}
|
||||
void Set(const keyT& key, const valueT& value){
|
||||
table[key] = value;
|
||||
}
|
||||
valueT Find(const keyT& key) {
|
||||
if(table.find(key) == table.end())
|
||||
return valueT();
|
||||
return table.find(key)->second;
|
||||
}
|
||||
|
||||
bool Holds(const keyT& key) {
|
||||
if(table.find(key) == table.end())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
void EraseAll() {
|
||||
table.clear();
|
||||
}
|
||||
private:
|
||||
MyHashTable table;
|
||||
};
|
||||
|
@ -60,8 +60,7 @@ static unsigned getFileIndexForLatLon(const int lt, const int ln)
|
||||
return fileIndex;
|
||||
}
|
||||
|
||||
static unsigned getRAMIndexFromFileIndex(const int fileIndex)
|
||||
{
|
||||
static unsigned getRAMIndexFromFileIndex(const int fileIndex) {
|
||||
unsigned fileLine = fileIndex / 32768;
|
||||
fileLine = fileLine / 32;
|
||||
fileLine = fileLine * 1024;
|
||||
@ -158,22 +157,17 @@ class NNGrid {
|
||||
ifstream stream;
|
||||
};
|
||||
|
||||
struct ThreadLookupTable{
|
||||
HashTable<unsigned, unsigned> table;
|
||||
};
|
||||
typedef HashTable<unsigned, unsigned> ThreadLookupTable;
|
||||
public:
|
||||
ThreadLookupTable threadLookup;
|
||||
|
||||
|
||||
NNGrid() { ramIndexTable.resize((1024*1024), UINT_MAX); if( WriteAccess) { entries = new stxxl::vector<GridEdgeData>(); }}
|
||||
|
||||
NNGrid(const char* rif, const char* iif) {
|
||||
NNGrid(const char* rif, const char* iif, unsigned numberOfThreads = omp_get_num_procs()) {
|
||||
ramIndexTable.resize((1024*1024), UINT_MAX);
|
||||
// indexInFile.open(iif, std::ios::in | std::ios::binary);
|
||||
ramInFile.open(rif, std::ios::in | std::ios::binary);
|
||||
|
||||
cout << "opening grid file for " << omp_get_num_procs() << " threads" << endl;
|
||||
|
||||
for(int i = 0; i< omp_get_num_procs(); i++) {
|
||||
indexFileStreams.push_back(new _ThreadData(iif));
|
||||
}
|
||||
@ -183,19 +177,17 @@ public:
|
||||
if(ramInFile.is_open()) ramInFile.close();
|
||||
// if(indexInFile.is_open()) indexInFile.close();
|
||||
|
||||
if (WriteAccess)
|
||||
{
|
||||
if (WriteAccess) {
|
||||
delete entries;
|
||||
}
|
||||
|
||||
#pragma omp parallel for
|
||||
for(int i = 0; i< indexFileStreams.size(); i++) {
|
||||
delete indexFileStreams[i];
|
||||
}
|
||||
threadLookup.EraseAll();
|
||||
}
|
||||
|
||||
void OpenIndexFiles()
|
||||
{
|
||||
void OpenIndexFiles() {
|
||||
assert(ramInFile.is_open());
|
||||
// assert(indexInFile.is_open());
|
||||
|
||||
@ -513,7 +505,7 @@ private:
|
||||
void GetContentsOfFileBucket(const unsigned fileIndex, std::vector<_Edge>& result)
|
||||
{
|
||||
// cout << "thread: " << boost::this_thread::get_id() << ", hash: " << boost_thread_id_hash(boost::this_thread::get_id()) << ", id: " << threadLookup.table.Find(boost_thread_id_hash(boost::this_thread::get_id())) << endl;
|
||||
unsigned threadID = threadLookup.table.Find(boost_thread_id_hash(boost::this_thread::get_id()));
|
||||
unsigned threadID = threadLookup.Find(boost_thread_id_hash(boost::this_thread::get_id()));
|
||||
unsigned ramIndex = getRAMIndexFromFileIndex(fileIndex);
|
||||
unsigned startIndexInFile = ramIndexTable[ramIndex];
|
||||
// ifstream indexInFile( indexFileStreams[threadID]->stream );
|
||||
|
@ -33,19 +33,24 @@ typedef NNGrid::NNGrid<false> ReadOnlyGrid;
|
||||
|
||||
class NodeInformationHelpDesk{
|
||||
public:
|
||||
NodeInformationHelpDesk(const char* ramIndexInput, const char* fileIndexInput) { numberOfNodes = 0; int2ExtNodeMap = new vector<_Coordinate>(); g = new ReadOnlyGrid(ramIndexInput,fileIndexInput); }
|
||||
~NodeInformationHelpDesk() { delete int2ExtNodeMap; delete g; }
|
||||
void initNNGrid(ifstream& in)
|
||||
{
|
||||
while(!in.eof())
|
||||
{
|
||||
NodeInfo b;
|
||||
in.read((char *)&b, sizeof(b));
|
||||
int2ExtNodeMap->push_back(_Coordinate(b.lat, b.lon));
|
||||
numberOfNodes++;
|
||||
}
|
||||
in.close();
|
||||
g->OpenIndexFiles();
|
||||
NodeInformationHelpDesk(const char* ramIndexInput, const char* fileIndexInput) {
|
||||
readOnlyGrid = new ReadOnlyGrid(ramIndexInput,fileIndexInput);
|
||||
int2ExtNodeMap = new vector<_Coordinate>();
|
||||
numberOfNodes = 0;
|
||||
}
|
||||
~NodeInformationHelpDesk() {
|
||||
delete int2ExtNodeMap;
|
||||
delete readOnlyGrid;
|
||||
}
|
||||
void initNNGrid(ifstream& in) {
|
||||
while(!in.eof()) {
|
||||
NodeInfo b;
|
||||
in.read((char *)&b, sizeof(b));
|
||||
int2ExtNodeMap->push_back(_Coordinate(b.lat, b.lon));
|
||||
numberOfNodes++;
|
||||
}
|
||||
in.close();
|
||||
readOnlyGrid->OpenIndexFiles();
|
||||
}
|
||||
|
||||
inline int getLatitudeOfNode(const NodeID node) const { return int2ExtNodeMap->at(node).lat; }
|
||||
@ -53,21 +58,22 @@ public:
|
||||
inline int getLongitudeOfNode(const NodeID node) const { return int2ExtNodeMap->at(node).lon; }
|
||||
|
||||
NodeID getNumberOfNodes() const { return numberOfNodes; }
|
||||
NodeID getNumberOfNodes2() const { return int2ExtNodeMap->size(); }
|
||||
|
||||
inline void findNearestNodeCoordForLatLon(const _Coordinate coord, _Coordinate& result) {
|
||||
result = g->FindNearestPointOnEdge(coord);
|
||||
result = readOnlyGrid->FindNearestPointOnEdge(coord);
|
||||
}
|
||||
|
||||
inline bool FindRoutingStarts(const _Coordinate start, const _Coordinate target, PhantomNodes * phantomNodes) {
|
||||
g->FindRoutingStarts(start, target, phantomNodes);
|
||||
readOnlyGrid->FindRoutingStarts(start, target, phantomNodes);
|
||||
}
|
||||
|
||||
inline void RegisterThread(const unsigned k, const unsigned v) {
|
||||
g->threadLookup.table.Add(k, v);
|
||||
readOnlyGrid->threadLookup.Add(k, v);
|
||||
}
|
||||
private:
|
||||
vector<_Coordinate> * int2ExtNodeMap;
|
||||
ReadOnlyGrid * g;
|
||||
ReadOnlyGrid * readOnlyGrid;
|
||||
unsigned numberOfNodes;
|
||||
};
|
||||
|
||||
|
5
Docs/KnownBugs.txt
Normal file
5
Docs/KnownBugs.txt
Normal file
@ -0,0 +1,5 @@
|
||||
- extractorLargeNetwork finishes with:
|
||||
terminate called after throwing an instance of 'stxxl::resource_error'
|
||||
what(): Error in function void stxxl::mutex::lock() pthread_mutex_lock(&_mutex) Invalid argument
|
||||
|
||||
This ist a known, albeit odd behavior that is caused by a bug in stxxl. It can be ignored
|
@ -1,150 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef HTTP_SERVER3_CONNECTION_HPP
|
||||
#define HTTP_CONNECTION_HPP
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/array.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/enable_shared_from_this.hpp>
|
||||
#include "reply.h"
|
||||
#include "request.h"
|
||||
#include "request_handler.h"
|
||||
#include "request_parser.h"
|
||||
|
||||
namespace http {
|
||||
|
||||
|
||||
/// Represents a single connection from a client.
|
||||
template<typename GraphT>
|
||||
class connection
|
||||
: public boost::enable_shared_from_this<connection<GraphT> >,
|
||||
private boost::noncopyable
|
||||
{
|
||||
public:
|
||||
/// Construct a connection with the given io_service.
|
||||
explicit connection(boost::asio::io_service& io_service,
|
||||
request_handler<GraphT>& handler)
|
||||
: strand_(io_service),
|
||||
socket_(io_service),
|
||||
request_handler_(handler)
|
||||
{
|
||||
}
|
||||
|
||||
/// Get the socket associated with the connection.
|
||||
boost::asio::ip::tcp::socket& socket()
|
||||
{
|
||||
return socket_;
|
||||
}
|
||||
|
||||
/// Start the first asynchronous operation for the connection.
|
||||
void start()
|
||||
{
|
||||
socket_.async_read_some(boost::asio::buffer(buffer_),
|
||||
strand_.wrap(
|
||||
boost::bind(&connection<GraphT>::handle_read, this->shared_from_this(),
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred)));
|
||||
}
|
||||
|
||||
private:
|
||||
/// Handle completion of a read operation.
|
||||
void handle_read(const boost::system::error_code& e, std::size_t bytes_transferred)
|
||||
{
|
||||
if (!e)
|
||||
{
|
||||
boost::tribool result;
|
||||
boost::tie(result, boost::tuples::ignore) = request_parser_.parse(
|
||||
request_, buffer_.data(), buffer_.data() + bytes_transferred);
|
||||
|
||||
if (result)
|
||||
{
|
||||
request_handler_.handle_request(request_, reply_);
|
||||
boost::asio::async_write(socket_, reply_.to_buffers(),
|
||||
strand_.wrap(
|
||||
boost::bind(&connection<GraphT>::handle_write, this->shared_from_this(),
|
||||
boost::asio::placeholders::error)));
|
||||
}
|
||||
else if (!result)
|
||||
{
|
||||
reply_ = reply::stock_reply(reply::bad_request);
|
||||
boost::asio::async_write(socket_, reply_.to_buffers(),
|
||||
strand_.wrap(
|
||||
boost::bind(&connection<GraphT>::handle_write, this->shared_from_this(),
|
||||
boost::asio::placeholders::error)));
|
||||
}
|
||||
else
|
||||
{
|
||||
socket_.async_read_some(boost::asio::buffer(buffer_),
|
||||
strand_.wrap(
|
||||
boost::bind(&connection<GraphT>::handle_read, this->shared_from_this(),
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle completion of a write operation.
|
||||
void handle_write(const boost::system::error_code& e)
|
||||
{
|
||||
if (!e)
|
||||
{
|
||||
// Initiate graceful connection closure.
|
||||
boost::system::error_code ignored_ec;
|
||||
socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec);
|
||||
}
|
||||
|
||||
// No new asynchronous operations are started. This means that all shared_ptr
|
||||
// references to the connection object will disappear and the object will be
|
||||
// destroyed automatically after this handler returns. The connection class's
|
||||
// destructor closes the socket.
|
||||
}
|
||||
|
||||
/// Strand to ensure the connection's handlers are not called concurrently.
|
||||
boost::asio::io_service::strand strand_;
|
||||
|
||||
/// Socket for the connection.
|
||||
boost::asio::ip::tcp::socket socket_;
|
||||
|
||||
/// The handler used to process the incoming request.
|
||||
request_handler<GraphT>& request_handler_;
|
||||
|
||||
/// Buffer for incoming data.
|
||||
boost::array<char, 8192> buffer_;
|
||||
|
||||
/// The incoming request.
|
||||
Request request_;
|
||||
|
||||
/// The parser for the incoming request.
|
||||
request_parser request_parser_;
|
||||
|
||||
/// The reply to be sent back to the client.
|
||||
reply reply_;
|
||||
|
||||
};
|
||||
|
||||
} // namespace http
|
||||
|
||||
#endif /* CONNECTION_HPP_ */
|
@ -1,156 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef HTTP_SERVER3_REPLY_HPP
|
||||
#define HTTP_SERVER3_REPLY_HPP
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include "header.h"
|
||||
|
||||
namespace http {
|
||||
|
||||
/// A reply to be sent to a client.
|
||||
struct reply
|
||||
{
|
||||
reply() { content.reserve(1000000); }
|
||||
/// The status of the reply.
|
||||
enum status_type
|
||||
{
|
||||
ok = 200,
|
||||
bad_request = 400,
|
||||
internal_server_error = 500
|
||||
} status;
|
||||
|
||||
std::vector<header> headers;
|
||||
|
||||
/// The content to be sent in the reply.
|
||||
std::string content;
|
||||
|
||||
/// Convert the reply into a vector of buffers. The buffers do not own the
|
||||
/// underlying memory blocks, therefore the reply object must remain valid and
|
||||
/// not be changed until the write operation has completed.
|
||||
std::vector<boost::asio::const_buffer> to_buffers();
|
||||
|
||||
/// Get a stock reply.
|
||||
static reply stock_reply(status_type status);
|
||||
};
|
||||
|
||||
namespace status_strings {
|
||||
|
||||
const std::string ok =
|
||||
"HTTP/1.0 200 OK\r\n";
|
||||
const std::string bad_request =
|
||||
"HTTP/1.0 400 Bad Request\r\n";
|
||||
const std::string internal_server_error =
|
||||
"HTTP/1.0 500 Internal Server Error\r\n";
|
||||
|
||||
boost::asio::const_buffer to_buffer(reply::status_type status)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case reply::ok:
|
||||
return boost::asio::buffer(ok);
|
||||
case reply::bad_request:
|
||||
return boost::asio::buffer(bad_request);
|
||||
case reply::internal_server_error:
|
||||
return boost::asio::buffer(internal_server_error);
|
||||
default:
|
||||
return boost::asio::buffer(bad_request);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace status_strings
|
||||
|
||||
namespace misc_strings {
|
||||
|
||||
const char name_value_separator[] = { ':', ' ' };
|
||||
const char crlf[] = { '\r', '\n' };
|
||||
|
||||
} // namespace misc_strings
|
||||
|
||||
std::vector<boost::asio::const_buffer> reply::to_buffers()
|
||||
{
|
||||
std::vector<boost::asio::const_buffer> buffers;
|
||||
buffers.push_back(status_strings::to_buffer(status));
|
||||
for (std::size_t i = 0; i < headers.size(); ++i)
|
||||
{
|
||||
header& h = headers[i];
|
||||
buffers.push_back(boost::asio::buffer(h.name));
|
||||
buffers.push_back(boost::asio::buffer(misc_strings::name_value_separator));
|
||||
buffers.push_back(boost::asio::buffer(h.value));
|
||||
buffers.push_back(boost::asio::buffer(misc_strings::crlf));
|
||||
}
|
||||
buffers.push_back(boost::asio::buffer(misc_strings::crlf));
|
||||
buffers.push_back(boost::asio::buffer(content));
|
||||
return buffers;
|
||||
}
|
||||
|
||||
namespace stock_replies {
|
||||
|
||||
const char ok[] = "";
|
||||
const char bad_request[] =
|
||||
"<html>"
|
||||
"<head><title>Bad Request</title></head>"
|
||||
"<body><h1>400 Bad Request</h1></body>"
|
||||
"</html>";
|
||||
const char internal_server_error[] =
|
||||
"<html>"
|
||||
"<head><title>Internal Server Error</title></head>"
|
||||
"<body><h1>500 Internal Server Error</h1></body>"
|
||||
"</html>";
|
||||
|
||||
std::string to_string(reply::status_type status)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case reply::ok:
|
||||
return ok;
|
||||
case reply::bad_request:
|
||||
return bad_request;
|
||||
case reply::internal_server_error:
|
||||
return internal_server_error;
|
||||
default:
|
||||
return internal_server_error;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace stock_replies
|
||||
|
||||
reply reply::stock_reply(reply::status_type status)
|
||||
{
|
||||
reply rep;
|
||||
rep.status = status;
|
||||
rep.content = stock_replies::to_string(status);
|
||||
rep.headers.resize(2);
|
||||
rep.headers[0].name = "Content-Length";
|
||||
rep.headers[0].value = boost::lexical_cast<std::string>(rep.content.size());
|
||||
rep.headers[1].name = "Content-Type";
|
||||
rep.headers[1].value = "text/html";
|
||||
return rep;
|
||||
}
|
||||
|
||||
} // namespace http
|
||||
|
||||
#endif // HTTP_SERVER3_REPLY_HPP
|
@ -1,399 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef HTTP_ROUTER_REQUEST_HANDLER_HPP
|
||||
#define HTTP_ROUTER_REQUEST_HANDLER_HPP
|
||||
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
#include "reply.h"
|
||||
#include "request.h"
|
||||
|
||||
#include "../typedefs.h"
|
||||
|
||||
namespace http {
|
||||
|
||||
struct reply;
|
||||
struct Request;
|
||||
|
||||
/// The common handler for all incoming requests.
|
||||
template<typename GraphT>
|
||||
class request_handler : private boost::noncopyable
|
||||
{
|
||||
public:
|
||||
explicit request_handler(SearchEngine<EdgeData, GraphT> * s) : sEngine(s){}
|
||||
|
||||
/// Handle a request and produce a reply.
|
||||
void handle_request(const Request& req, reply& rep){
|
||||
try {
|
||||
std::string request(req.uri);
|
||||
std::string command;
|
||||
std::size_t first_amp_pos = request.find_first_of("&");
|
||||
command = request.substr(1,first_amp_pos-1);
|
||||
if(command == "locate")
|
||||
{
|
||||
std::size_t last_amp_pos = request.find_last_of("&");
|
||||
int lat = static_cast<int>(100000*atof(request.substr(first_amp_pos+1, request.length()-last_amp_pos-1).c_str()));
|
||||
int lon = static_cast<int>(100000*atof(request.substr(last_amp_pos+1).c_str()));
|
||||
_Coordinate result;
|
||||
sEngine->findNearestNodeForLatLon(_Coordinate(lat, lon), result);
|
||||
|
||||
rep.status = reply::ok;
|
||||
rep.content.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||||
rep.content.append("<kml xmlns=\"http://www.opengis.net/kml/2.2\">");
|
||||
rep.content.append("<Placemark>");
|
||||
|
||||
std::stringstream out1;
|
||||
out1 << setprecision(10);
|
||||
out1 << "<name>Nearest Place in map to " << lat/100000. << "," << lon/100000. << "</name>";
|
||||
rep.content.append(out1.str());
|
||||
rep.content.append("<Point>");
|
||||
|
||||
std::stringstream out2;
|
||||
out2 << setprecision(10);
|
||||
out2 << "<coordinates>" << result.lon / 100000. << "," << result.lat / 100000. << "</coordinates>";
|
||||
rep.content.append(out2.str());
|
||||
rep.content.append("</Point>");
|
||||
rep.content.append("</Placemark>");
|
||||
rep.content.append("</kml>");
|
||||
|
||||
rep.headers.resize(3);
|
||||
rep.headers[0].name = "Content-Length";
|
||||
rep.headers[0].value = boost::lexical_cast<std::string>(rep.content.size());
|
||||
rep.headers[1].name = "Content-Type";
|
||||
rep.headers[1].value = "application/vnd.google-earth.kml+xml";
|
||||
rep.headers[2].name = "Content-Disposition";
|
||||
rep.headers[2].value = "attachment; filename=\"placemark.kml\"";
|
||||
return;
|
||||
}
|
||||
if(command == "route")
|
||||
{
|
||||
double timestamp = get_timestamp();
|
||||
//http://localhost:5000/route&45.1427&12.14144&54.8733&8.59438
|
||||
std::size_t second_amp_pos = request.find_first_of("&", first_amp_pos+1);
|
||||
std::size_t third_amp_pos = request.find_first_of("&", second_amp_pos+1);
|
||||
std::size_t fourth_amp_pos = request.find_last_of("&");
|
||||
|
||||
int lat1 = static_cast<int>(100000*atof(request.substr(first_amp_pos+1, request.length()-second_amp_pos-1).c_str()));
|
||||
int lon1 = static_cast<int>(100000*atof(request.substr(second_amp_pos+1, request.length()-third_amp_pos-1).c_str()));
|
||||
int lat2 = static_cast<int>(100000*atof(request.substr(third_amp_pos+1, request.length()-fourth_amp_pos-1).c_str()));
|
||||
int lon2 = static_cast<int>(100000*atof(request.substr(fourth_amp_pos+1).c_str()));
|
||||
|
||||
_Coordinate startCoord(lat1, lon1);
|
||||
_Coordinate targetCoord(lat2, lon2);
|
||||
|
||||
vector< _PathData > * path = new vector< _PathData >();
|
||||
PhantomNodes * phantomNodes = new PhantomNodes();
|
||||
sEngine->FindRoutingStarts(startCoord, targetCoord, phantomNodes);
|
||||
unsigned int distance = sEngine->ComputeRoute(phantomNodes, path, startCoord, targetCoord);
|
||||
rep.status = reply::ok;
|
||||
|
||||
string tmp;
|
||||
|
||||
rep.content += ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||||
rep.content += ("<kml xmlns=\"http://www.opengis.net/kml/2.2\">");
|
||||
rep.content += ("<Document>");
|
||||
|
||||
/* if(distance != std::numeric_limits<unsigned int>::max())
|
||||
computeDescription(tmp, path, phantomNodes);
|
||||
cout << tmp << endl;
|
||||
*/
|
||||
// rep.content += tmp;
|
||||
rep.content += ("<Placemark>");
|
||||
rep.content += ("<name>OSM Routing Engine (c) Dennis Luxen and others </name>");
|
||||
|
||||
rep.content += "<description>Route from ";
|
||||
convertLatLon(lat1, tmp);
|
||||
rep.content += tmp;
|
||||
rep.content += ",";
|
||||
convertLatLon(lon1, tmp);
|
||||
rep.content += tmp;
|
||||
rep.content += " to ";
|
||||
convertLatLon(lat2, tmp);
|
||||
rep.content += tmp;
|
||||
rep.content += ",";
|
||||
convertLatLon(lon2, tmp);
|
||||
rep.content += tmp;
|
||||
rep.content += "</description> ";
|
||||
rep.content += ("<LineString>");
|
||||
rep.content += ("<extrude>1</extrude>");
|
||||
rep.content += ("<tessellate>1</tessellate>");
|
||||
rep.content += ("<altitudeMode>absolute</altitudeMode>");
|
||||
rep.content += ("<coordinates>");
|
||||
|
||||
|
||||
if(distance != std::numeric_limits<unsigned int>::max())
|
||||
{ //A route has been found
|
||||
convertLatLon(phantomNodes->startCoord.lon, tmp);
|
||||
rep.content += tmp;
|
||||
rep.content += (",");
|
||||
doubleToString(phantomNodes->startCoord.lat/100000., tmp);
|
||||
rep.content += tmp;
|
||||
rep.content += (" ");
|
||||
_Coordinate result;
|
||||
for(vector< _PathData >::iterator it = path->begin(); it != path->end(); it++)
|
||||
{
|
||||
sEngine->getNodeInfo(it->node, result);
|
||||
convertLatLon(result.lon, tmp);
|
||||
rep.content += tmp;
|
||||
rep.content += (",");
|
||||
convertLatLon(result.lat, tmp);
|
||||
rep.content += tmp;
|
||||
rep.content += (" ");
|
||||
}
|
||||
|
||||
convertLatLon(phantomNodes->targetCoord.lon, tmp);
|
||||
rep.content += tmp;
|
||||
rep.content += (",");
|
||||
convertLatLon(phantomNodes->targetCoord.lat, tmp);
|
||||
rep.content += tmp;
|
||||
}
|
||||
|
||||
rep.content += ("</coordinates>");
|
||||
rep.content += ("</LineString>");
|
||||
rep.content += ("</Placemark>");
|
||||
rep.content += ("</Document>");
|
||||
rep.content += ("</kml>");
|
||||
|
||||
rep.headers.resize(3);
|
||||
rep.headers[0].name = "Content-Length";
|
||||
intToString(rep.content.size(), tmp);
|
||||
rep.headers[0].value = tmp;
|
||||
rep.headers[1].name = "Content-Type";
|
||||
rep.headers[1].value = "application/vnd.google-earth.kml+xml";
|
||||
rep.headers[2].name = "Content-Disposition";
|
||||
rep.headers[2].value = "attachment; filename=\"route.kml\"";
|
||||
|
||||
delete path;
|
||||
delete phantomNodes;
|
||||
// timestamp2 = get_timestamp();
|
||||
//cout << "description in " << timestamp2 - timestamp << "s" << endl;
|
||||
return;
|
||||
}
|
||||
rep = reply::stock_reply(reply::bad_request);
|
||||
return;
|
||||
} catch(std::exception& e)
|
||||
{
|
||||
//TODO: log exception somewhere
|
||||
rep = reply::stock_reply(reply::internal_server_error);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
//SearchEngine object that is queried
|
||||
SearchEngine<EdgeData, GraphT> * sEngine;
|
||||
|
||||
/* used to be boosts lexical cast, but this was too slow */
|
||||
inline void doubleToString(const double value, std::string & output)
|
||||
{
|
||||
// The largest 32-bit integer is 4294967295, that is 10 chars
|
||||
// On the safe side, add 1 for sign, and 1 for trailing zero
|
||||
char buffer[12] ;
|
||||
sprintf(buffer, "%f", value) ;
|
||||
output = buffer ;
|
||||
}
|
||||
|
||||
inline void intToString(const int value, std::string & output)
|
||||
{
|
||||
// The largest 32-bit integer is 4294967295, that is 10 chars
|
||||
// On the safe side, add 1 for sign, and 1 for trailing zero
|
||||
char buffer[12] ;
|
||||
sprintf(buffer, "%i", value) ;
|
||||
output = buffer ;
|
||||
}
|
||||
|
||||
inline void convertLatLon(const int value, std::string & output)
|
||||
{
|
||||
char buffer[100];
|
||||
buffer[10] = 0; // Nullterminierung
|
||||
char* string = printInt< 10, 5 >( buffer, value );
|
||||
output = string;
|
||||
}
|
||||
|
||||
// precision: position after decimal point
|
||||
// length: maximum number of digits including comma and decimals
|
||||
template< int length, int precision >
|
||||
inline char* printInt( char* buffer, int value )
|
||||
{
|
||||
bool minus = false;
|
||||
if ( value < 0 ) {
|
||||
minus = true;
|
||||
value = -value;
|
||||
}
|
||||
buffer += length - 1;
|
||||
for ( int i = 0; i < precision; i++ ) {
|
||||
*buffer = '0' + ( value % 10 );
|
||||
value /= 10;
|
||||
buffer--;
|
||||
}
|
||||
*buffer = '.';
|
||||
buffer--;
|
||||
for ( int i = precision + 1; i < length; i++ ) {
|
||||
*buffer = '0' + ( value % 10 );
|
||||
value /= 10;
|
||||
if ( value == 0 ) break;
|
||||
buffer--;
|
||||
}
|
||||
if ( minus ) {
|
||||
buffer--;
|
||||
*buffer = '-';
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void computeDescription(string &tmp, vector< _PathData > * path, PhantomNodes * phantomNodes)
|
||||
{
|
||||
_Coordinate previous(phantomNodes->startCoord.lat, phantomNodes->startCoord.lon);
|
||||
_Coordinate next, current, lastPlace;
|
||||
stringstream numberString;
|
||||
|
||||
double tempDist = 0;
|
||||
NodeID nextID = UINT_MAX;
|
||||
NodeID nameID = sEngine->GetNameIDForOriginDestinationNodeID(phantomNodes->startNode1, phantomNodes->startNode2);
|
||||
short type = sEngine->GetTypeOfEdgeForOriginDestinationNodeID(phantomNodes->startNode1, phantomNodes->startNode2);
|
||||
lastPlace.lat = phantomNodes->startCoord.lat;
|
||||
lastPlace.lon = phantomNodes->startCoord.lon;
|
||||
short nextType = SHRT_MAX;
|
||||
short prevType = SHRT_MAX;
|
||||
tmp += "<Placemark>\n <Name>";
|
||||
for(vector< _PathData >::iterator it = path->begin(); it != path->end(); it++)
|
||||
{
|
||||
sEngine->getNodeInfo(it->node, current);
|
||||
if(it==path->end()-1){
|
||||
next = _Coordinate(phantomNodes->targetCoord.lat, phantomNodes->targetCoord.lon);
|
||||
nextID = sEngine->GetNameIDForOriginDestinationNodeID(phantomNodes->targetNode1, phantomNodes->targetNode2);
|
||||
nextType = sEngine->GetTypeOfEdgeForOriginDestinationNodeID(phantomNodes->targetNode1, phantomNodes->targetNode2);
|
||||
} else {
|
||||
sEngine->getNodeInfo((it+1)->node, next);
|
||||
nextID = sEngine->GetNameIDForOriginDestinationNodeID(it->node, (it+1)->node);
|
||||
nextType = sEngine->GetTypeOfEdgeForOriginDestinationNodeID(it->node, (it+1)->node);
|
||||
}
|
||||
if(nextID == nameID) {
|
||||
tempDist += ApproximateDistance(previous.lat, previous.lon, current.lat, current.lon);
|
||||
} else {
|
||||
if(type == 0 && prevType != 0)
|
||||
tmp += "enter motorway and ";
|
||||
if(type != 0 && prevType == 0 )
|
||||
tmp += "leave motorway and ";
|
||||
|
||||
double angle = GetAngleBetweenTwoEdges(previous, current, next);
|
||||
// if(it->turn)
|
||||
// tmp += " turn! ";
|
||||
tmp += "follow road ";
|
||||
if(nameID != 0)
|
||||
tmp += sEngine->GetNameForNameID(nameID);
|
||||
tmp += " (type: ";
|
||||
numberString << type;
|
||||
tmp += numberString.str();
|
||||
numberString.str("");
|
||||
tmp += ", id: ";
|
||||
numberString << nameID;
|
||||
tmp += numberString.str();
|
||||
numberString.str("");
|
||||
tmp += ")</Name>\n <Description>drive for ";
|
||||
numberString << ApproximateDistance(previous.lat, previous.lon, current.lat, current.lon)+tempDist;
|
||||
tmp += numberString.str();
|
||||
numberString.str("");
|
||||
tmp += "m </Description>";
|
||||
string lat; string lon;
|
||||
convertLatLon(lastPlace.lon, lon);
|
||||
convertLatLon(lastPlace.lat, lat);
|
||||
lastPlace = current;
|
||||
tmp += "\n <Point><Coordinates>";
|
||||
tmp += lon;
|
||||
tmp += ",";
|
||||
tmp += lat;
|
||||
tmp += "</Coordinates></Point>";
|
||||
tmp += "\n</Placemark>\n";
|
||||
tmp += "<Placemark>\n <Name> (";
|
||||
numberString << angle;
|
||||
tmp += numberString.str();
|
||||
numberString.str("");
|
||||
tmp +=") ";
|
||||
if(angle > 160 && angle < 200) {
|
||||
tmp += /* " (" << angle << ")*/"drive ahead, ";
|
||||
} else if (angle > 290 && angle <= 360) {
|
||||
tmp += /*" (" << angle << ")*/ "turn sharp left, ";
|
||||
} else if (angle > 230 && angle <= 290) {
|
||||
tmp += /*" (" << angle << ")*/ "turn left, ";
|
||||
} else if (angle > 200 && angle <= 230) {
|
||||
tmp += /*" (" << angle << ") */"bear left, ";
|
||||
} else if (angle > 130 && angle <= 160) {
|
||||
tmp += /*" (" << angle << ") */"bear right, ";
|
||||
} else if (angle > 70 && angle <= 130) {
|
||||
tmp += /*" (" << angle << ") */"turn right, ";
|
||||
} else {
|
||||
tmp += /*" (" << angle << ") */"turn sharp right, ";
|
||||
}
|
||||
tempDist = 0;
|
||||
prevType = type;
|
||||
}
|
||||
nameID = nextID;
|
||||
previous = current;
|
||||
type = nextType;
|
||||
}
|
||||
nameID = sEngine->GetNameIDForOriginDestinationNodeID(phantomNodes->targetNode1, phantomNodes->targetNode2);
|
||||
type = sEngine->GetTypeOfEdgeForOriginDestinationNodeID(phantomNodes->targetNode1, phantomNodes->targetNode2);
|
||||
tmp += "follow road ";
|
||||
tmp += sEngine->GetNameForNameID(nameID);
|
||||
tmp += " (type: ";
|
||||
numberString << type;
|
||||
tmp += numberString.str();
|
||||
numberString.str("");
|
||||
tmp += ", id: ";
|
||||
numberString << nameID;
|
||||
tmp += numberString.str();
|
||||
numberString.str("");
|
||||
tmp += ")</name>\n <Description> drive for ";
|
||||
numberString << ApproximateDistance(previous.lat, previous.lon, phantomNodes->targetCoord.lat, phantomNodes->targetCoord.lon) + tempDist;
|
||||
tmp += numberString.str();
|
||||
numberString.str("");
|
||||
tmp += "m</Description>\n ";
|
||||
string lat; string lon;
|
||||
convertLatLon(lastPlace.lon, lon);
|
||||
convertLatLon(lastPlace.lat, lat);
|
||||
tmp += "<Point><Coordinates>";
|
||||
tmp += lon;
|
||||
tmp += ",";
|
||||
tmp += lat;
|
||||
tmp += "</Coordinates></Point>";
|
||||
tmp += "</Placemark>\n";
|
||||
tmp += "<Placemark>\n <Name>you have reached your destination</Name>\n ";
|
||||
tmp += "<Description>End of Route</Description>";
|
||||
convertLatLon(phantomNodes->targetCoord.lon, lon);
|
||||
convertLatLon(phantomNodes->targetCoord.lat, lat);
|
||||
tmp += "\n <Point><Coordinates>";
|
||||
tmp += lon;
|
||||
tmp += ",";
|
||||
tmp += lat;
|
||||
tmp +="</Coordinates></Point>\n";
|
||||
tmp += "</Placemark>";
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif // HTTP_ROUTER_REQUEST_HANDLER_HPP
|
@ -1,402 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef HTTP_REQUEST_PARSER_HPP
|
||||
#define HTTP_REQUEST_PARSER_HPP
|
||||
|
||||
#include <boost/logic/tribool.hpp>
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
|
||||
namespace http {
|
||||
|
||||
struct Request;
|
||||
|
||||
/// Parser for incoming requests.
|
||||
class request_parser
|
||||
{
|
||||
public:
|
||||
/// Construct ready to parse the request method.
|
||||
request_parser();
|
||||
|
||||
/// Reset to initial parser state.
|
||||
void reset();
|
||||
|
||||
/// Parse some data. The tribool return value is true when a complete request
|
||||
/// has been parsed, false if the data is invalid, indeterminate when more
|
||||
/// data is required. The InputIterator return value indicates how much of the
|
||||
/// input has been consumed.
|
||||
template <typename InputIterator>
|
||||
boost::tuple<boost::tribool, InputIterator> parse(Request& req,
|
||||
InputIterator begin, InputIterator end)
|
||||
{
|
||||
while (begin != end)
|
||||
{
|
||||
boost::tribool result = consume(req, *begin++);
|
||||
if (result || !result)
|
||||
return boost::make_tuple(result, begin);
|
||||
}
|
||||
boost::tribool result = boost::indeterminate;
|
||||
return boost::make_tuple(result, begin);
|
||||
}
|
||||
|
||||
private:
|
||||
/// Handle the next character of input.
|
||||
boost::tribool consume(Request& req, char input);
|
||||
|
||||
/// Check if a byte is an HTTP character.
|
||||
static bool is_char(int c);
|
||||
|
||||
/// Check if a byte is an HTTP control character.
|
||||
static bool is_ctl(int c);
|
||||
|
||||
/// Check if a byte is defined as an HTTP tspecial character.
|
||||
static bool is_tspecial(int c);
|
||||
|
||||
/// Check if a byte is a digit.
|
||||
static bool is_digit(int c);
|
||||
|
||||
/// The current state of the parser.
|
||||
enum state
|
||||
{
|
||||
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_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace http
|
||||
|
||||
#include "request.h"
|
||||
|
||||
namespace http {
|
||||
|
||||
request_parser::request_parser()
|
||||
: state_(method_start)
|
||||
{
|
||||
}
|
||||
|
||||
void request_parser::reset()
|
||||
{
|
||||
state_ = method_start;
|
||||
}
|
||||
|
||||
boost::tribool request_parser::consume(Request& req, char input)
|
||||
{
|
||||
switch (state_)
|
||||
{
|
||||
case method_start:
|
||||
if (!is_char(input) || is_ctl(input) || is_tspecial(input))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
state_ = method;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
case method:
|
||||
if (input == ' ')
|
||||
{
|
||||
state_ = uri;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else if (!is_char(input) || is_ctl(input) || is_tspecial(input))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return boost::indeterminate;
|
||||
}
|
||||
case uri_start:
|
||||
if (is_ctl(input))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
state_ = uri;
|
||||
req.uri.push_back(input);
|
||||
return boost::indeterminate;
|
||||
}
|
||||
case uri:
|
||||
if (input == ' ')
|
||||
{
|
||||
state_ = http_version_h;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else if (is_ctl(input))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
req.uri.push_back(input);
|
||||
return boost::indeterminate;
|
||||
}
|
||||
case http_version_h:
|
||||
if (input == 'H')
|
||||
{
|
||||
state_ = http_version_t_1;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
case http_version_t_1:
|
||||
if (input == 'T')
|
||||
{
|
||||
state_ = http_version_t_2;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
case http_version_t_2:
|
||||
if (input == 'T')
|
||||
{
|
||||
state_ = http_version_p;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
case http_version_p:
|
||||
if (input == 'P')
|
||||
{
|
||||
state_ = http_version_slash;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
case http_version_slash:
|
||||
if (input == '/')
|
||||
{
|
||||
state_ = http_version_major_start;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
case http_version_major_start:
|
||||
if (is_digit(input))
|
||||
{
|
||||
state_ = http_version_major;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
case http_version_major:
|
||||
if (input == '.')
|
||||
{
|
||||
state_ = http_version_minor_start;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else if (is_digit(input))
|
||||
{
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
case http_version_minor_start:
|
||||
if (is_digit(input))
|
||||
{
|
||||
state_ = http_version_minor;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
case http_version_minor:
|
||||
if (input == '\r')
|
||||
{
|
||||
state_ = expecting_newline_1;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else if (is_digit(input))
|
||||
{
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
case expecting_newline_1:
|
||||
if (input == '\n')
|
||||
{
|
||||
state_ = header_line_start;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
case header_line_start:
|
||||
if (input == '\r')
|
||||
{
|
||||
state_ = expecting_newline_3;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else if (!is_char(input) || is_ctl(input) || is_tspecial(input))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
state_ = header_name;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
case header_lws:
|
||||
if (input == '\r')
|
||||
{
|
||||
state_ = expecting_newline_2;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else if (input == ' ' || input == '\t')
|
||||
{
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else if (is_ctl(input))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
state_ = header_value;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
case header_name:
|
||||
if (input == ':')
|
||||
{
|
||||
state_ = space_before_header_value;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else if (!is_char(input) || is_ctl(input) || is_tspecial(input))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return boost::indeterminate;
|
||||
}
|
||||
case space_before_header_value:
|
||||
if (input == ' ')
|
||||
{
|
||||
state_ = header_value;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
case header_value:
|
||||
if (input == '\r')
|
||||
{
|
||||
state_ = expecting_newline_2;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else if (is_ctl(input))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return boost::indeterminate;
|
||||
}
|
||||
case expecting_newline_2:
|
||||
if (input == '\n')
|
||||
{
|
||||
state_ = header_line_start;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
case expecting_newline_3:
|
||||
return (input == '\n');
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool request_parser::is_char(int c)
|
||||
{
|
||||
return c >= 0 && c <= 127;
|
||||
}
|
||||
|
||||
bool request_parser::is_ctl(int c)
|
||||
{
|
||||
return (c >= 0 && c <= 31) || (c == 127);
|
||||
}
|
||||
|
||||
bool request_parser::is_tspecial(int c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
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 request_parser::is_digit(int c)
|
||||
{
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
||||
|
||||
} // namespace http
|
||||
|
||||
#endif // HTTP_SERVER3_REQUEST_PARSER_HPP
|
@ -1,124 +0,0 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef HTTP_ROUTER_SERVER_HPP
|
||||
#define HTTP_ROUTER_SERVER_HPP
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
#include <climits>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "../typedefs.h"
|
||||
|
||||
#include "connection.h"
|
||||
#include "request_handler.h"
|
||||
|
||||
namespace http {
|
||||
|
||||
/// The top-level class of the HTTP server.
|
||||
template<typename GraphT>
|
||||
class server: private boost::noncopyable
|
||||
{
|
||||
public:
|
||||
/// Construct the server to listen on the specified TCP address and port
|
||||
explicit server(const std::string& address, const std::string& port, std::size_t thread_pool_size, SearchEngine<EdgeData, GraphT, NodeInformationHelpDesk> * s)
|
||||
: thread_pool_size_(thread_pool_size),
|
||||
acceptor_(io_service_),
|
||||
new_connection_(new connection<GraphT>(io_service_, request_handler_)),
|
||||
request_handler_(s),
|
||||
sEngine(s)
|
||||
{
|
||||
// Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR).
|
||||
boost::asio::ip::tcp::resolver resolver(io_service_);
|
||||
boost::asio::ip::tcp::resolver::query query(address, port);
|
||||
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::handle_accept, this, boost::asio::placeholders::error));
|
||||
}
|
||||
|
||||
/// Run the server's io_service loop.
|
||||
void run()
|
||||
{
|
||||
// Create a pool of threads to run all of the io_services.
|
||||
std::vector<boost::shared_ptr<boost::thread> > threads;
|
||||
for (std::size_t i = 0; i < thread_pool_size_; ++i)
|
||||
{
|
||||
boost::shared_ptr<boost::thread> thread(new boost::thread(boost::bind(&boost::asio::io_service::run, &io_service_)));
|
||||
sEngine->RegisterThread( boost_thread_id_hash( thread->get_id() ), threads.size());
|
||||
threads.push_back(thread);
|
||||
}
|
||||
|
||||
// Wait for all threads in the pool to exit.
|
||||
for (std::size_t i = 0; i < threads.size(); ++i)
|
||||
threads[i]->join();
|
||||
}
|
||||
|
||||
/// Stop the server.
|
||||
void stop()
|
||||
{
|
||||
io_service_.stop();
|
||||
}
|
||||
|
||||
private:
|
||||
typedef boost::shared_ptr<connection<GraphT> > connection_ptr;
|
||||
|
||||
/// Handle completion of an asynchronous accept operation.
|
||||
void handle_accept(const boost::system::error_code& e)
|
||||
{
|
||||
if (!e)
|
||||
{
|
||||
new_connection_->start();
|
||||
new_connection_.reset(new connection<GraphT>(io_service_, request_handler_));
|
||||
acceptor_.async_accept(new_connection_->socket(), boost::bind(&server::handle_accept, this, boost::asio::placeholders::error));
|
||||
}
|
||||
}
|
||||
|
||||
/// The number of threads that will call io_service::run().
|
||||
std::size_t thread_pool_size_;
|
||||
|
||||
/// The io_service used to perform asynchronous operations.
|
||||
boost::asio::io_service io_service_;
|
||||
|
||||
/// Acceptor used to listen for incoming connections.
|
||||
boost::asio::ip::tcp::acceptor acceptor_;
|
||||
|
||||
/// The next connection to be accepted.
|
||||
connection_ptr new_connection_;
|
||||
|
||||
/// The handler for all incoming requests.
|
||||
request_handler<GraphT> request_handler_;
|
||||
|
||||
/// The object to query the Routing Engine
|
||||
SearchEngine<EdgeData, GraphT> * sEngine;
|
||||
|
||||
};
|
||||
|
||||
} // namespace http
|
||||
|
||||
#endif // HTTP_ROUTER_SERVER_HPP
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
Copyright (C) Dennis Luxen, 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
@ -16,22 +16,24 @@ You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
*/
|
||||
|
||||
#ifndef HTTP_HEADER_HPP
|
||||
#define HTTP_HEADER_HPP
|
||||
#ifndef BASEPLUGIN_H_
|
||||
#define BASEPLUGIN_H_
|
||||
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "../Server/BasicDatastructures.h"
|
||||
|
||||
namespace http {
|
||||
|
||||
|
||||
struct header
|
||||
{
|
||||
std::string name;
|
||||
std::string value;
|
||||
class BasePlugin {
|
||||
public:
|
||||
BasePlugin() { }
|
||||
//Maybe someone can explain the pure virtual destructor thing to me (dennis)
|
||||
virtual ~BasePlugin() { }
|
||||
virtual std::string GetDescriptor() = 0;
|
||||
virtual std::string GetVersionString() = 0;
|
||||
virtual void HandleRequest(std::vector<std::string> parameters, http::Reply& reply) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* BASEPLUGIN_H_ */
|
35
Plugins/HelloWorldPlugin.h
Normal file
35
Plugins/HelloWorldPlugin.h
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* LocatePlugin.h
|
||||
*
|
||||
* Created on: 01.01.2011
|
||||
* Author: dennis
|
||||
*/
|
||||
|
||||
#ifndef HELLOWORLDPLUGIN_H_
|
||||
#define HELLOWORLDPLUGIN_H_
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "BasePlugin.h"
|
||||
|
||||
class HelloWorldPlugin : public BasePlugin {
|
||||
public:
|
||||
HelloWorldPlugin() {}
|
||||
~HelloWorldPlugin() { std::cout << GetDescriptor() << " destructor" << std::endl; }
|
||||
std::string GetDescriptor() { return std::string("hello"); }
|
||||
void HandleRequest(std::vector<std::string> parameters, http::Reply& reply) {
|
||||
std::cout << "[hello world]: runnning handler" << std::endl;
|
||||
reply.status = http::Reply::ok;
|
||||
reply.content.append("<html><head><title>Hello World Demonstration Document</title></head><body><h1>Hello, World!</h1>");
|
||||
std::stringstream content;
|
||||
content << "Number of parameters: " << parameters.size() << "<br>";
|
||||
for(int i = 0; i < parameters.size(); i++) {
|
||||
content << parameters[i] << "<br>";
|
||||
}
|
||||
reply.content.append(content.str());
|
||||
reply.content.append("</body></html>");
|
||||
}
|
||||
std::string GetVersionString() { return std::string("0.1a"); }
|
||||
};
|
||||
|
||||
#endif /* HELLOWORLDPLUGIN_H_ */
|
91
Plugins/LocatePlugin.h
Normal file
91
Plugins/LocatePlugin.h
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef LOCATEPLUGIN_H_
|
||||
#define LOCATEPLUGIN_H_
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include "BasePlugin.h"
|
||||
|
||||
#include "../DataStructures/NodeInformationHelpDesk.h"
|
||||
|
||||
/*
|
||||
* This Plugin locates the nearest point on a street in the road network for a given coordinate.
|
||||
*/
|
||||
class LocatePlugin : public BasePlugin {
|
||||
public:
|
||||
LocatePlugin(std::string ramIndexPath, std::string fileIndexPath, std::string nodesPath) {
|
||||
nodeHelpDesk = new NodeInformationHelpDesk(ramIndexPath.c_str(), fileIndexPath.c_str());
|
||||
ifstream nodesInStream(nodesPath.c_str(), ios::binary);
|
||||
nodeHelpDesk->initNNGrid(nodesInStream);
|
||||
}
|
||||
~LocatePlugin() {
|
||||
delete nodeHelpDesk;
|
||||
}
|
||||
std::string GetDescriptor() { return std::string("locate"); }
|
||||
std::string GetVersionString() { return std::string("0.2a (DL)"); }
|
||||
void HandleRequest(std::vector<std::string> parameters, http::Reply& reply) {
|
||||
//check number of parameters
|
||||
if(parameters.size() != 2) {
|
||||
reply = http::Reply::stockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
|
||||
int lat = static_cast<int>(100000.*atof(parameters[0].c_str()));
|
||||
int lon = static_cast<int>(100000.*atof(parameters[1].c_str()));
|
||||
//query to helpdesk
|
||||
_Coordinate result;
|
||||
nodeHelpDesk->findNearestNodeCoordForLatLon(_Coordinate(lat, lon), result);
|
||||
|
||||
//Write to stream
|
||||
reply.status = http::Reply::ok;
|
||||
reply.content.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||||
reply.content.append("<kml xmlns=\"http://www.opengis.net/kml/2.2\">");
|
||||
reply.content.append("<Placemark>");
|
||||
|
||||
std::stringstream out1;
|
||||
out1 << setprecision(10);
|
||||
out1 << "<name>Nearest Place in map to " << lat/100000. << "," << lon/100000. << "</name>";
|
||||
reply.content.append(out1.str());
|
||||
reply.content.append("<Point>");
|
||||
|
||||
std::stringstream out2;
|
||||
out2 << setprecision(10);
|
||||
out2 << "<coordinates>" << result.lon / 100000. << "," << result.lat / 100000. << "</coordinates>";
|
||||
reply.content.append(out2.str());
|
||||
reply.content.append("</Point>");
|
||||
reply.content.append("</Placemark>");
|
||||
reply.content.append("</kml>");
|
||||
|
||||
reply.headers.resize(3);
|
||||
reply.headers[0].name = "Content-Length";
|
||||
reply.headers[0].value = boost::lexical_cast<std::string>(reply.content.size());
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "application/vnd.google-earth.kml+xml";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"placemark.kml\"";
|
||||
return;
|
||||
}
|
||||
private:
|
||||
NodeInformationHelpDesk * nodeHelpDesk;
|
||||
};
|
||||
|
||||
#endif /* LOCATEPLUGIN_H_ */
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
Copyright (C) Dennis Luxen, 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
@ -18,21 +18,17 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef HTTP_REQUEST_HPP
|
||||
#define HTTP_REQUEST_HPP
|
||||
#ifndef PLUGINMAPFACTORY_H_
|
||||
#define PLUGINMAPFACTORY_H_
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include "header.h"
|
||||
//#include "../DataStructures/HashTable.h"
|
||||
//#include "../Plugins/BasePlugin.h"
|
||||
//
|
||||
//struct PluginMapFactory {
|
||||
// static HashTable<std::string, BasePlugin *> * CreatePluginMap() {
|
||||
// HashTable<std::string, BasePlugin *> * map = new HashTable<std::string, BasePlugin *>();
|
||||
//
|
||||
// }
|
||||
//};
|
||||
|
||||
namespace http {
|
||||
|
||||
/// A request received from a client.
|
||||
struct Request
|
||||
{
|
||||
std::string uri;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // HTTP_REQUEST_HPP
|
||||
#endif /* PLUGINMAPFACTORY_H_ */
|
311
Plugins/RoutePlugin.h
Normal file
311
Plugins/RoutePlugin.h
Normal file
@ -0,0 +1,311 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef ROUTEPLUGIN_H_
|
||||
#define ROUTEPLUGIN_H_
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "BasePlugin.h"
|
||||
#include "../DataStructures/StaticGraph.h"
|
||||
#include "../DataStructures/SearchEngine.h"
|
||||
|
||||
#include "../Util/GraphLoader.h"
|
||||
#include "../Util/StrIngUtil.h"
|
||||
|
||||
typedef ContractionCleanup::Edge::EdgeData EdgeData;
|
||||
typedef StaticGraph<EdgeData>::InputEdge GridEdge;
|
||||
|
||||
class RoutePlugin : public BasePlugin {
|
||||
public:
|
||||
RoutePlugin(std::string hsgrPath, std::string ramIndexPath, std::string fileIndexPath, std::string nodesPath, std::string namesPath) {
|
||||
//Init nearest neighbor data structure
|
||||
nodeHelpDesk = new NodeInformationHelpDesk(ramIndexPath.c_str(), fileIndexPath.c_str());
|
||||
ifstream nodesInStream(nodesPath.c_str(), ios::binary);
|
||||
ifstream hsgrInStream(hsgrPath.c_str(), ios::binary);
|
||||
nodeHelpDesk->initNNGrid(nodesInStream);
|
||||
|
||||
//Deserialize road network graph
|
||||
std::vector< GridEdge> * edgeList = new std::vector< GridEdge>();
|
||||
readHSGRFromStream(hsgrInStream, edgeList);
|
||||
hsgrInStream.close();
|
||||
|
||||
graph = new StaticGraph<EdgeData>(nodeHelpDesk->getNumberOfNodes()-1, *edgeList);
|
||||
delete edgeList;
|
||||
|
||||
//deserialize street name list
|
||||
ifstream namesInStream(namesPath.c_str(), ios::binary);
|
||||
unsigned size = 0;
|
||||
namesInStream.read((char *)&size, sizeof(unsigned));
|
||||
names = new std::vector<std::string>();
|
||||
|
||||
//init complete search engine
|
||||
sEngine = new SearchEngine<EdgeData, StaticGraph<EdgeData> >(graph, nodeHelpDesk, names);
|
||||
}
|
||||
~RoutePlugin() {
|
||||
delete names;
|
||||
delete sEngine;
|
||||
delete graph;
|
||||
delete nodeHelpDesk;
|
||||
}
|
||||
std::string GetDescriptor() { return std::string("route"); }
|
||||
std::string GetVersionString() { return std::string("0.2a (DL)"); }
|
||||
void HandleRequest(std::vector<std::string> parameters, http::Reply& reply) {
|
||||
//check number of parameters
|
||||
if(parameters.size() != 4) {
|
||||
reply = http::Reply::stockReply(http::Reply::badRequest);
|
||||
return;
|
||||
}
|
||||
|
||||
int lat1 = static_cast<int>(100000.*atof(parameters[0].c_str()));
|
||||
int lon1 = static_cast<int>(100000.*atof(parameters[1].c_str()));
|
||||
int lat2 = static_cast<int>(100000.*atof(parameters[2].c_str()));
|
||||
int lon2 = static_cast<int>(100000.*atof(parameters[3].c_str()));
|
||||
|
||||
_Coordinate startCoord(lat1, lon1);
|
||||
_Coordinate targetCoord(lat2, lon2);
|
||||
|
||||
vector< _PathData > * path = new vector< _PathData >();
|
||||
PhantomNodes * phantomNodes = new PhantomNodes();
|
||||
sEngine->FindRoutingStarts(startCoord, targetCoord, phantomNodes);
|
||||
unsigned int distance = sEngine->ComputeRoute(phantomNodes, path, startCoord, targetCoord);
|
||||
reply.status = http::Reply::ok;
|
||||
|
||||
string tmp;
|
||||
|
||||
reply.content += ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||||
reply.content += ("<kml xmlns=\"http://www.opengis.net/kml/2.2\">");
|
||||
reply.content += ("<Document>");
|
||||
|
||||
/* if(distance != std::numeric_limits<unsigned int>::max())
|
||||
computeDescription(tmp, path, phantomNodes);
|
||||
cout << tmp << endl;
|
||||
*/
|
||||
// reply.content += tmp;
|
||||
reply.content += ("<Placemark>");
|
||||
reply.content += ("<name>OSM Routing Engine (c) Dennis Luxen and others </name>");
|
||||
|
||||
reply.content += "<description>Route from ";
|
||||
convertLatLon(lat1, tmp);
|
||||
reply.content += tmp;
|
||||
reply.content += ",";
|
||||
convertLatLon(lon1, tmp);
|
||||
reply.content += tmp;
|
||||
reply.content += " to ";
|
||||
convertLatLon(lat2, tmp);
|
||||
reply.content += tmp;
|
||||
reply.content += ",";
|
||||
convertLatLon(lon2, tmp);
|
||||
reply.content += tmp;
|
||||
reply.content += "</description> ";
|
||||
reply.content += ("<LineString>");
|
||||
reply.content += ("<extrude>1</extrude>");
|
||||
reply.content += ("<tessellate>1</tessellate>");
|
||||
reply.content += ("<altitudeMode>absolute</altitudeMode>");
|
||||
reply.content += ("<coordinates>");
|
||||
|
||||
|
||||
if(distance != std::numeric_limits<unsigned int>::max())
|
||||
{ //A route has been found
|
||||
convertLatLon(phantomNodes->startCoord.lon, tmp);
|
||||
reply.content += tmp;
|
||||
reply.content += (",");
|
||||
doubleToString(phantomNodes->startCoord.lat/100000., tmp);
|
||||
reply.content += tmp;
|
||||
reply.content += (" ");
|
||||
_Coordinate result;
|
||||
for(vector< _PathData >::iterator it = path->begin(); it != path->end(); it++)
|
||||
{
|
||||
sEngine->getNodeInfo(it->node, result);
|
||||
convertLatLon(result.lon, tmp);
|
||||
reply.content += tmp;
|
||||
reply.content += (",");
|
||||
convertLatLon(result.lat, tmp);
|
||||
reply.content += tmp;
|
||||
reply.content += (" ");
|
||||
}
|
||||
|
||||
convertLatLon(phantomNodes->targetCoord.lon, tmp);
|
||||
reply.content += tmp;
|
||||
reply.content += (",");
|
||||
convertLatLon(phantomNodes->targetCoord.lat, tmp);
|
||||
reply.content += tmp;
|
||||
}
|
||||
|
||||
reply.content += ("</coordinates>");
|
||||
reply.content += ("</LineString>");
|
||||
reply.content += ("</Placemark>");
|
||||
reply.content += ("</Document>");
|
||||
reply.content += ("</kml>");
|
||||
|
||||
reply.headers.resize(3);
|
||||
reply.headers[0].name = "Content-Length";
|
||||
intToString(reply.content.size(), tmp);
|
||||
reply.headers[0].value = tmp;
|
||||
reply.headers[1].name = "Content-Type";
|
||||
reply.headers[1].value = "application/vnd.google-earth.kml+xml";
|
||||
reply.headers[2].name = "Content-Disposition";
|
||||
reply.headers[2].value = "attachment; filename=\"route.kml\"";
|
||||
|
||||
delete path;
|
||||
delete phantomNodes;
|
||||
return;
|
||||
}
|
||||
private:
|
||||
// void computeDescription(string &tmp, vector< _PathData > * path, PhantomNodes * phantomNodes)
|
||||
// {
|
||||
// _Coordinate previous(phantomNodes->startCoord.lat, phantomNodes->startCoord.lon);
|
||||
// _Coordinate next, current, lastPlace;
|
||||
// stringstream numberString;
|
||||
//
|
||||
// double tempDist = 0;
|
||||
// NodeID nextID = UINT_MAX;
|
||||
// NodeID nameID = sEngine->GetNameIDForOriginDestinationNodeID(phantomNodes->startNode1, phantomNodes->startNode2);
|
||||
// short type = sEngine->GetTypeOfEdgeForOriginDestinationNodeID(phantomNodes->startNode1, phantomNodes->startNode2);
|
||||
// lastPlace.lat = phantomNodes->startCoord.lat;
|
||||
// lastPlace.lon = phantomNodes->startCoord.lon;
|
||||
// short nextType = SHRT_MAX;
|
||||
// short prevType = SHRT_MAX;
|
||||
// tmp += "<Placemark>\n <Name>";
|
||||
// for(vector< _PathData >::iterator it = path->begin(); it != path->end(); it++)
|
||||
// {
|
||||
// sEngine->getNodeInfo(it->node, current);
|
||||
// if(it==path->end()-1){
|
||||
// next = _Coordinate(phantomNodes->targetCoord.lat, phantomNodes->targetCoord.lon);
|
||||
// nextID = sEngine->GetNameIDForOriginDestinationNodeID(phantomNodes->targetNode1, phantomNodes->targetNode2);
|
||||
// nextType = sEngine->GetTypeOfEdgeForOriginDestinationNodeID(phantomNodes->targetNode1, phantomNodes->targetNode2);
|
||||
// } else {
|
||||
// sEngine->getNodeInfo((it+1)->node, next);
|
||||
// nextID = sEngine->GetNameIDForOriginDestinationNodeID(it->node, (it+1)->node);
|
||||
// nextType = sEngine->GetTypeOfEdgeForOriginDestinationNodeID(it->node, (it+1)->node);
|
||||
// }
|
||||
// if(nextID == nameID) {
|
||||
// tempDist += ApproximateDistance(previous.lat, previous.lon, current.lat, current.lon);
|
||||
// } else {
|
||||
// if(type == 0 && prevType != 0)
|
||||
// tmp += "enter motorway and ";
|
||||
// if(type != 0 && prevType == 0 )
|
||||
// tmp += "leave motorway and ";
|
||||
//
|
||||
// double angle = GetAngleBetweenTwoEdges(previous, current, next);
|
||||
//// if(it->turn)
|
||||
//// tmp += " turn! ";
|
||||
// tmp += "follow road ";
|
||||
// if(nameID != 0)
|
||||
// tmp += sEngine->GetNameForNameID(nameID);
|
||||
// tmp += " (type: ";
|
||||
// numberString << type;
|
||||
// tmp += numberString.str();
|
||||
// numberString.str("");
|
||||
// tmp += ", id: ";
|
||||
// numberString << nameID;
|
||||
// tmp += numberString.str();
|
||||
// numberString.str("");
|
||||
// tmp += ")</Name>\n <Description>drive for ";
|
||||
// numberString << ApproximateDistance(previous.lat, previous.lon, current.lat, current.lon)+tempDist;
|
||||
// tmp += numberString.str();
|
||||
// numberString.str("");
|
||||
// tmp += "m </Description>";
|
||||
// string lat; string lon;
|
||||
// convertLatLon(lastPlace.lon, lon);
|
||||
// convertLatLon(lastPlace.lat, lat);
|
||||
// lastPlace = current;
|
||||
// tmp += "\n <Point><Coordinates>";
|
||||
// tmp += lon;
|
||||
// tmp += ",";
|
||||
// tmp += lat;
|
||||
// tmp += "</Coordinates></Point>";
|
||||
// tmp += "\n</Placemark>\n";
|
||||
// tmp += "<Placemark>\n <Name> (";
|
||||
// numberString << angle;
|
||||
// tmp += numberString.str();
|
||||
// numberString.str("");
|
||||
// tmp +=") ";
|
||||
// if(angle > 160 && angle < 200) {
|
||||
// tmp += /* " (" << angle << ")*/"drive ahead, ";
|
||||
// } else if (angle > 290 && angle <= 360) {
|
||||
// tmp += /*" (" << angle << ")*/ "turn sharp left, ";
|
||||
// } else if (angle > 230 && angle <= 290) {
|
||||
// tmp += /*" (" << angle << ")*/ "turn left, ";
|
||||
// } else if (angle > 200 && angle <= 230) {
|
||||
// tmp += /*" (" << angle << ") */"bear left, ";
|
||||
// } else if (angle > 130 && angle <= 160) {
|
||||
// tmp += /*" (" << angle << ") */"bear right, ";
|
||||
// } else if (angle > 70 && angle <= 130) {
|
||||
// tmp += /*" (" << angle << ") */"turn right, ";
|
||||
// } else {
|
||||
// tmp += /*" (" << angle << ") */"turn sharp right, ";
|
||||
// }
|
||||
// tempDist = 0;
|
||||
// prevType = type;
|
||||
// }
|
||||
// nameID = nextID;
|
||||
// previous = current;
|
||||
// type = nextType;
|
||||
// }
|
||||
// nameID = sEngine->GetNameIDForOriginDestinationNodeID(phantomNodes->targetNode1, phantomNodes->targetNode2);
|
||||
// type = sEngine->GetTypeOfEdgeForOriginDestinationNodeID(phantomNodes->targetNode1, phantomNodes->targetNode2);
|
||||
// tmp += "follow road ";
|
||||
// tmp += sEngine->GetNameForNameID(nameID);
|
||||
// tmp += " (type: ";
|
||||
// numberString << type;
|
||||
// tmp += numberString.str();
|
||||
// numberString.str("");
|
||||
// tmp += ", id: ";
|
||||
// numberString << nameID;
|
||||
// tmp += numberString.str();
|
||||
// numberString.str("");
|
||||
// tmp += ")</name>\n <Description> drive for ";
|
||||
// numberString << ApproximateDistance(previous.lat, previous.lon, phantomNodes->targetCoord.lat, phantomNodes->targetCoord.lon) + tempDist;
|
||||
// tmp += numberString.str();
|
||||
// numberString.str("");
|
||||
// tmp += "m</Description>\n ";
|
||||
// string lat; string lon;
|
||||
// convertLatLon(lastPlace.lon, lon);
|
||||
// convertLatLon(lastPlace.lat, lat);
|
||||
// tmp += "<Point><Coordinates>";
|
||||
// tmp += lon;
|
||||
// tmp += ",";
|
||||
// tmp += lat;
|
||||
// tmp += "</Coordinates></Point>";
|
||||
// tmp += "</Placemark>\n";
|
||||
// tmp += "<Placemark>\n <Name>you have reached your destination</Name>\n ";
|
||||
// tmp += "<Description>End of Route</Description>";
|
||||
// convertLatLon(phantomNodes->targetCoord.lon, lon);
|
||||
// convertLatLon(phantomNodes->targetCoord.lat, lat);
|
||||
// tmp += "\n <Point><Coordinates>";
|
||||
// tmp += lon;
|
||||
// tmp += ",";
|
||||
// tmp += lat;
|
||||
// tmp +="</Coordinates></Point>\n";
|
||||
// tmp += "</Placemark>";
|
||||
// }
|
||||
|
||||
NodeInformationHelpDesk * nodeHelpDesk;
|
||||
SearchEngine<EdgeData, StaticGraph<EdgeData> > * sEngine;
|
||||
std::vector<std::string> * names;
|
||||
StaticGraph<EdgeData> * graph;
|
||||
};
|
||||
|
||||
|
||||
#endif /* ROUTEPLUGIN_H_ */
|
112
Server/BasicDatastructures.h
Normal file
112
Server/BasicDatastructures.h
Normal file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef BASIC_DATASTRUCTURES_H
|
||||
#define BASIC_DATASTRUCTURES_H
|
||||
|
||||
#include <string>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
namespace http {
|
||||
|
||||
const std::string okString = "HTTP/1.0 200 OK\r\n";
|
||||
const std::string badRequestString = "HTTP/1.0 400 Bad Request\r\n";
|
||||
const std::string internalServerErrorString = "HTTP/1.0 500 Internal Server Error\r\n";
|
||||
|
||||
const char okHTML[] = "";
|
||||
const char badRequestHTML[] = "<html><head><title>Bad Request</title></head><body><h1>400 Bad Request</h1></body></html>";
|
||||
const char internalServerErrorHTML[] = "<html><head><title>Internal Server Error</title></head><body><h1>500 Internal Server Error</h1></body></html>";
|
||||
const char seperators[] = { ':', ' ' };
|
||||
const char crlf[] = { '\r', '\n' };
|
||||
|
||||
struct Header {
|
||||
std::string name;
|
||||
std::string value;
|
||||
};
|
||||
|
||||
struct Request {
|
||||
std::string uri;
|
||||
};
|
||||
|
||||
struct Reply {
|
||||
Reply() { content.reserve(1000000); }
|
||||
enum status_type {
|
||||
ok = 200,
|
||||
badRequest = 400,
|
||||
internalServerError = 500
|
||||
} status;
|
||||
|
||||
std::vector<Header> headers;
|
||||
std::string content;
|
||||
std::vector<boost::asio::const_buffer> toBuffers();
|
||||
static Reply stockReply(status_type status);
|
||||
};
|
||||
|
||||
boost::asio::const_buffer ToBuffer(Reply::status_type status) {
|
||||
switch (status) {
|
||||
case Reply::ok:
|
||||
return boost::asio::buffer(okString);
|
||||
case Reply::internalServerError:
|
||||
return boost::asio::buffer(internalServerErrorString);
|
||||
default:
|
||||
return boost::asio::buffer(badRequestString);
|
||||
}
|
||||
}
|
||||
|
||||
std::string ToString(Reply::status_type status) {
|
||||
switch (status) {
|
||||
case Reply::ok:
|
||||
return okHTML;
|
||||
case Reply::badRequest:
|
||||
return badRequestHTML;
|
||||
default:
|
||||
return internalServerErrorHTML;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<boost::asio::const_buffer> Reply::toBuffers(){
|
||||
std::vector<boost::asio::const_buffer> buffers;
|
||||
buffers.push_back(ToBuffer(status));
|
||||
for (std::size_t i = 0; i < headers.size(); ++i) {
|
||||
Header& h = headers[i];
|
||||
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;
|
||||
}
|
||||
|
||||
Reply Reply::stockReply(Reply::status_type status) {
|
||||
Reply rep;
|
||||
rep.status = status;
|
||||
rep.content = ToString(status);
|
||||
rep.headers.resize(2);
|
||||
rep.headers[0].name = "Content-Length";
|
||||
rep.headers[0].value = boost::lexical_cast<std::string>(rep.content.size());
|
||||
rep.headers[1].name = "Content-Type";
|
||||
rep.headers[1].value = "text/html";
|
||||
return rep;
|
||||
}
|
||||
} // namespace http
|
||||
|
||||
#endif //BASIC_DATASTRUCTURES_H
|
94
Server/Connection.h
Normal file
94
Server/Connection.h
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef CONNECTION_H
|
||||
#define CONNECTION_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/array.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/enable_shared_from_this.hpp>
|
||||
#include "BasicDatastructures.h"
|
||||
#include "RequestHandler.h"
|
||||
#include "RequestParser.h"
|
||||
|
||||
namespace http {
|
||||
|
||||
/// Represents a single connection from a client.
|
||||
class Connection : public boost::enable_shared_from_this<Connection>, private boost::noncopyable {
|
||||
public:
|
||||
explicit Connection(boost::asio::io_service& io_service, RequestHandler& handler) : strand(io_service), TCPsocket(io_service), requestHandler(handler) {}
|
||||
|
||||
boost::asio::ip::tcp::socket& socket() {
|
||||
return TCPsocket;
|
||||
}
|
||||
|
||||
/// Start the first asynchronous operation for the connection.
|
||||
void start() {
|
||||
TCPsocket.async_read_some(boost::asio::buffer(incomingDataBuffer), strand.wrap( boost::bind(&Connection::handleRead, this->shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)));
|
||||
}
|
||||
|
||||
private:
|
||||
void handleRead(const boost::system::error_code& e, std::size_t bytes_transferred) {
|
||||
if (!e) {
|
||||
boost::tribool result;
|
||||
boost::tie(result, boost::tuples::ignore) = requestParser.Parse( request, incomingDataBuffer.data(), incomingDataBuffer.data() + bytes_transferred);
|
||||
|
||||
if (result) {
|
||||
requestHandler.handle_request(request, reply);
|
||||
boost::asio::async_write(TCPsocket, reply.toBuffers(), strand.wrap( boost::bind(&Connection::handleWrite, this->shared_from_this(), boost::asio::placeholders::error)));
|
||||
} else if (!result) {
|
||||
reply = Reply::stockReply(Reply::badRequest);
|
||||
boost::asio::async_write(TCPsocket, reply.toBuffers(), strand.wrap( boost::bind(&Connection::handleWrite, this->shared_from_this(), boost::asio::placeholders::error)));
|
||||
} else {
|
||||
TCPsocket.async_read_some(boost::asio::buffer(incomingDataBuffer), strand.wrap( boost::bind(&Connection::handleRead, this->shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle completion of a write operation.
|
||||
void handleWrite(const boost::system::error_code& e) {
|
||||
if (!e) {
|
||||
// Initiate graceful connection closure.
|
||||
boost::system::error_code ignoredEC;
|
||||
TCPsocket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignoredEC);
|
||||
}
|
||||
// No new asynchronous operations are started. This means that all shared_ptr
|
||||
// references to the connection object will disappear and the object will be
|
||||
// destroyed automatically after this handler returns. The connection class's
|
||||
// destructor closes the socket.
|
||||
}
|
||||
|
||||
boost::asio::io_service::strand strand;
|
||||
boost::asio::ip::tcp::socket TCPsocket;
|
||||
RequestHandler& requestHandler;
|
||||
boost::array<char, 8192> incomingDataBuffer;
|
||||
Request request;
|
||||
RequestParser requestParser;
|
||||
Reply reply;
|
||||
};
|
||||
|
||||
} // namespace http
|
||||
|
||||
#endif // CONNECTION_H
|
85
Server/RequestHandler.h
Normal file
85
Server/RequestHandler.h
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef REQUEST_HANDLER_H
|
||||
#define REQUEST_HANDLER_H
|
||||
|
||||
#include <iostream>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
#include "BasicDatastructures.h"
|
||||
|
||||
#include "../DataStructures/HashTable.h"
|
||||
#include "../Plugins/BasePlugin.h"
|
||||
|
||||
namespace http {
|
||||
|
||||
class RequestHandler : private boost::noncopyable {
|
||||
public:
|
||||
explicit RequestHandler() { }
|
||||
|
||||
~RequestHandler() {
|
||||
pluginMap.EraseAll();
|
||||
}
|
||||
|
||||
void handle_request(const Request& req, Reply& rep){
|
||||
//parse command
|
||||
std::string request(req.uri);
|
||||
std::string command;
|
||||
std::size_t firstAmpPosition = request.find_first_of("&");
|
||||
command = request.substr(1,firstAmpPosition-1);
|
||||
std::cout << "[debug] looking for handler for command: " << command << std::endl;
|
||||
try {
|
||||
if(pluginMap.Holds(command)) {
|
||||
|
||||
std::vector<std::string> parameters;
|
||||
std::stringstream ss(( firstAmpPosition == std::string::npos ? "" : request.substr(firstAmpPosition+1) ));
|
||||
std::string item;
|
||||
while(std::getline(ss, item, '&')) {
|
||||
parameters.push_back(item);
|
||||
}
|
||||
// std::cout << "[debug] found handler for '" << command << "' at version: " << pluginMap.Find(command)->GetVersionString() << std::endl;
|
||||
// std::cout << "[debug] remaining parameters: " << parameters.size() << std::endl;
|
||||
rep.status = Reply::ok;
|
||||
pluginMap.Find(command)->HandleRequest(parameters, rep );
|
||||
} else {
|
||||
rep = Reply::stockReply(Reply::badRequest);
|
||||
}
|
||||
return;
|
||||
} catch(std::exception& e) {
|
||||
rep = Reply::stockReply(Reply::internalServerError);
|
||||
std::cerr << "[server error] code: " << e.what() << ", uri: " << req.uri << std::endl;
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
void RegisterPlugin(BasePlugin * plugin) {
|
||||
std::cout << "[handler] registering plugin " << plugin->GetDescriptor() << std::endl;
|
||||
pluginMap.Add(plugin->GetDescriptor(), plugin);
|
||||
}
|
||||
|
||||
private:
|
||||
boost::mutex pluginMutex;
|
||||
HashTable<std::string, BasePlugin *> pluginMap;
|
||||
};
|
||||
} // namespace http
|
||||
|
||||
#endif // REQUEST_HANDLER_H
|
271
Server/RequestParser.h
Normal file
271
Server/RequestParser.h
Normal file
@ -0,0 +1,271 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef REQUEST_PARSER_H
|
||||
#define REQUEST_PARSER_H
|
||||
|
||||
#include <boost/logic/tribool.hpp>
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
#include "BasicDatastructures.h"
|
||||
|
||||
namespace http {
|
||||
|
||||
class RequestParser {
|
||||
public:
|
||||
RequestParser() : state_(method_start) { }
|
||||
void Reset() { state_ = method_start; }
|
||||
|
||||
boost::tuple<boost::tribool, char*> Parse(Request& req, char* begin, char* end) {
|
||||
while (begin != end) {
|
||||
boost::tribool result = consume(req, *begin++);
|
||||
if (result || !result){
|
||||
return boost::make_tuple(result, begin);
|
||||
}
|
||||
}
|
||||
boost::tribool result = boost::indeterminate;
|
||||
return boost::make_tuple(result, begin);
|
||||
}
|
||||
|
||||
private:
|
||||
boost::tribool consume(Request& req, char input) {
|
||||
switch (state_) {
|
||||
case method_start:
|
||||
if (!isChar(input) || isCTL(input) || isTSpecial(input)) {
|
||||
return false;
|
||||
} else {
|
||||
state_ = method;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
case method:
|
||||
if (input == ' ') {
|
||||
state_ = uri;
|
||||
return boost::indeterminate;
|
||||
} else if (!isChar(input) || isCTL(input) || isTSpecial(input)) {
|
||||
return false;
|
||||
} else {
|
||||
return boost::indeterminate;
|
||||
}
|
||||
case uri_start:
|
||||
if (isCTL(input)) {
|
||||
return false;
|
||||
} else {
|
||||
state_ = uri;
|
||||
req.uri.push_back(input);
|
||||
return boost::indeterminate;
|
||||
}
|
||||
case uri:
|
||||
if (input == ' ') {
|
||||
state_ = http_version_h;
|
||||
return boost::indeterminate;
|
||||
} else if (isCTL(input)) {
|
||||
return false;
|
||||
} else {
|
||||
req.uri.push_back(input);
|
||||
return boost::indeterminate;
|
||||
}
|
||||
case http_version_h:
|
||||
if (input == 'H') {
|
||||
state_ = http_version_t_1;
|
||||
return boost::indeterminate;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
case http_version_t_1:
|
||||
if (input == 'T') {
|
||||
state_ = http_version_t_2;
|
||||
return boost::indeterminate;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
case http_version_t_2:
|
||||
if (input == 'T') {
|
||||
state_ = http_version_p;
|
||||
return boost::indeterminate;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
case http_version_p:
|
||||
if (input == 'P') {
|
||||
state_ = http_version_slash;
|
||||
return boost::indeterminate;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
case http_version_slash:
|
||||
if (input == '/') {
|
||||
state_ = http_version_major_start;
|
||||
return boost::indeterminate;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
case http_version_major_start:
|
||||
if (isDigit(input)) {
|
||||
state_ = http_version_major;
|
||||
return boost::indeterminate;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
case http_version_major:
|
||||
if (input == '.') {
|
||||
state_ = http_version_minor_start;
|
||||
return boost::indeterminate;
|
||||
} else if (isDigit(input)) {
|
||||
return boost::indeterminate;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
case http_version_minor_start:
|
||||
if (isDigit(input)) {
|
||||
state_ = http_version_minor;
|
||||
return boost::indeterminate;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
case http_version_minor:
|
||||
if (input == '\r') {
|
||||
state_ = expecting_newline_1;
|
||||
return boost::indeterminate;
|
||||
} else if (isDigit(input)) {
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
case expecting_newline_1:
|
||||
if (input == '\n') {
|
||||
state_ = header_line_start;
|
||||
return boost::indeterminate;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
case header_line_start:
|
||||
if (input == '\r') {
|
||||
state_ = expecting_newline_3;
|
||||
return boost::indeterminate;
|
||||
} else if (!isChar(input) || isCTL(input) || isTSpecial(input)) {
|
||||
return false;
|
||||
} else {
|
||||
state_ = header_name;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
case header_lws:
|
||||
if (input == '\r') {
|
||||
state_ = expecting_newline_2;
|
||||
return boost::indeterminate;
|
||||
} else if (input == ' ' || input == '\t') {
|
||||
return boost::indeterminate;
|
||||
}
|
||||
else if (isCTL(input)) {
|
||||
return false;
|
||||
} else {
|
||||
state_ = header_value;
|
||||
return boost::indeterminate;
|
||||
}
|
||||
case header_name:
|
||||
if (input == ':') {
|
||||
state_ = space_before_header_value;
|
||||
return boost::indeterminate;
|
||||
} else if (!isChar(input) || isCTL(input) || isTSpecial(input)) {
|
||||
return false;
|
||||
} else {
|
||||
return boost::indeterminate;
|
||||
}
|
||||
case space_before_header_value:
|
||||
if (input == ' ') {
|
||||
state_ = header_value;
|
||||
return boost::indeterminate;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
case header_value:
|
||||
if (input == '\r') {
|
||||
state_ = expecting_newline_2;
|
||||
return boost::indeterminate;
|
||||
} else if (isCTL(input)) {
|
||||
return false;
|
||||
} else {
|
||||
return boost::indeterminate;
|
||||
}
|
||||
case expecting_newline_2:
|
||||
if (input == '\n') {
|
||||
state_ = header_line_start;
|
||||
return boost::indeterminate;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
case expecting_newline_3:
|
||||
return (input == '\n');
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool isChar(int c) {
|
||||
return c >= 0 && c <= 127;
|
||||
}
|
||||
|
||||
inline bool isCTL(int c) {
|
||||
return (c >= 0 && c <= 31) || (c == 127);
|
||||
}
|
||||
|
||||
inline bool isTSpecial(int c) {
|
||||
switch (c) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool isDigit(int c) {
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
||||
|
||||
enum state {
|
||||
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_;
|
||||
};
|
||||
|
||||
} // namespace http
|
||||
|
||||
#endif // REQUEST_PARSER_H
|
90
Server/Server.h
Normal file
90
Server/Server.h
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef SERVER_H
|
||||
#define SERVER_H
|
||||
|
||||
#include <vector>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
#include "Connection.h"
|
||||
#include "RequestHandler.h"
|
||||
|
||||
namespace http {
|
||||
|
||||
class Server: private boost::noncopyable {
|
||||
public:
|
||||
explicit Server(const std::string& address, const std::string& port, unsigned thread_pool_size) : threadPoolSize(thread_pool_size), acceptor(ioService), newConnection(new Connection(ioService, requestHandler)), requestHandler(){
|
||||
boost::asio::ip::tcp::resolver resolver(ioService);
|
||||
boost::asio::ip::tcp::resolver::query query(address, port);
|
||||
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(newConnection->socket(), boost::bind(&Server::handleAccept, this, boost::asio::placeholders::error));
|
||||
}
|
||||
|
||||
void Run() {
|
||||
std::vector<boost::shared_ptr<boost::thread> > threads;
|
||||
for (unsigned i = 0; i < threadPoolSize; ++i) {
|
||||
boost::shared_ptr<boost::thread> thread(new boost::thread(boost::bind(&boost::asio::io_service::run, &ioService)));
|
||||
threads.push_back(thread);
|
||||
}
|
||||
for (unsigned i = 0; i < threads.size(); ++i)
|
||||
threads[i]->join();
|
||||
}
|
||||
|
||||
void Stop() {
|
||||
ioService.stop();
|
||||
}
|
||||
|
||||
|
||||
|
||||
RequestHandler * GetRequestHandlerPtr() {
|
||||
return &requestHandler;
|
||||
}
|
||||
|
||||
private:
|
||||
typedef boost::shared_ptr<Connection > ConnectionPtr;
|
||||
|
||||
void handleAccept(const boost::system::error_code& e) {
|
||||
if (!e) {
|
||||
newConnection->start();
|
||||
newConnection.reset(new Connection(ioService, requestHandler));
|
||||
acceptor.async_accept(newConnection->socket(), boost::bind(&Server::handleAccept, this, boost::asio::placeholders::error));
|
||||
}
|
||||
}
|
||||
|
||||
unsigned threadPoolSize;
|
||||
boost::asio::io_service ioService;
|
||||
boost::asio::ip::tcp::acceptor acceptor;
|
||||
ConnectionPtr newConnection;
|
||||
RequestHandler requestHandler;
|
||||
};
|
||||
|
||||
} // namespace http
|
||||
|
||||
#endif // SERVER_H
|
15
Server/ServerConfiguration.h
Normal file
15
Server/ServerConfiguration.h
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* ServerConfiguration.h
|
||||
*
|
||||
* Created on: 26.11.2010
|
||||
* Author: dennis
|
||||
*/
|
||||
|
||||
#ifndef SERVERCONFIGURATION_H_
|
||||
#define SERVERCONFIGURATION_H_
|
||||
|
||||
#include "../Util/BaseConfiguration.h"
|
||||
|
||||
typedef BaseConfiguration ServerConfiguration;
|
||||
|
||||
#endif /* SERVERCONFIGURATION_H_ */
|
88
Server/ServerFactory.h
Normal file
88
Server/ServerFactory.h
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
|
||||
Created on: 26.11.2010
|
||||
Author: dennis
|
||||
|
||||
*/
|
||||
|
||||
#ifndef SERVERFACTORY_H_
|
||||
#define SERVERFACTORY_H_
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#ifdef _OPENMP
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
#include "Server.h"
|
||||
#include "ServerConfiguration.h"
|
||||
|
||||
#include "../Util/InputFileUtil.h"
|
||||
|
||||
typedef http::Server Server;
|
||||
|
||||
struct ServerFactory {
|
||||
static Server * CreateServer(ServerConfiguration& serverConfig) {
|
||||
|
||||
if(!testDataFile(serverConfig.GetParameter("nodesData").c_str())) {
|
||||
std::cerr << "[error] nodes file not found" << std::endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if(!testDataFile(serverConfig.GetParameter("hsgrData").c_str())) {
|
||||
std::cerr << "[error] hsgr file not found" << std::endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if(!testDataFile(serverConfig.GetParameter("namesData").c_str())) {
|
||||
std::cerr << "[error] names file not found" << std::endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if(!testDataFile(serverConfig.GetParameter("ramIndex").c_str())) {
|
||||
std::cerr << "[error] ram index file not found" << std::endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if(!testDataFile(serverConfig.GetParameter("fileIndex").c_str())) {
|
||||
std::cerr << "[error] file index file not found" << std::endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
unsigned threads = omp_get_num_procs();
|
||||
if(serverConfig.GetParameter("IP") == "")
|
||||
serverConfig.SetParameter("IP", "0.0.0.0");
|
||||
if(serverConfig.GetParameter("Port") == "")
|
||||
serverConfig.SetParameter("Port", "5000");
|
||||
|
||||
if(atoi(serverConfig.GetParameter("Threads").c_str()) != 0 && atoi(serverConfig.GetParameter("Threads").c_str()) <= threads)
|
||||
threads = atoi( serverConfig.GetParameter("Threads").c_str() );
|
||||
|
||||
Server * server = new Server(serverConfig.GetParameter("IP"), serverConfig.GetParameter("Port"), threads);
|
||||
return server;
|
||||
}
|
||||
|
||||
static Server * CreateServer(const char * iniFile) {
|
||||
ServerConfiguration serverConfig(iniFile);
|
||||
return CreateServer(serverConfig);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* SERVERFACTORY_H_ */
|
68
Util/BaseConfiguration.h
Normal file
68
Util/BaseConfiguration.h
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* BaseConfiguration.h
|
||||
*
|
||||
* Created on: 26.11.2010
|
||||
* Author: dennis
|
||||
*/
|
||||
|
||||
#ifndef BASECONFIGURATION_H_
|
||||
#define BASECONFIGURATION_H_
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <exception>
|
||||
#include <fstream>
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/program_options/detail/config_file.hpp>
|
||||
#include <boost/program_options/parsers.hpp>
|
||||
|
||||
#include "../DataStructures/HashTable.h"
|
||||
|
||||
class BaseConfiguration {
|
||||
public:
|
||||
BaseConfiguration(const char * configFile) {
|
||||
std::ifstream config( configFile );
|
||||
if(!config) {
|
||||
std::cerr << "[config] .ini not found" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
//parameters
|
||||
options.insert("*");
|
||||
|
||||
try {
|
||||
for (boost::program_options::detail::config_file_iterator i(config, options), e ; i != e; ++i) {
|
||||
std::cout << "[config] " << i->string_key << " = " << i->value[0] << std::endl;
|
||||
parameters.Add(i->string_key, i->value[0]);
|
||||
}
|
||||
} catch(std::exception& e) {
|
||||
std::cerr << "[config] .ini not found -> Exception: " <<e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
std::string GetParameter(const char * key){
|
||||
return GetParameter(std::string(key));
|
||||
}
|
||||
|
||||
std::string GetParameter(std::string key) {
|
||||
return parameters.Find(key);
|
||||
}
|
||||
|
||||
void SetParameter(const char* key, const char* value) {
|
||||
SetParameter(std::string(key), std::string(value));
|
||||
}
|
||||
|
||||
void SetParameter(std::string key, std::string value) {
|
||||
parameters.Set(key, value);
|
||||
}
|
||||
|
||||
private:
|
||||
std::set<std::string> options;
|
||||
HashTable<std::string, std::string> parameters;
|
||||
//Speichert alle Einträge aus INI Datei
|
||||
};
|
||||
|
||||
#endif /* BASECONFIGURATION_H_ */
|
142
Util/GraphLoader.h
Normal file
142
Util/GraphLoader.h
Normal file
@ -0,0 +1,142 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef CREATEGRAPH_H
|
||||
#define GRAPHLOADER_H
|
||||
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <vector>
|
||||
|
||||
#include <google/dense_hash_map>
|
||||
|
||||
#ifdef _GLIBCXX_PARALLEL
|
||||
#include <parallel/algorithm>
|
||||
#else
|
||||
#include <algorithm>
|
||||
#endif
|
||||
|
||||
#include "../DataStructures/ImportEdge.h"
|
||||
#include "../typedefs.h"
|
||||
|
||||
typedef google::dense_hash_map<NodeID, NodeID> ExternalNodeMap;
|
||||
|
||||
template<typename EdgeT>
|
||||
NodeID readOSRMGraphFromStream(istream &in, vector<EdgeT>& edgeList, vector<NodeInfo> * int2ExtNodeMap) {
|
||||
NodeID n, source, target, id;
|
||||
EdgeID m;
|
||||
short locatable;
|
||||
int dir, xcoord, ycoord;// direction (0 = open, 1 = forward, 2+ = open)
|
||||
ExternalNodeMap ext2IntNodeMap;
|
||||
ext2IntNodeMap.set_empty_key(UINT_MAX);
|
||||
in >> n;
|
||||
VERBOSE(cout << "Importing n = " << n << " nodes ..." << flush;)
|
||||
for (NodeID i=0; i<n;i++) {
|
||||
in >> id >> ycoord >> xcoord;
|
||||
int2ExtNodeMap->push_back(NodeInfo(xcoord, ycoord, id));
|
||||
ext2IntNodeMap.insert(make_pair(id, i));
|
||||
}
|
||||
in >> m;
|
||||
VERBOSE(cout << " and " << m << " edges ..." << flush;)
|
||||
|
||||
edgeList.reserve(m);
|
||||
for (EdgeID i=0; i<m; i++) {
|
||||
EdgeWeight weight;
|
||||
short type;
|
||||
NodeID nameID;
|
||||
int length;
|
||||
in >> source >> target >> length >> dir >> weight >> type >> nameID;
|
||||
assert(length > 0);
|
||||
assert(weight > 0);
|
||||
assert(0<=dir && dir<=2);
|
||||
|
||||
bool forward = true;
|
||||
bool backward = true;
|
||||
if (dir == 1) backward = false;
|
||||
if (dir == 2) forward = false;
|
||||
|
||||
if(length == 0)
|
||||
{ cerr << "loaded null length edge" << endl; exit(1); }
|
||||
|
||||
// translate the external NodeIDs to internal IDs
|
||||
ExternalNodeMap::iterator intNodeID = ext2IntNodeMap.find(source);
|
||||
if( ext2IntNodeMap.find(source) == ext2IntNodeMap.end())
|
||||
{
|
||||
cerr << "after " << edgeList.size() << " edges" << endl;
|
||||
cerr << "->" << source << "," << target << "," << length << "," << dir << "," << weight << endl;
|
||||
cerr << "unresolved source NodeID: " << source << endl; exit(0);
|
||||
}
|
||||
source = intNodeID->second;
|
||||
intNodeID = ext2IntNodeMap.find(target);
|
||||
if(ext2IntNodeMap.find(target) == ext2IntNodeMap.end()) { cerr << "unresolved target NodeID : " << target << endl; exit(0); }
|
||||
target = intNodeID->second;
|
||||
|
||||
if(source == UINT_MAX || target == UINT_MAX) { cerr << "nonexisting source or target" << endl; exit(0); }
|
||||
|
||||
EdgeT inputEdge(source, target, nameID, weight, forward, backward, type );
|
||||
edgeList.push_back(inputEdge);
|
||||
}
|
||||
ext2IntNodeMap.clear();
|
||||
vector<ImportEdge>(edgeList.begin(), edgeList.end()).swap(edgeList); //remove excess candidates.
|
||||
cout << "ok" << endl;
|
||||
return n;
|
||||
}
|
||||
|
||||
template<typename EdgeT>
|
||||
void readHSGRFromStream(istream &in, vector<EdgeT> * edgeList) {
|
||||
while(!in.eof())
|
||||
{
|
||||
EdgeT g;
|
||||
EdgeData e;
|
||||
|
||||
int distance;
|
||||
bool shortcut;
|
||||
bool forward;
|
||||
bool backward;
|
||||
bool forwardTurn;
|
||||
bool backwardTurn;
|
||||
short type;
|
||||
NodeID middle;
|
||||
NodeID source;
|
||||
NodeID target;
|
||||
|
||||
in.read((char *)&(distance), sizeof(int));
|
||||
assert(distance > 0);
|
||||
in.read((char *)&(forwardTurn), sizeof(bool));
|
||||
in.read((char *)&(backwardTurn), sizeof(bool));
|
||||
in.read((char *)&(shortcut), sizeof(bool));
|
||||
in.read((char *)&(forward), sizeof(bool));
|
||||
in.read((char *)&(backward), sizeof(bool));
|
||||
in.read((char *)&(middle), sizeof(NodeID));
|
||||
in.read((char *)&(type), sizeof(short));
|
||||
in.read((char *)&(source), sizeof(NodeID));
|
||||
in.read((char *)&(target), sizeof(NodeID));
|
||||
e.backward = backward; e.distance = distance; e.forward = forward; e.middleName.middle = middle; e.shortcut = shortcut; e.type = type;
|
||||
e.forwardTurn = forwardTurn; e.backwardTurn = backwardTurn;
|
||||
g.data = e; g.source = source; g.target = target;
|
||||
|
||||
edgeList->push_back(g);
|
||||
}
|
||||
|
||||
}
|
||||
#endif // CREATEGRAPH_H
|
43
Util/InputFileUtil.h
Normal file
43
Util/InputFileUtil.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, others 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef INPUTFILEUTIL_H_
|
||||
#define INPUTFILEUTIL_H_
|
||||
|
||||
#include <fstream>
|
||||
|
||||
// Check if file exists and if it can be opened for reading with ifstream an object
|
||||
bool testDataFile(const char *filename){
|
||||
std::ifstream in(filename, std::ios::binary);
|
||||
if(in.fail()) {
|
||||
std::cerr << "[error] Failed to open file " << filename << " for reading." << std::endl;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool testDataFiles(int argc, char *argv[]){
|
||||
for(int i = 0; i < argc; ++i) {
|
||||
if(testDataFile(argv[i])==false)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* INPUTFILEUTIL_H_ */
|
82
Util/StrIngUtil.h
Normal file
82
Util/StrIngUtil.h
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
open source routing machine
|
||||
Copyright (C) Dennis Luxen, 2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU AFFERO General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
|
||||
#ifndef STRINGUTIL_H_
|
||||
#define STRINGUTIL_H_
|
||||
|
||||
// precision: position after decimal point
|
||||
// length: maximum number of digits including comma and decimals
|
||||
template< int length, int precision >
|
||||
inline char* printInt( char* buffer, int value )
|
||||
{
|
||||
bool minus = false;
|
||||
if ( value < 0 ) {
|
||||
minus = true;
|
||||
value = -value;
|
||||
}
|
||||
buffer += length - 1;
|
||||
for ( int i = 0; i < precision; i++ ) {
|
||||
*buffer = '0' + ( value % 10 );
|
||||
value /= 10;
|
||||
buffer--;
|
||||
}
|
||||
*buffer = '.';
|
||||
buffer--;
|
||||
for ( int i = precision + 1; i < length; i++ ) {
|
||||
*buffer = '0' + ( value % 10 );
|
||||
value /= 10;
|
||||
if ( value == 0 ) break;
|
||||
buffer--;
|
||||
}
|
||||
if ( minus ) {
|
||||
buffer--;
|
||||
*buffer = '-';
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
inline void intToString(const int value, std::string & output)
|
||||
{
|
||||
// The largest 32-bit integer is 4294967295, that is 10 chars
|
||||
// On the safe side, add 1 for sign, and 1 for trailing zero
|
||||
char buffer[12] ;
|
||||
sprintf(buffer, "%i", value) ;
|
||||
output = buffer ;
|
||||
}
|
||||
|
||||
inline void convertLatLon(const int value, std::string & output)
|
||||
{
|
||||
char buffer[100];
|
||||
buffer[10] = 0; // Nullterminierung
|
||||
char* string = printInt< 10, 5 >( buffer, value );
|
||||
output = string;
|
||||
}
|
||||
|
||||
/* used to be boosts lexical cast, but this was too slow */
|
||||
inline void doubleToString(const double value, std::string & output)
|
||||
{
|
||||
// The largest 32-bit integer is 4294967295, that is 10 chars
|
||||
// On the safe side, add 1 for sign, and 1 for trailing zero
|
||||
char buffer[12] ;
|
||||
sprintf(buffer, "%f", value) ;
|
||||
output = buffer ;
|
||||
}
|
||||
|
||||
#endif /* STRINGUTIL_H_ */
|
1
contractor.ini
Normal file
1
contractor.ini
Normal file
@ -0,0 +1 @@
|
||||
Threads = 4
|
@ -41,12 +41,14 @@ or see http://www.gnu.org/licenses/agpl.txt.
|
||||
#endif
|
||||
|
||||
#include "typedefs.h"
|
||||
#include "Contractor/GraphLoader.h"
|
||||
#include "Contractor/BinaryHeap.h"
|
||||
#include "Contractor/Contractor.h"
|
||||
#include "Contractor/ContractionCleanup.h"
|
||||
#include "DataStructures/BinaryHeap.h"
|
||||
#include "DataStructures/NNGrid.h"
|
||||
#include "DataStructures/TurnInfoFactory.h"
|
||||
#include "Util/BaseConfiguration.h"
|
||||
#include "Util/InputFileUtil.h"
|
||||
#include "Util/GraphLoader.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@ -54,6 +56,7 @@ typedef ContractionCleanup::Edge::EdgeData EdgeData;
|
||||
typedef DynamicGraph<EdgeData>::InputEdge GridEdge;
|
||||
typedef StaticGraph<EdgeData>::InputEdge StaticEdge;
|
||||
typedef NNGrid::NNGrid<true> WritableGrid;
|
||||
typedef BaseConfiguration ContractorConfiguration;
|
||||
|
||||
vector<NodeInfo> * int2ExtNodeMap = new vector<NodeInfo>();
|
||||
|
||||
@ -64,6 +67,16 @@ int main (int argc, char *argv[])
|
||||
cerr << "usage: " << endl << argv[0] << " <osmr-data>" << endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
//todo: check if contractor exists
|
||||
unsigned numberOfThreads = omp_get_num_procs();
|
||||
if(testDataFile("contractor.ini")) {
|
||||
ContractorConfiguration contractorConfig("contractor.ini");
|
||||
if(atoi(contractorConfig.GetParameter("Threads").c_str()) != 0 && atoi(contractorConfig.GetParameter("Threads").c_str()) <= numberOfThreads)
|
||||
numberOfThreads = atoi( contractorConfig.GetParameter("Threads").c_str() );
|
||||
}
|
||||
omp_set_num_threads(numberOfThreads);
|
||||
|
||||
cout << "preprocessing data from input file " << argv[1] << endl;
|
||||
|
||||
ifstream in;
|
||||
|
@ -27,6 +27,7 @@ or see http://www.gnu.org/licenses/agpl.txt.
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@ -58,284 +59,284 @@ STXXLStringVector nameVector;
|
||||
NodeMap * nodeMap = new NodeMap();
|
||||
StringMap * stringMap = new StringMap();
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
if(argc <= 1)
|
||||
{
|
||||
cerr << "usage: " << endl << argv[0] << " <file.osm>" << endl;
|
||||
exit(-1);
|
||||
}
|
||||
cout << "extracting data from input file " << argv[1] << endl;
|
||||
cout << "reading input file. This may take some time ..." << flush;
|
||||
xmlTextReaderPtr inputReader = inputReaderFactory(argv[1]);
|
||||
|
||||
double time = get_timestamp();
|
||||
settings.speedProfile.names.insert(settings.speedProfile.names.begin(), names, names+14);
|
||||
settings.speedProfile.speed.insert(settings.speedProfile.speed.begin(), speeds, speeds+14);
|
||||
int main (int argc, char *argv[]) {
|
||||
if(argc <= 1) {
|
||||
cerr << "usage: " << endl << argv[0] << " <file.osm>" << endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
nodeMap->set_empty_key(UINT_MAX);
|
||||
stringMap->set_empty_key(GetRandomString());
|
||||
stringMap->insert(std::make_pair("", 0));
|
||||
try {
|
||||
while ( xmlTextReaderRead( inputReader ) == 1 ) {
|
||||
const int type = xmlTextReaderNodeType( inputReader );
|
||||
cout << "extracting data from input file " << argv[1] << endl;
|
||||
cout << "reading input file. This may take some time ..." << flush;
|
||||
xmlTextReaderPtr inputReader = inputReaderFactory(argv[1]);
|
||||
|
||||
//1 is Element
|
||||
if ( type != 1 )
|
||||
continue;
|
||||
double time = get_timestamp();
|
||||
settings.speedProfile.names.insert(settings.speedProfile.names.begin(), names, names+14);
|
||||
settings.speedProfile.speed.insert(settings.speedProfile.speed.begin(), speeds, speeds+14);
|
||||
|
||||
xmlChar* currentName = xmlTextReaderName( inputReader );
|
||||
if ( currentName == NULL )
|
||||
continue;
|
||||
nodeMap->set_empty_key(UINT_MAX);
|
||||
stringMap->set_empty_key(GetRandomString());
|
||||
stringMap->insert(std::make_pair("", 0));
|
||||
try {
|
||||
while ( xmlTextReaderRead( inputReader ) == 1 ) {
|
||||
const int type = xmlTextReaderNodeType( inputReader );
|
||||
|
||||
if ( xmlStrEqual( currentName, ( const xmlChar* ) "node" ) == 1 ) {
|
||||
_Node node = _ReadXMLNode( inputReader );
|
||||
allNodes.push_back(node);
|
||||
if ( node.trafficSignal )
|
||||
SignalNodes.push_back( node.id );
|
||||
//1 is Element
|
||||
if ( type != 1 )
|
||||
continue;
|
||||
|
||||
}
|
||||
if ( xmlStrEqual( currentName, ( const xmlChar* ) "way" ) == 1 ) {
|
||||
string name;
|
||||
_Way way = _ReadXMLWay( inputReader, settings, name );
|
||||
xmlChar* currentName = xmlTextReaderName( inputReader );
|
||||
if ( currentName == NULL )
|
||||
continue;
|
||||
|
||||
if ( way.usefull && way.access && way.path.size() ) {
|
||||
StringMap::iterator strit = stringMap->find(name);
|
||||
if(strit == stringMap->end())
|
||||
{
|
||||
way.nameID = nameVector.size();
|
||||
nameVector.push_back(name);
|
||||
stringMap->insert(std::make_pair(name, way.nameID) );
|
||||
// cout << "found name ID: " << way.nameID << " (" << name << ")" << endl;
|
||||
} else {
|
||||
way.nameID = strit->second;
|
||||
// cout << "name with ID " << way.nameID << " already existing (" << name << ")" << endl;
|
||||
}
|
||||
for ( unsigned i = 0; i < way.path.size(); ++i ) {
|
||||
usedNodes.push_back(way.path[i]);
|
||||
}
|
||||
if ( xmlStrEqual( currentName, ( const xmlChar* ) "node" ) == 1 ) {
|
||||
_Node node = _ReadXMLNode( inputReader );
|
||||
allNodes.push_back(node);
|
||||
if ( node.trafficSignal )
|
||||
SignalNodes.push_back( node.id );
|
||||
|
||||
if ( way.direction == _Way::opposite ){
|
||||
std::reverse( way.path.begin(), way.path.end() );
|
||||
}
|
||||
vector< NodeID > & path = way.path;
|
||||
assert(way.type > -1 || way.maximumSpeed != -1);
|
||||
assert(path.size()>0);
|
||||
}
|
||||
if ( xmlStrEqual( currentName, ( const xmlChar* ) "way" ) == 1 ) {
|
||||
string name;
|
||||
_Way way = _ReadXMLWay( inputReader, settings, name );
|
||||
|
||||
if(way.maximumSpeed == -1)
|
||||
way.maximumSpeed = settings.speedProfile.speed[way.type];
|
||||
if ( way.usefull && way.access && way.path.size() ) {
|
||||
StringMap::iterator strit = stringMap->find(name);
|
||||
if(strit == stringMap->end())
|
||||
{
|
||||
way.nameID = nameVector.size();
|
||||
nameVector.push_back(name);
|
||||
stringMap->insert(std::make_pair(name, way.nameID) );
|
||||
// cout << "found name ID: " << way.nameID << " (" << name << ")" << endl;
|
||||
} else {
|
||||
way.nameID = strit->second;
|
||||
// cout << "name with ID " << way.nameID << " already existing (" << name << ")" << endl;
|
||||
}
|
||||
for ( unsigned i = 0; i < way.path.size(); ++i ) {
|
||||
usedNodes.push_back(way.path[i]);
|
||||
}
|
||||
|
||||
for(vector< NodeID >::size_type n = 0; n < path.size()-1; n++)
|
||||
{
|
||||
_Edge e;
|
||||
e.start = way.path[n];
|
||||
e.target = way.path[n+1];
|
||||
e.type = way.type;
|
||||
e.direction = way.direction;
|
||||
e.speed = way.maximumSpeed;
|
||||
e.nameID = way.nameID;
|
||||
allEdges.push_back(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( xmlStrEqual( currentName, ( const xmlChar* ) "relation" ) == 1 ) {
|
||||
if ( way.direction == _Way::opposite ){
|
||||
std::reverse( way.path.begin(), way.path.end() );
|
||||
}
|
||||
vector< NodeID > & path = way.path;
|
||||
assert(way.type > -1 || way.maximumSpeed != -1);
|
||||
assert(path.size()>0);
|
||||
|
||||
}
|
||||
xmlFree( currentName );
|
||||
}
|
||||
cout << "raw no. of names: " << nameVector.size() << endl;
|
||||
cout << "raw no. of nodes: " << allNodes.size() << endl;
|
||||
cout << "raw no. of edges: " << allEdges.size() << endl;
|
||||
if(way.maximumSpeed == -1)
|
||||
way.maximumSpeed = settings.speedProfile.speed[way.type];
|
||||
|
||||
cout << "ok, after " << get_timestamp() - time << "s" << endl;
|
||||
time = get_timestamp();
|
||||
unsigned memory_to_use = 1024 * 1024 * 1024;
|
||||
for(vector< NodeID >::size_type n = 0; n < path.size()-1; n++)
|
||||
{
|
||||
_Edge e;
|
||||
e.start = way.path[n];
|
||||
e.target = way.path[n+1];
|
||||
e.type = way.type;
|
||||
e.direction = way.direction;
|
||||
e.speed = way.maximumSpeed;
|
||||
e.nameID = way.nameID;
|
||||
allEdges.push_back(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( xmlStrEqual( currentName, ( const xmlChar* ) "relation" ) == 1 ) {
|
||||
|
||||
cout << "Sorting used nodes ..." << flush;
|
||||
stxxl::sort(usedNodes.begin(), usedNodes.end(), Cmp(), memory_to_use);
|
||||
cout << "ok, after " << get_timestamp() - time << "s" << endl;
|
||||
time = get_timestamp();
|
||||
cout << "Erasing duplicate entries ..." << flush;
|
||||
stxxl::vector<NodeID>::iterator NewEnd = unique ( usedNodes.begin(),usedNodes.end() ) ;
|
||||
usedNodes.resize ( NewEnd - usedNodes.begin() );
|
||||
cout << "ok, after " << get_timestamp() - time << "s" << endl;
|
||||
time = get_timestamp();
|
||||
}
|
||||
xmlFree( currentName );
|
||||
}
|
||||
cout << "raw no. of names: " << nameVector.size() << endl;
|
||||
cout << "raw no. of nodes: " << allNodes.size() << endl;
|
||||
cout << "raw no. of edges: " << allEdges.size() << endl;
|
||||
|
||||
cout << "Sorting all nodes ..." << flush;
|
||||
stxxl::sort(allNodes.begin(), allNodes.end(), CmpNodeByID(), memory_to_use);
|
||||
cout << "ok, after " << get_timestamp() - time << "s" << endl;
|
||||
time = get_timestamp();
|
||||
cout << "ok, after " << get_timestamp() - time << "s" << endl;
|
||||
time = get_timestamp();
|
||||
unsigned memory_to_use = 1024 * 1024 * 1024;
|
||||
|
||||
string name(argv[1]);
|
||||
int pos;
|
||||
pos = name.find(".osm.bz2");
|
||||
if(pos!=string::npos)
|
||||
{
|
||||
name.replace(pos, 8, ".osrm");
|
||||
} else {
|
||||
pos=name.find(".osm");
|
||||
if(pos!=string::npos)
|
||||
{
|
||||
name.replace(pos, 5, ".osrm");
|
||||
} else {
|
||||
name.append(".osrm");
|
||||
}
|
||||
}
|
||||
cout << "Sorting used nodes ..." << flush;
|
||||
stxxl::sort(usedNodes.begin(), usedNodes.end(), Cmp(), memory_to_use);
|
||||
cout << "ok, after " << get_timestamp() - time << "s" << endl;
|
||||
time = get_timestamp();
|
||||
cout << "Erasing duplicate entries ..." << flush;
|
||||
stxxl::vector<NodeID>::iterator NewEnd = unique ( usedNodes.begin(),usedNodes.end() ) ;
|
||||
usedNodes.resize ( NewEnd - usedNodes.begin() );
|
||||
cout << "ok, after " << get_timestamp() - time << "s" << endl;
|
||||
time = get_timestamp();
|
||||
|
||||
ofstream fout;
|
||||
fout.open(name.c_str());
|
||||
cout << "Sorting all nodes ..." << flush;
|
||||
stxxl::sort(allNodes.begin(), allNodes.end(), CmpNodeByID(), memory_to_use);
|
||||
cout << "ok, after " << get_timestamp() - time << "s" << endl;
|
||||
time = get_timestamp();
|
||||
|
||||
cout << "Confirming used nodes ..." << flush;
|
||||
NodeID counter = 0;
|
||||
NodeID notfound = 0;
|
||||
STXXLNodeVector::iterator nvit = allNodes.begin();
|
||||
STXXLNodeIDVector::iterator niit = usedNodes.begin();
|
||||
while(niit != usedNodes.end() && nvit != allNodes.end())
|
||||
{
|
||||
if(*niit < nvit->id){
|
||||
niit++;
|
||||
continue;
|
||||
}
|
||||
if(*niit > nvit->id)
|
||||
{
|
||||
nvit++;
|
||||
continue;
|
||||
}
|
||||
if(*niit == nvit->id)
|
||||
{
|
||||
confirmedNodes.push_back(*nvit);
|
||||
nodeMap->insert(std::make_pair(nvit->id, *nvit));
|
||||
niit++;
|
||||
nvit++;
|
||||
}
|
||||
}
|
||||
cout << "ok, after " << get_timestamp() - time << "s" << endl;
|
||||
time = get_timestamp();
|
||||
string name(argv[1]);
|
||||
int pos;
|
||||
pos = name.find(".osm.bz2");
|
||||
if(pos!=string::npos)
|
||||
{
|
||||
name.replace(pos, 8, ".osrm");
|
||||
} else {
|
||||
pos=name.find(".osm");
|
||||
if(pos!=string::npos)
|
||||
{
|
||||
name.replace(pos, 5, ".osrm");
|
||||
} else {
|
||||
name.append(".osrm");
|
||||
}
|
||||
}
|
||||
|
||||
cout << "Writing used nodes ..." << flush;
|
||||
fout << confirmedNodes.size() << endl;
|
||||
for(STXXLNodeVector::iterator ut = confirmedNodes.begin(); ut != confirmedNodes.end(); ut++)
|
||||
{
|
||||
fout << ut->id<< " " << ut->lon << " " << ut->lat << "\n";
|
||||
}
|
||||
ofstream fout;
|
||||
fout.open(name.c_str());
|
||||
|
||||
cout << "ok, after " << get_timestamp() - time << "s" << endl;
|
||||
time = get_timestamp();
|
||||
cout << "Confirming used nodes ..." << flush;
|
||||
NodeID counter = 0;
|
||||
NodeID notfound = 0;
|
||||
STXXLNodeVector::iterator nvit = allNodes.begin();
|
||||
STXXLNodeIDVector::iterator niit = usedNodes.begin();
|
||||
while(niit != usedNodes.end() && nvit != allNodes.end())
|
||||
{
|
||||
if(*niit < nvit->id){
|
||||
niit++;
|
||||
continue;
|
||||
}
|
||||
if(*niit > nvit->id)
|
||||
{
|
||||
nvit++;
|
||||
continue;
|
||||
}
|
||||
if(*niit == nvit->id)
|
||||
{
|
||||
confirmedNodes.push_back(*nvit);
|
||||
nodeMap->insert(std::make_pair(nvit->id, *nvit));
|
||||
niit++;
|
||||
nvit++;
|
||||
}
|
||||
}
|
||||
cout << "ok, after " << get_timestamp() - time << "s" << endl;
|
||||
time = get_timestamp();
|
||||
|
||||
cout << "confirming used ways ..." << flush;
|
||||
for(STXXLEdgeVector::iterator eit = allEdges.begin(); eit != allEdges.end(); eit++)
|
||||
{
|
||||
assert(eit->type > -1 || eit->speed != -1);
|
||||
cout << "Writing used nodes ..." << flush;
|
||||
fout << confirmedNodes.size() << endl;
|
||||
for(STXXLNodeVector::iterator ut = confirmedNodes.begin(); ut != confirmedNodes.end(); ut++)
|
||||
{
|
||||
fout << ut->id<< " " << ut->lon << " " << ut->lat << "\n";
|
||||
}
|
||||
|
||||
NodeMap::iterator startit = nodeMap->find(eit->start);
|
||||
if(startit == nodeMap->end())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
NodeMap::iterator targetit = nodeMap->find(eit->target);
|
||||
cout << "ok, after " << get_timestamp() - time << "s" << endl;
|
||||
time = get_timestamp();
|
||||
|
||||
if(targetit == nodeMap->end())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
confirmedEdges.push_back(*eit);
|
||||
}
|
||||
fout << confirmedEdges.size() << "\n";
|
||||
cout << "ok, after " << get_timestamp() - time << "s" << endl;
|
||||
time = get_timestamp();
|
||||
cout << "confirming used ways ..." << flush;
|
||||
for(STXXLEdgeVector::iterator eit = allEdges.begin(); eit != allEdges.end(); eit++)
|
||||
{
|
||||
assert(eit->type > -1 || eit->speed != -1);
|
||||
|
||||
cout << "writing confirmed ways ..." << flush;
|
||||
NodeMap::iterator startit = nodeMap->find(eit->start);
|
||||
if(startit == nodeMap->end())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
NodeMap::iterator targetit = nodeMap->find(eit->target);
|
||||
|
||||
for(STXXLEdgeVector::iterator eit = confirmedEdges.begin(); eit != confirmedEdges.end(); eit++)
|
||||
{
|
||||
NodeMap::iterator startit = nodeMap->find(eit->start);
|
||||
if(startit == nodeMap->end())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
NodeMap::iterator targetit = nodeMap->find(eit->target);
|
||||
if(targetit == nodeMap->end())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
confirmedEdges.push_back(*eit);
|
||||
}
|
||||
fout << confirmedEdges.size() << "\n";
|
||||
cout << "ok, after " << get_timestamp() - time << "s" << endl;
|
||||
time = get_timestamp();
|
||||
|
||||
if(targetit == nodeMap->end())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
double distance = ApproximateDistance(startit->second.lat, startit->second.lon, targetit->second.lat, targetit->second.lon);
|
||||
if(eit->speed == -1)
|
||||
eit->speed = settings.speedProfile.speed[eit->type];
|
||||
double weight = ( distance * 10. ) / (eit->speed / 3.6);
|
||||
int intWeight = max(1, (int) weight);
|
||||
int intDist = max(1, (int)distance);
|
||||
int ferryIndex = settings.indexInAccessListOf("ferry");
|
||||
assert(ferryIndex != -1);
|
||||
cout << "writing confirmed ways ..." << flush;
|
||||
|
||||
switch(eit->direction)
|
||||
{
|
||||
case _Way::notSure:
|
||||
fout << startit->first << " " << targetit->first << " " << intDist << " " << 0 << " " << intWeight << " " << eit->type << " " << eit->nameID << "\n";
|
||||
break;
|
||||
case _Way::oneway:
|
||||
fout << startit->first << " " << targetit->first << " " << intDist << " " << 1 << " " << intWeight << " " << eit->type << " " << eit->nameID << "\n";
|
||||
break;
|
||||
case _Way::bidirectional:
|
||||
fout << startit->first << " " << targetit->first << " " << intDist << " " << 0 << " " << intWeight << " " << eit->type << " " << eit->nameID << "\n";
|
||||
break;
|
||||
case _Way::opposite:
|
||||
fout << startit->first << " " << targetit->first << " " << intDist << " " << 1 << " " << intWeight << " " << eit->type << " " << eit->nameID << "\n";
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
fout.close();
|
||||
for(STXXLEdgeVector::iterator eit = confirmedEdges.begin(); eit != confirmedEdges.end(); eit++)
|
||||
{
|
||||
NodeMap::iterator startit = nodeMap->find(eit->start);
|
||||
if(startit == nodeMap->end())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
NodeMap::iterator targetit = nodeMap->find(eit->target);
|
||||
|
||||
name.append(".names");
|
||||
cout << "ok, after " << get_timestamp() - time << "s" << endl;
|
||||
time = get_timestamp();
|
||||
cout << "writing street name index ..." << flush;
|
||||
if(targetit == nodeMap->end())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
double distance = ApproximateDistance(startit->second.lat, startit->second.lon, targetit->second.lat, targetit->second.lon);
|
||||
if(eit->speed == -1)
|
||||
eit->speed = settings.speedProfile.speed[eit->type];
|
||||
double weight = ( distance * 10. ) / (eit->speed / 3.6);
|
||||
int intWeight = max(1, (int) weight);
|
||||
int intDist = max(1, (int)distance);
|
||||
int ferryIndex = settings.indexInAccessListOf("ferry");
|
||||
assert(ferryIndex != -1);
|
||||
|
||||
vector<unsigned> * nameIndex = new vector<unsigned>(nameVector.size()+1, 0);
|
||||
unsigned currentNameIndex = 0;
|
||||
for(int i = 0; i < nameVector.size(); i++) {
|
||||
nameIndex->at(i) = currentNameIndex;
|
||||
currentNameIndex += nameVector[i].length();
|
||||
}
|
||||
nameIndex->at(nameVector.size()) = currentNameIndex;
|
||||
ofstream nameOutFile(name.c_str(), ios::binary);
|
||||
unsigned sizeOfNameIndex = nameIndex->size();
|
||||
nameOutFile.write((char *)&(sizeOfNameIndex), sizeof(unsigned));
|
||||
switch(eit->direction)
|
||||
{
|
||||
case _Way::notSure:
|
||||
fout << startit->first << " " << targetit->first << " " << intDist << " " << 0 << " " << intWeight << " " << eit->type << " " << eit->nameID << "\n";
|
||||
break;
|
||||
case _Way::oneway:
|
||||
fout << startit->first << " " << targetit->first << " " << intDist << " " << 1 << " " << intWeight << " " << eit->type << " " << eit->nameID << "\n";
|
||||
break;
|
||||
case _Way::bidirectional:
|
||||
fout << startit->first << " " << targetit->first << " " << intDist << " " << 0 << " " << intWeight << " " << eit->type << " " << eit->nameID << "\n";
|
||||
break;
|
||||
case _Way::opposite:
|
||||
fout << startit->first << " " << targetit->first << " " << intDist << " " << 1 << " " << intWeight << " " << eit->type << " " << eit->nameID << "\n";
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
fout.close();
|
||||
|
||||
for(int i = 0; i < nameIndex->size(); i++) {
|
||||
nameOutFile.write((char *)&(nameIndex->at(i)), sizeof(unsigned));
|
||||
}
|
||||
for(int i = 0; i < nameVector.size(); i++){
|
||||
nameOutFile << nameVector[i];
|
||||
}
|
||||
name.append(".names");
|
||||
cout << "ok, after " << get_timestamp() - time << "s" << endl;
|
||||
time = get_timestamp();
|
||||
cout << "writing street name index ..." << flush;
|
||||
|
||||
nameOutFile.close();
|
||||
delete nameIndex;
|
||||
cout << "ok, after " << get_timestamp() - time << "s" << endl;
|
||||
vector<unsigned> * nameIndex = new vector<unsigned>(nameVector.size()+1, 0);
|
||||
unsigned currentNameIndex = 0;
|
||||
for(int i = 0; i < nameVector.size(); i++) {
|
||||
nameIndex->at(i) = currentNameIndex;
|
||||
currentNameIndex += nameVector[i].length();
|
||||
}
|
||||
nameIndex->at(nameVector.size()) = currentNameIndex;
|
||||
ofstream nameOutFile(name.c_str(), ios::binary);
|
||||
unsigned sizeOfNameIndex = nameIndex->size();
|
||||
nameOutFile.write((char *)&(sizeOfNameIndex), sizeof(unsigned));
|
||||
|
||||
} catch ( const std::exception& e ) {
|
||||
cerr << "Caught Execption:" << e.what() << endl;
|
||||
return false;
|
||||
}
|
||||
for(int i = 0; i < nameIndex->size(); i++) {
|
||||
nameOutFile.write((char *)&(nameIndex->at(i)), sizeof(unsigned));
|
||||
}
|
||||
for(int i = 0; i < nameVector.size(); i++){
|
||||
nameOutFile << nameVector[i];
|
||||
}
|
||||
|
||||
cout << endl << "Statistics:" << endl;
|
||||
cout << "-----------" << endl;
|
||||
cout << "Usable Nodes: " << confirmedNodes.size() << endl;
|
||||
cout << "Usable Ways : " << confirmedEdges.size() << endl;
|
||||
nameOutFile.close();
|
||||
delete nameIndex;
|
||||
cout << "ok, after " << get_timestamp() - time << "s" << endl;
|
||||
|
||||
SignalNodes.clear();
|
||||
usedNodes.clear();
|
||||
allNodes.clear();
|
||||
confirmedNodes.clear();
|
||||
allEdges.clear();
|
||||
confirmedEdges.clear();
|
||||
nameVector.clear();
|
||||
xmlFreeTextReader(inputReader);
|
||||
delete nodeMap;
|
||||
delete stringMap;
|
||||
cout << "finished." << endl;
|
||||
return 0;
|
||||
} catch ( const std::exception& e ) {
|
||||
cerr << "Caught Execption:" << e.what() << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
cout << endl << "Statistics:" << endl;
|
||||
cout << "-----------" << endl;
|
||||
cout << "Usable Nodes: " << confirmedNodes.size() << endl;
|
||||
cout << "Usable Ways : " << confirmedEdges.size() << endl;
|
||||
|
||||
SignalNodes.clear();
|
||||
usedNodes.clear();
|
||||
allNodes.clear();
|
||||
confirmedNodes.clear();
|
||||
allEdges.clear();
|
||||
confirmedEdges.clear();
|
||||
nameVector.clear();
|
||||
xmlFreeTextReader(inputReader);
|
||||
delete nodeMap;
|
||||
delete stringMap;
|
||||
cout << "finished." << endl;
|
||||
return 0;
|
||||
}
|
||||
|
164
routed.cpp
164
routed.cpp
@ -16,132 +16,84 @@ You should have received a copy of the GNU Affero General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
or see http://www.gnu.org/licenses/agpl.txt.
|
||||
*/
|
||||
*/
|
||||
|
||||
#include <climits>
|
||||
#include <fstream>
|
||||
#include <istream>
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#ifdef _OPENMP
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
#include "typedefs.h"
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include "HttpServer/server.h"
|
||||
#include "Contractor/GraphLoader.h"
|
||||
#include "DataStructures/StaticGraph.h"
|
||||
|
||||
#include "Server/ServerConfiguration.h"
|
||||
#include "Server/ServerFactory.h"
|
||||
|
||||
#include "Plugins/HelloWorldPlugin.h"
|
||||
#include "Plugins/LocatePlugin.h"
|
||||
#include "Plugins/RoutePlugin.h"
|
||||
#include "Util/InputFileUtil.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
typedef ContractionCleanup::Edge::EdgeData EdgeData;
|
||||
typedef StaticGraph<EdgeData>::InputEdge GridEdge;
|
||||
typedef http::server<StaticGraph<EdgeData> > server;
|
||||
typedef http::RequestHandler RequestHandler;
|
||||
|
||||
/*
|
||||
* TODO: Description of command line arguments
|
||||
*/
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
if(argc < 6)
|
||||
{
|
||||
cerr << "Correct usage:" << endl << argv[0] << " <hsgr data> <nodes data> <ram index> <file index> <names data>" << endl;
|
||||
exit(-1);
|
||||
}
|
||||
if(testDataFiles(argc, argv)==false) {
|
||||
std::cerr << "[error] at least one data file name seems to be bogus!" << std::endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
ifstream hsgrInStream(argv[1], ios::binary);
|
||||
ifstream nodesInStream(argv[2], ios::binary);
|
||||
NodeInformationHelpDesk * nodeInfoHelper = new NodeInformationHelpDesk(argv[3], argv[4]);
|
||||
try {
|
||||
std::cout << "[server] starting up engines" << std::endl;
|
||||
int sig = 0;
|
||||
sigset_t new_mask;
|
||||
sigset_t old_mask;
|
||||
sigfillset(&new_mask);
|
||||
pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask);
|
||||
|
||||
double time = get_timestamp();
|
||||
cout << "deserializing edge data from " << argv[1] << " ..." << flush;
|
||||
ServerConfiguration serverConfig("server.ini");
|
||||
Server * s = ServerFactory::CreateServer(serverConfig);
|
||||
RequestHandler * h = s->GetRequestHandlerPtr();
|
||||
|
||||
std::vector< GridEdge> * edgeList = new std::vector< GridEdge>();
|
||||
readHSGRFromStream(hsgrInStream, edgeList);
|
||||
hsgrInStream.close();
|
||||
cout << "in " << get_timestamp() - time << "s" << endl;
|
||||
time = get_timestamp();
|
||||
cout << "deserializing node map and building nearest neighbor grid ..." << flush;
|
||||
nodeInfoHelper->initNNGrid(nodesInStream);
|
||||
cout << "in " << get_timestamp() - time << "s" << endl;
|
||||
StaticGraph<EdgeData> * graph = new StaticGraph<EdgeData>(nodeInfoHelper->getNumberOfNodes()-1, *edgeList);
|
||||
delete edgeList;
|
||||
time = get_timestamp();
|
||||
cout << "deserializing street names ..." << flush;
|
||||
ifstream namesInStream(argv[5], ios::binary);
|
||||
unsigned size = 0;
|
||||
namesInStream.read((char *)&size, sizeof(unsigned));
|
||||
vector<unsigned> * nameIndex = new vector<unsigned>(size, 0);
|
||||
vector<string> * names = new vector<string>();
|
||||
for(int i = 0; i<size; i++)
|
||||
namesInStream.read((char *)&(nameIndex->at(i)), sizeof(unsigned));
|
||||
BasePlugin * helloWorld = new HelloWorldPlugin();
|
||||
h->RegisterPlugin(helloWorld);
|
||||
|
||||
for(int i = 0; i<size-1; i++){
|
||||
string tempString;
|
||||
for(int j = 0; j < nameIndex->at(i+1) - nameIndex->at(i); j++){
|
||||
char c;
|
||||
namesInStream.read(&c, sizeof(char));
|
||||
tempString.append(1, c);
|
||||
}
|
||||
names->push_back(tempString);
|
||||
tempString = "";
|
||||
}
|
||||
delete nameIndex;
|
||||
BasePlugin * locate = new LocatePlugin(
|
||||
serverConfig.GetParameter("ramIndex"),
|
||||
serverConfig.GetParameter("fileIndex"),
|
||||
serverConfig.GetParameter("nodesData"));
|
||||
h->RegisterPlugin(locate);
|
||||
|
||||
namesInStream.close();
|
||||
cout << "in " << get_timestamp() - time << "s" << endl;
|
||||
time = get_timestamp();
|
||||
BasePlugin * route = new RoutePlugin(
|
||||
serverConfig.GetParameter("hsgrData"),
|
||||
serverConfig.GetParameter("ramIndex"),
|
||||
serverConfig.GetParameter("fileIndex"),
|
||||
serverConfig.GetParameter("nodesData"),
|
||||
serverConfig.GetParameter("namesData"));
|
||||
h->RegisterPlugin(route);
|
||||
|
||||
cout << "constructing search graph ..." << flush;
|
||||
boost::thread t(boost::bind(&Server::Run, s));
|
||||
|
||||
SearchEngine<EdgeData, StaticGraph<EdgeData> > * sEngine = new SearchEngine<EdgeData, StaticGraph<EdgeData> >(graph, nodeInfoHelper, names);
|
||||
cout << "in " << get_timestamp() - time << "s" << endl;
|
||||
time = get_timestamp();
|
||||
|
||||
try {
|
||||
// Block all signals for background thread.
|
||||
sigset_t new_mask;
|
||||
sigfillset(&new_mask);
|
||||
sigset_t old_mask;
|
||||
pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask);
|
||||
|
||||
cout << "starting web server ..." << flush;
|
||||
// Run server in background thread.
|
||||
server s("0.0.0.0", "5000", omp_get_num_procs(), sEngine);
|
||||
boost::thread t(boost::bind(&server::run, &s));
|
||||
cout << "ok" << endl;
|
||||
|
||||
// Restore previous signals.
|
||||
pthread_sigmask(SIG_SETMASK, &old_mask, 0);
|
||||
|
||||
// Wait for signal indicating time to shut down.
|
||||
sigset_t wait_mask;
|
||||
sigemptyset(&wait_mask);
|
||||
sigaddset(&wait_mask, SIGINT);
|
||||
sigaddset(&wait_mask, SIGQUIT);
|
||||
sigaddset(&wait_mask, SIGTERM);
|
||||
pthread_sigmask(SIG_BLOCK, &wait_mask, 0);
|
||||
int sig = 0;
|
||||
sigwait(&wait_mask, &sig);
|
||||
// Stop the server.
|
||||
s.stop();
|
||||
t.join();
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
std::cerr << "exception: " << e.what() << "\n";
|
||||
}
|
||||
cout << "graceful shutdown after " << get_timestamp() - time << "s" << endl;
|
||||
delete names;
|
||||
delete sEngine;
|
||||
delete graph;
|
||||
delete nodeInfoHelper;
|
||||
return 0;
|
||||
sigset_t wait_mask;
|
||||
pthread_sigmask(SIG_SETMASK, &old_mask, 0);
|
||||
sigemptyset(&wait_mask);
|
||||
sigaddset(&wait_mask, SIGINT);
|
||||
sigaddset(&wait_mask, SIGQUIT);
|
||||
sigaddset(&wait_mask, SIGTERM);
|
||||
pthread_sigmask(SIG_BLOCK, &wait_mask, 0);
|
||||
std::cout << "[server] running and waiting for requests" << std::endl;
|
||||
sigwait(&wait_mask, &sig);
|
||||
std::cout << std::endl << "[server] shutting down" << std::endl;
|
||||
s->Stop();
|
||||
t.join();
|
||||
delete helloWorld;
|
||||
delete locate;
|
||||
delete s;
|
||||
} catch (std::exception& e) {
|
||||
std::cerr << "[fatal error] exception: " << e.what() << std::endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
9
server.ini
Normal file
9
server.ini
Normal file
@ -0,0 +1,9 @@
|
||||
Threads = 8
|
||||
IP = 0.0.0.0
|
||||
Port = 5000
|
||||
|
||||
hsgrData=/opt/osm/germany.osrm.hsgr
|
||||
nodesData=/opt/osm/germany.osrm.nodes
|
||||
ramIndex=/opt/osm/germany.osrm.ramIndex
|
||||
fileIndex=/opt/osm/germany.osrm.fileIndex
|
||||
namesData=/opt/osm/germany.osrm.names
|
@ -52,11 +52,11 @@ static const EdgeID SPECIAL_EDGEID = UINT_MAX;
|
||||
typedef NodeCoords<NodeID> NodeInfo;
|
||||
#include "DataStructures/Util.h"
|
||||
#include "DataStructures/NodeInformationHelpDesk.h"
|
||||
#include "Contractor/BinaryHeap.h"
|
||||
#include "DataStructures/BinaryHeap.h"
|
||||
#include "Contractor/Contractor.h"
|
||||
#include "Contractor/ContractionCleanup.h"
|
||||
typedef ContractionCleanup::Edge::EdgeData EdgeData;
|
||||
#include "DataStructures/DynamicGraph.h"
|
||||
#include "Contractor/SearchEngine.h"
|
||||
//#include "Contractor/SearchEngine.h"
|
||||
|
||||
#endif /* TYPEDEFS_H_ */
|
||||
|
Loading…
Reference in New Issue
Block a user