Added a trivial HTTP server class.

master
Hannes Matuschek 11 years ago
parent 7c5cfb2019
commit a3a6165ede

@ -1,2 +1,4 @@
#add_subdirectory(libhttpd)
add_executable(sdr_cmd main.cc)
target_link_libraries(sdr_cmd ${LIBS} libsdr)

@ -0,0 +1,5 @@
#include "json.hh"
JSON::JSON()
{
}

@ -0,0 +1,5 @@
#ifndef __SDR_HTTP_JSON_HH__
#define __SDR_HTTP_JSON_HH__
#endif // __SDR_HTTP_JSON_HH__

@ -1,225 +1,64 @@
#include "options.hh"
#include <stdio.h>
#include "queue.hh"
#include "http.hh"
#include "logger.hh"
#include "wavfile.hh"
#include "autocast.hh"
#include "portaudio.hh"
#include "rtlsource.hh"
#include "baseband.hh"
#include "demod.hh"
#include <iostream>
#include <csignal>
using namespace sdr;
// On SIGINT -> stop queue properly
static void __sigint_handler(int signo) {
Queue::get().stop();
}
class Application
{
public:
Application() {}
// Command line options
static Options::Definition options[] = {
{"rtl2832", 'R', Options::FLOAT,
"Specifies a RTL2832 USB dongle as the input source"},
{"rtl-device", 0, Options::INTEGER,
"Specifies the RTL2832 device index. (default 0)"},
{"disable-rtl-agc", 0 , Options::FLAG,
"Disables the IF AGC of the RTL2832 device, default on."},
{"rtl-agc-gain", 0, Options::INTEGER,
"In conjecture with --disable-rtl-agc, specifies the fixed IF gain of the RTL2832 device."},
{"rtl-ppm", 0, Options::FLOAT,
"Specifies the frequency correction for the RTL2832 device in parts-per-million (ppm)."},
{"audio", 'a', Options::FLAG,
"Specifies the system audio as the input source."},
{"audio-iq", 'a', Options::FLAG,
"Specifies the system audio as the input source (I/Q channels)."},
{"source-rate", 0, Options::FLOAT,
"Specifies the sample rate of the input device."},
{"file", 'f', Options::ANY,
"Specifies a WAV file as input source."},
{"demod", 'd', Options::ANY,
"Specifies the demodulator (wfm, nfm, am, usb, lsb)."},
{"demod-offset", 0, Options::FLOAT,
"Specifies the reception offset in Hz. (default 0)"},
{"loglevel", 0, Options::INTEGER,
"Specifies the log-level. 0 = DEBUG, 1 = INFO, 2 = WARNING, 3 = ERROR."},
{"help", '?', Options::FLAG,
"Prints this help."},
{0,0,Options::FLAG,0}
bool echo(const http::JSON &request, http::JSON &response) {
response = request;
return true;
}
};
void print_help() {
std::cerr << "USAGE: sdr_cmd SOURCE [OPTIONS] OUTPUT" << std::endl << std::endl;
Options::print_help(std::cerr, options);
static http::Server *server = 0;
static void __sigint_handler(int signo) {
server->stop(true);
}
const char *index_html = "<html>"
"<head></head>"
"<body>"
"<b>It is alive!</b>"
"<body>"
"</html>";
bool
json_echo(const http::JSON &request, http::JSON &response) {
response = request;
return true;
}
int main(int argc, char *argv[]) {
// Parse command line options.
Options opts;
if (! Options::parse(options, argc, argv, opts)) {
print_help(); return -1;
}
Application app;
server = new http::Server(8080);
// If help flag is present -> print and done.
if (opts.has("help")) { print_help(); return 0; }
// Install log-handler
LogLevel loglevel = LOG_INFO;
if (opts.has("loglevel")) {
if (0 >= opts.get("loglevel").toInteger()) { loglevel = LOG_DEBUG; }
else if (1 >= opts.get("loglevel").toInteger()) { loglevel = LOG_INFO; }
else if (2 >= opts.get("loglevel").toInteger()) { loglevel = LOG_WARNING; }
else { loglevel = LOG_ERROR; }
}
// Install log handler
sdr::Logger::get().addHandler(
new sdr::StreamLogHandler(std::cerr, loglevel));
new sdr::StreamLogHandler(std::cerr, sdr::LOG_DEBUG));
// If no source has been selected -> error
if (! (opts.has("rtl2832")|opts.has("audio")|opts.has("file"))) {
std::cerr << "No source has been selected!" << std::endl;
print_help(); return -1;
}
// If no demodulator has been selected.
if (!opts.has("demod")) {
std::cerr << "No demodulator has been selected!" << std::endl;
print_help(); return -1;
}
double bbFc = 0, bbFf = 0, bbFw = 0, bbFs = 0;
// Configure baseband node depending on the selected demodulator
if ("wfm" == opts.get("demod").toString()) {
bbFw = 100e3; bbFs = 100e3;
} else if ("nfm" == opts.get("demod").toString()) {
bbFw = 12.5e3; bbFs = 22.05e3;
} else if ("am" == opts.get("demod").toString()) {
bbFw = 10.0e3; bbFs = 22.05e3;
} else if ("usb" == opts.get("demod").toString()) {
bbFf = 1.5e3; bbFw = 3e3; bbFs = 22.05e3;
} else if ("lsb" == opts.get("demod").toString()) {
bbFf = -1.5e3; bbFw = 3e3; bbFs = 22.05e3;
} else {
std::cerr << "Unknown demodulator '" << opts.get("demod").toString() << "'." << std::endl;
print_help(); return -1;
}
// Register signal handler to stop queue on SIGINT
// Register signal handler:
signal(SIGINT, __sigint_handler);
// Init audio system
PortAudio::init();
// Register callbacks
server->addStatic("/", index_html, "text/html");
server->addJSON("/echo", &app, &Application::echo);
// Get the global queue
Queue &queue = Queue::get();
// start server
server->start(true);
// reference to selected source node
Source *source = 0;
// Nodes for file input
WavSource *wav_src=0;
AutoCast< std::complex<int16_t> > *wav_cast=0;
// nodes for real audio input
PortSource<int16_t> *raudio_src=0;
AutoCast< std::complex<int16_t> > *raudio_cast=0;
// nodes for IQ audio input
PortSource< std::complex<int16_t> > *iqaudio_src=0;
// nodes for RTL2832 input
RTLSource *rtl_source=0;
AutoCast< std::complex<int16_t> > *rtl_cast=0;
/* Demodulator nodes. */
Source *demod = 0;
FMDemod<int16_t> *fm_demod = 0;
FMDeemph<int16_t> *fm_deemph = 0;
AMDemod<int16_t> *am_demod = 0;
USBDemod<int16_t> *ssb_demod = 0;
// Dispatch by selected source
if (opts.has("rtl2832")) {
// Instantiate & config RTL2832 node
size_t devIdx = 0;
double sampleRate = 1e6;
if (opts.has("rtl-device")) { devIdx = opts.get("rtl-device").toInteger(); }
if (opts.has("source-rate")) { sampleRate = opts.get("source-rate").toFloat(); }
rtl_source = new RTLSource(opts.get("rtl2832").toFloat(), sampleRate, devIdx);
if (opts.has("rtl-disable-agc")) { rtl_source->enableAGC(false); }
if (opts.has("rtl-gain")) { rtl_source->setGain(opts.get("rtl-gain").toFloat()); }
if (opts.has("rtl-ppm")) { rtl_source->setFreqCorrection(opts.get("rtl-ppm").toFloat()); }
rtl_cast = new AutoCast< std::complex<int16_t> >();
rtl_source->connect(rtl_cast);
source = rtl_cast;
// Connect start & stop event to RTL2832 device
queue.addStart(rtl_source, &RTLSource::start);
queue.addStop(rtl_source, &RTLSource::stop);
} else if (opts.has("audio")) {
double sampleRate = 44100;
if (opts.has("source-rate")) { sampleRate = opts.get("source-rate").toFloat(); }
raudio_src = new PortSource<int16_t>(sampleRate, 1024);
raudio_cast = new AutoCast< std::complex<int16_t> >();
source = raudio_cast;
// Connect idle event to source
queue.addIdle(raudio_src, &PortSource<int16_t>::next);
} else if (opts.has("audio-iq")) {
double sampleRate = 44100;
if (opts.has("source-rate")) { sampleRate = opts.get("source-rate").toFloat(); }
iqaudio_src = new PortSource< std::complex<int16_t> >(sampleRate, 1024);
source = iqaudio_src;
// Connect idle event to source
queue.addIdle(iqaudio_src, &PortSource< std::complex<int16_t> >::next);
}
// Shift baseband by offset
if (opts.has("demod-offset")) {
bbFc += opts.get("demod-offset").toFloat();
bbFf += opts.get("demod-offset").toFloat();
}
IQBaseBand< int16_t > baseband(bbFc, bbFf, bbFw, 31, 0, bbFs);
source->connect(&baseband, true);
// Dispatch by selected demodulator
if (("wfm" == opts.get("demod").toString()) || ("nfm" == opts.get("demod").toString())) {
fm_demod = new FMDemod<int16_t>();
fm_deemph = new FMDeemph<int16_t>();
source->connect(fm_demod, true);
fm_demod->connect(fm_deemph, true);
demod = fm_deemph;
} else if ("am" == opts.get("demod").toString()) {
am_demod = new AMDemod<int16_t>();
source->connect(am_demod, true);
demod = am_demod;
} else if (("usb" == opts.get("demod").toString()) || ("lsb" == opts.get("demod").toString())) {
ssb_demod = new USBDemod<int16_t>();
source->connect(ssb_demod, true);
demod = ssb_demod;
}
// Enable playback
PortSink audio_sink;
demod->connect(&audio_sink, true);
// Start queue & processing
queue.start();
// Wait for queue to to stop
queue.wait();
// Free allocated input nodes
if (rtl_source) { delete rtl_source; }
if (rtl_cast) { delete rtl_cast; }
if (raudio_src) { delete raudio_src; }
if (raudio_cast) { delete raudio_cast; }
if (iqaudio_src) { delete iqaudio_src; }
if (wav_src) { delete wav_src; }
if (wav_cast) { delete wav_cast; }
if (fm_demod) { delete fm_demod; }
if (fm_deemph) { delete fm_deemph; }
if (am_demod) { delete am_demod; }
if (ssb_demod) { delete ssb_demod; }
PortAudio::terminate();
// Done.
return 0;
}

@ -1,13 +1,13 @@
# Sources of libsdr
set(LIBSDR_SOURCES
buffer.cc node.cc queue.cc traits.cc portaudio.cc utils.cc wavfile.cc exception.cc logger.cc
psk31.cc options.cc fsk.cc ax25.cc aprs.cc baudot.cc pocsag.cc bch31_21.cc)
psk31.cc options.cc fsk.cc ax25.cc aprs.cc baudot.cc pocsag.cc bch31_21.cc http.cc)
set(LIBSDR_HEADERS sdr.hh math.hh
buffer.hh node.hh queue.hh buffernode.hh filternode.hh traits.hh autocast.hh
siggen.hh portaudio.hh utils.hh wavfile.hh demod.hh firfilter.hh
fftplan.hh fftplan_native.hh exception.hh baseband.hh freqshift.hh subsample.hh
combine.hh logger.hh psk31.hh interpolate.hh operators.hh options.hh fsk.hh ax25.hh
aprs.hh baudot.hh pocsag.hh bch31_21.hh)
aprs.hh baudot.hh pocsag.hh bch31_21.hh http.hh)
if(SDR_WITH_PORTAUDIO)
set(LIBSDR_SOURCES ${LIBSDR_SOURCES} portaudio.cc)

@ -241,34 +241,28 @@ protected:
/** The actual demodulation. */
void _process(const Buffer< std::complex<iScalar> > &in, const Buffer<oScalar> &out)
{
// The last input value
std::complex<iScalar> last_value = _last_value;
// calc first value
SScalar a = (SScalar(in[0].real())*SScalar(last_value.real()))/2
+ (SScalar(in[0].imag())*SScalar(last_value.imag()))/2;
SScalar b = (SScalar(in[0].imag())*SScalar(last_value.real()))/2
- (SScalar(in[0].real())*SScalar(last_value.imag()))/2;
SScalar a = (SScalar(in[0].real())*SScalar(_last_value.real()))/2
+ (SScalar(in[0].imag())*SScalar(_last_value.imag()))/2;
SScalar b = (SScalar(in[0].imag())*SScalar(_last_value.real()))/2
- (SScalar(in[0].real())*SScalar(_last_value.imag()))/2;
a >>= Traits<iScalar>::shift; b >>= Traits<iScalar>::shift;
// update last value
last_value = in[0];
_last_value = in[0];
// calc output (prob. overwriting the last value)
out[0] = fast_atan2<iScalar, oScalar>(a, b);
//out[0] = (1<<12)*(std::atan2(float(a),float(b))/M_PI);
// Calc remaining values
for (size_t i=1; i<in.size(); i++) {
a = (SScalar(in[i].real())*SScalar(last_value.real()))/2
+ (SScalar(in[i].imag())*SScalar(last_value.imag()))/2;
b = (SScalar(in[i].imag())*SScalar(last_value.real()))/2
- (SScalar(in[i].real())*SScalar(last_value.imag()))/2;
a = (SScalar(in[i].real())*SScalar(_last_value.real()))/2
+ (SScalar(in[i].imag())*SScalar(_last_value.imag()))/2;
b = (SScalar(in[i].imag())*SScalar(_last_value.real()))/2
- (SScalar(in[i].real())*SScalar(_last_value.imag()))/2;
a >>= Traits<iScalar>::shift; b >>= Traits<iScalar>::shift;
last_value = in[i];
_last_value = in[i];
out[i] = fast_atan2<iScalar,oScalar>(a, b);
//out[i] = (1<<12)*(std::atan2(float(a),float(b))/M_PI);
}
// Store last value
_last_value = last_value;
// propergate result
this->send(out.head(in.size()));
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,521 @@
/** @defgroup httpd A rather trivia HTTP daemon implementation. */
#ifndef __SDR_HTTPD_HH__
#define __SDR_HTTPD_HH__
#include <string>
#include <sstream>
#include <map>
#include <set>
#include <list>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
namespace sdr {
namespace http {
// Forward declarations
class Server;
/** Represents a JSON object.
* @ingroup http */
class JSON
{
public:
/** Specifies the possible json types. */
typedef enum {
EMPTY, ///< null.
BOOLEAN, ///< A boolean value.
NUMBER, ///< A number.
STRING, ///< A string.
ARRAY, ///< An array or list.
TABLE ///< A table or object.
} Type;
public:
/** Empty constructor (null). */
JSON();
/** Constructs a boolean value. */
JSON(bool value);
/** Constructs a number. */
JSON(double value);
/** Constructs a string. */
JSON(const std::string &value);
/** Constructs a list. */
JSON(const std::list<JSON> &list);
/** Constructs a table. */
JSON(const std::map<std::string, JSON> &table);
/** Copy constructor (deep copy). */
JSON(const JSON &other);
/** Destructor. */
~JSON();
/** Assignment operator (deep copy). */
JSON &operator=(const JSON &other);
/** Retruns @c true for the null. */
inline bool isNull() const { return EMPTY == _type; }
/** Returns @c true if this is a boolean value. */
inline bool isBoolean() const { return BOOLEAN == _type; }
/** Returns the boolean value. */
inline const bool &asBoolean() const { return *_value.boolean; }
/** Returns @c true if this is a number. */
inline bool isNumber() const { return NUMBER == _type; }
/** Returns the number. */
inline const double &asNumber() const { return *_value.number; }
/** Returns @c true if this is a string. */
inline bool isString() const { return STRING == _type; }
/** Returns the string. */
inline const std::string &asString() const { return *_value.string; }
/** Returns @c true if this is an array. */
inline bool isArray() const { return ARRAY == _type; }
/** Retruns the array as a list. */
inline const std::list<JSON> &asArray() const { return *_value.list; }
/** Returns @c true if this is a table. */
inline bool isTable() const { return TABLE == _type; }
/** Returns the table. */
inline const std::map<std::string, JSON> &asTable() const { return *_value.table; }
/** Resets the JSON object to null. */
void clear();
/** Parses the given string. Retruns @c true on success. */
static bool parse(const std::string &text, JSON &obj);
/** Serializes the JSON object. */
void serialize(std::ostream &stream) const;
/** Serializes the JSON object. */
inline void serialize(std::string &text) const {
std::stringstream buffer; this->serialize(buffer);
text = buffer.str();
}
protected:
/** The type of the object. */
Type _type;
/** Union of value pointers. */
union {
/** The boolean value. */
bool *boolean;
/** The number. */
double *number;
/** The string. */
std::string *string;
/** The array. */
std::list<JSON> *list;
/** The table. */
std::map<std::string, JSON> *table;
} _value;
};
/** Lists the possible HTTP methods.
* @ingroup http */
typedef enum {
HTTP_UNKNOWN,
HTTP_GET,
HTTP_HEAD,
HTTP_POST
} Method;
/** Lists the possible HTTP versions.
* @ingroup http */
typedef enum {
UNKNOWN_VERSION,
HTTP_1_0,
HTTP_1_1
} Version;
/** Represents a URL.
* @ingroup http */
class URL
{
public:
/** Empty constructor. */
URL();
/** Constructor from protocol, host and path. */
URL(const std::string &proto, const std::string &host, const std::string &path);
/** Copy constructor. */
URL(const URL &other);
/** Assignment operator. */
URL &operator=(const URL &other);
/** Parses a URL from the given string. */
static URL fromString(const std::string &url);
/** Serializes the URL into a string. */
std::string toString() const;
/** Returns @c true if the URL specifies a protocol. */
inline bool hasProtocol() const { return (0 != _protocol.size()); }
/** Returns the protocol. */
inline const std::string protocol() const { return _protocol; }
/** Sets the protocol. */
inline void setProtocol(const std::string &proto) { _protocol = proto; }
/** Returns @c true if the URL specified a host name. */
inline bool hasHost() const { return (0 != _host.size()); }
/** Returns the host name. */
inline const std::string &host() const { return _host; }
/** Set the host name. */
inline void setHost(const std::string &host) { _host = host; }
/** Retruns the path of the URL. */
inline const std::string &path() const { return _path; }
/** Sets the path of the URL. */
inline void setPath(const std::string &path) { _path = path; }
/** Adds a query pair (key, value) to the URL. */
inline void addQuery(const std::string &name, const std::string &value) {
_query.push_back(std::pair<std::string, std::string>(name, value));
}
/** Returns the list of query (key, value) pairs. */
inline const std::list< std::pair<std::string, std::string> > &query() const {
return _query;
}
protected:
/** Holds the protocol. */
std::string _protocol;
/** Holds the host name. */
std::string _host;
/** Holds the path. */
std::string _path;
/** Holds the query pairs. */
std::list< std::pair<std::string, std::string> > _query;
};
/** Represents a HTTP request.
* @ingroup http */
class Request
{
public:
/** Constructor. */
Request(int socket);
/** Parses the HTTP request header, returns @c true on success. */
bool parse();
/** Returns @c true if the connection to the client is kept alive after the response
* has been send. */
bool isKeepAlive() const;
/** Returns @c true if the given header is present. */
bool hasHeader(const std::string &name) const;
/** Returns the value of the given header. */
std::string header(const std::string &name) const;
/** Returns @c true if the Content-Length header is present. */
inline bool hasContentLength() const { return hasHeader("Content-Length"); }
/** Returns the value of the Content-Length header. */
size_t contentLength() const { return atol(header("Content-Length").c_str()); }
/** Retruns the request method. */
inline Method method() const { return _method; }
/** Returns the request URL. */
inline const URL &url() const { return _url; }
/** Allows to read data from the connection (i.e. the request body). */
inline int read(const char *data, size_t size) {
return ::read(_socket, (void *)data, size);
}
/** Reads the complete body (if Content-Length header is present).
* Retruns @c true on success.*/
bool readBody(std::string &body) const;
protected:
/** The connection socket. */
int _socket;
/** The request method. */
Method _method;
/** The HTTP version. */
Version _version;
/** The request URL. */
URL _url;
/** The request headers. */
std::map<std::string, std::string> _headers;
};
/** Represents a HTTP response. */
class Response
{
public:
/** Defines all possible responses. */
typedef enum {
STATUS_OK = 200,
STATUS_BAD_REQUEST = 400,
STATUS_NOT_FOUND = 404,
STATUS_SERVER_ERROR = 500
} Status;
public:
/** Constructor.
* @param socket Specifies the socket over which the response will be send.*/
Response(int socket);
/** Specifies the response code. */
void setStatus(Status status);
/** Returns @c true if the response has the given header. */
bool hasHeader(const std::string &name) const;
/** Returns the value of the header. */
std::string header(const std::string &name) const;
/** Sets the header. */
void setHeader(const std::string &name, const std::string &value);
/** Helper function to set the content length. */
void setContentLength(size_t length);
/** Sends the response code and all defined headers. */
bool sendHeaders() const;
/** Sends some data through the socket. To send the response body, call
* @c sendHeaders() first. */
bool send(const std::string &data) const;
/** Returns @c true if the connection will be closed after the response has been send.
* @c I.e. if there was an error. */
inline bool closeConnection() const { return _close_connection; }
/** Marks that the connection will be closed after the response has been send. */
inline void setCloseConnection() { _close_connection = true; }
protected:
/** The socket over which the response will be send. */
int _socket;
/** The response code. */
Status _status;
/** The response headers. */
std::map<std::string, std::string> _headers;
/** If @c true, the connection will be closed after the response has been send. */
bool _close_connection;
};
/** Implements a HTTP connection to a client.
* @c ingroup http */
class Connection
{
public:
/** Constructor. */
Connection(Server *server, int socket);
/** Destructor. */
~Connection();
/** Closes the connection.
* If @c wait is @c true, the method will wait until the thread listening for incomming
* request joined. */
void close(bool wait=false);
/** Returns @c true if the connection is closed. */
bool isClosed() const;
protected:
/** Main loop for incomming requests. */
static void *_main(void *ctx);
protected:
/** A weak reference to the server instance. */
Server *_server;
/** The connection socket. */
int _socket;
/** The thread processing requests for this connection. */
pthread_t _thread;
};
/** Base class of all HTTP request handlers.
* @ingroup http */
class Handler
{
protected:
/** Hidden constructor. */
Handler();
public:
/** Destructor. */
virtual ~Handler();
/** Needs to be implemented to accept the given request.
* If this method returns @c true, the server will call the @c handle instance next
* in expectation that this instance will process the request. */
virtual bool match(const Request &request) = 0;
/** Needs to be implemented to process requests, which have been accepted by the @c match()
* method. */
virtual void handle(const Request &request, Response &response) = 0;
};
/** Serves some static content.
* @ingroup http */
class StaticHandler: public Handler
{
public:
/** Constructor.
* @param url Specifies the URL (path) of the static content.
* @param text Speciefies the content.
* @param mimeType Speficies the mime-type of the content. */
StaticHandler(const std::string &url, const std::string &text,
const std::string mimeType="text/text");
/** Destructor. */
virtual ~StaticHandler();
bool match(const Request &request);
void handle(const Request &request, Response &response);
protected:
/** Holds the URL (path) of the content. */
std::string _url;
/** Holds the mime-type of the content. */
std::string _mimeType;
/** Holds the content itself. */
std::string _text;
};
/** Utility function to provide a handler as a delegate.
* @ingroup http */
template <class T>
class DelegateHandler: public Handler
{
public:
/** Constructor.
* @param url Specifies the path of the handler.
* @param instance Specifies the instance of the delegate.
* @param func Specifies the method of the delegate instance being called. */
DelegateHandler(const std::string &url, T *instance, void (T::*func)(const Request &, Response &))
: Handler(), _url(url), _instance(instance), _callback(func)
{
// pass...
}
bool match(const Request &request) {
return this->_url == request.url().path();
}
void handle(const Request &request, Response &response) {
(this->_instance->*(this->_callback))(request, response);
}
protected:
/** Holds the path of the handler. */
std::string _url;
/** Holds the instance of the delegate. */
T *_instance;
/** Holds the method of the instance being called. */
void (T::*_callback)(const Request &, Response &);
};
/** Implements a specialized handler to ease the processing of JSON REST-APIs.
* @ingroup http */
class JSONHandler: public http::Handler
{
public:
/** Constructor.
* @param url Speficies the path of the method. */
JSONHandler(const std::string &url);
bool match(const http::Request &request);
void handle(const http::Request &request, http::Response &response);
/** Needs to be implemented to process the request and assemble the result.
* An error (400 BAD REQUEST) will be send if the function does not return @c true. */
virtual bool process(const JSON &request, JSON &result) = 0;
protected:
/** The URL of the method. */
std::string _url;
};
/** A delegate JSON handler.
* @ingroup http */
template <class T>
class DelegateJSONHandler: public JSONHandler
{
public:
/** Constructor. */
DelegateJSONHandler(const std::string &url, T *instance,
bool (T::*func)(const JSON &request, JSON &response))
: JSONHandler(url), _instance(instance), _callback(func)
{
// pass...
}
virtual bool process(const JSON &request, JSON &result) {
return (this->_instance->*(this->_callback))(request, result);
}
protected:
/** The delegate instance. */
T *_instance;
/** The method to be called from the delegate instance. */
bool (T::*_callback)(const JSON &request, JSON &response);
};
/** Implements a trivial HTTP/1.1 server.
* @ingroup httpd*/
class Server
{
public:
/** Constructor.
* @param port Specifies the port number to listen on. */
Server(uint port);
/** Destructor. */
~Server();
/** Starts the server. */
void start(bool wait=false);
/** Stops the server. */
void stop(bool wait=false);
/** Wait for the server thread to join. */
void wait();
/** Adds a generic handler to the dispatcher. */
void addHandler(Handler *handler);
/** Adds a delegate to the dispatcher. */
template <class T>
void addHandler(const std::string &url,
T *instance, void (T::*func)(const Request &, Response &)) {
addHandler(new DelegateHandler<T>(url, instance, func));
}
/** Adds a JSON delegate to the dispatcher. */
template <class T>
void addJSON(const std::string &url,
T *instance, bool (T::*func)(const JSON &request, JSON &result)) {
addHandler(new DelegateJSONHandler<T>(url, instance, func));
}
/** Adds some static content to the dispatcher. */
inline void addStatic(const std::string &url, const std::string &text) {
addHandler(new StaticHandler(url, text));
}
/** Adds a generic handler to the dispatcher. */
inline void addStatic(const std::string &url, const std::string &text, const std::string &mimeType) {
addHandler(new StaticHandler(url, text, mimeType));
}
protected:
/** Dispatches a request. */
void dispatch(const Request &request, Response &response);
/** The thread waiting for incomming connections. */
static void *_listen_main(void *ctx);
protected:
/** Port to bind to. */
uint _port;
/** The socket to listen on. */
int _socket;
/** While true, the server is listening on the port for incomming connections. */
bool _is_running;
/** The listen thread. */
pthread_t _thread;
/** All registered handler. */
std::list<Handler *> _handler;
/** All open connections. */
std::set<Connection *> _connections;
/* Allow Connection to access dispatch(). */
friend class Connection;
};
}
}
#endif // __SDR_HTTPD_HH__

@ -29,7 +29,6 @@ template <> inline int16_t fast_atan2<uint8_t, int16_t>(uint8_t ua, uint8_t ub)
/** Implementation of atan2 approximation using integers. */
template <> inline int16_t fast_atan2<int16_t, int16_t>(int16_t a, int16_t b) {
//return (1<<15)*(std::atan2(float(a), float(b))/M_PI);
const int32_t pi4 = (1<<12);
const int32_t pi34 = 3*(1<<12);
int32_t aabs, angle;

Loading…
Cancel
Save