mediaserv
+testclient
libScheduler.a
libSocket.a
libUtils.a
libServer.a
+TODOS
+BUGS
+FIXMES
+
SatSCons.StandardTargets(env)
SatSCons.GlobalTargets(env)
-SatSCons.Binary(env, binary='mediaserv', sources=SatSCons.GlobSources(),
+SatSCons.Binary(env, binary='mediaserv', sources=SatSCons.GlobSources(exclude='testclient.cc'),
LIBS = [ 'Server', 'Scheduler', 'Socket', 'Utils' ])
+
+SatSCons.Binary(env, binary='testclient', sources=['testclient.cc'],
+ LIBS = [ 'Socket', 'Utils' ])
+++ /dev/null
-// $Id$
-//
-// Copyright (C) 2006
-
-// Definition of non-inline non-template functions
-
-#include "Connection.hh"
-//#include "Connection.ih"
-
-// Custom includes
-
-//#include "Connection.mpp"
-#define prefix_
-///////////////////////////////cc.p////////////////////////////////////////
-
-prefix_ g0dil::mediaserv::Connection::Connection(int fileFd, unsigned bytesPerSecond,
- ClientHandle client, unsigned bufferMSecs)
- : fileFd_(fileFd), bytesPerSecond_(bytesPerSecond), client_(client),
- bufferMSecs_(bufferMSecs), bytesWritten_(0), start_(satcom::lib::now()),
- bufferSize_(0), terminate_(false)
-{
- registerCallback();
- fillBuffer();
-}
-
-prefix_ void g0dil::mediaserv::Connection::fillBuffer()
-{
- bufferSize_ = ::read(fileFd_,buffer_,packetSize);
- if (bufferSize_ < packetSize)
- terminate_ = true;
- // TODO: Check error;
-}
-
-prefix_ void g0dil::mediaserv::Connection::callback(ClientHandle client,
- satcom::lib::Scheduler::EventId)
-{
- unsigned target (targetBytes());
- if (target - bytesWritten_ >= bufferSize_) {
- if (client_.write(buffer_,bufferSize_) < bufferSize_)
- // TODO: Destroy client handle ..
- ;
- bytesWritten_ += bufferSize_;
- if (terminate_) {
- unregisterCallback();
- // TODO: Destroy client handle
- } else
- fillBuffer();
- } else {
- unregisterCallback();
- registerTimeout(((bufferSize_-(target-bytesWritten_))*1000)/bytesPerSecond_);
- }
-}
-
-prefix_ void g0dil::mediaserv::Connection::timeout()
-{
- registerCallback();
-}
-
-///////////////////////////////cc.e////////////////////////////////////////
-#undef prefix_
-//#include "Connection.mpp"
-
-\f
-// Local Variables:
-// mode: c++
-// End:
+++ /dev/null
-// $Id$
-//
-// Copyright (C) 2006
-
-// Definition of inline non-template functions
-
-// Custom includes
-#include "Utils/membind.hh"
-
-#define prefix_ inline
-///////////////////////////////cci.p///////////////////////////////////////
-
-prefix_ void g0dil::mediaserv::Connection::registerCallback()
-{
- satcom::lib::Scheduler::instance().add(client_,satcom::lib::membind(&Connection::callback,this),
- satcom::lib::Scheduler::EV_WRITE);
-}
-
-prefix_ void g0dil::mediaserv::Connection::unregisterCallback()
-{
- satcom::lib::Scheduler::instance().remove(client_,satcom::lib::Scheduler::EV_WRITE);
-}
-
-prefix_ void g0dil::mediaserv::Connection::registerTimeout(unsigned timeout)
-{
- satcom::lib::Scheduler::instance().timeout(timeout,satcom::lib::membind(&Connection::timeout,this));
-}
-
-prefix_ unsigned g0dil::mediaserv::Connection::targetBytes()
-{
- return ((bufferMSecs_ + ((satcom::lib::now()-start_)/1000u))*bytesPerSecond_)/1000u;
-}
-
-///////////////////////////////cci.e///////////////////////////////////////
-#undef prefix_
-
-\f
-// Local Variables:
-// mode: c++
-// End:
--- /dev/null
+// $Id$
+//
+// Copyright (C) 2006
+
+// Definition of non-inline non-template functions
+
+//#include "HTTPConnection.hh"
+//#include "HTTPConnection.ih"
+
+// Custom includes
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sstream>
+
+#include <boost/lexical_cast.hpp>
+#include <boost/algorithm/string.hpp>
+
+#include "Utils/membind.hh"
+
+#include "SimpleHTTPServer.hh"
+#include "StreamConnection.hh"
+#include "MimeTypes.hh"
+
+//#include "HTTPConnection.mpp"
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+prefix_ g0dil::mediaserv::HTTPConnection::HTTPConnection(ClientHandle client,
+ SimpleHTTPServer & server,
+ HTTPLogger & logger)
+ : client_(client), server_(server), logger_(logger), fileFd_(-1), bandwidth_(0)
+{
+ satcom::lib::ReadHelper<ClientHandle>
+ ::dispatch(client_, MaxRequestSize, satcom::lib::ReadUntil("\r\n\r\n"),
+ satcom::lib::membind(&HTTPConnection::handleRequest,this));
+}
+
+prefix_ g0dil::mediaserv::HTTPConnection::~HTTPConnection()
+{
+// if (client_.valid())
+// client_.close();
+ if (fileFd_ != -1)
+ ::close(fileFd_);
+}
+
+prefix_ void
+g0dil::mediaserv::HTTPConnection::handleRequest(satcom::lib::ReadHelper<ClientHandle>::ptr helper)
+{
+
+ try {
+ helper->throw_error();
+
+ request_.parseRequest(helper->handle(), helper->data());
+
+ boost::algorithm::split_iterator<std::string::const_iterator>
+ i (request_.url(),boost::algorithm::first_finder("."));
+ boost::algorithm::split_iterator<std::string::const_iterator> i_end;
+ if (i == i_end || ++i == i_end) throw InvalidHTTPRequestException();
+ bandwidth_ = boost::lexical_cast<unsigned>(std::string(i->begin(),i->end()));
+ if (++i == i_end) throw InvalidHTTPRequestException();
+ std::string const & mimeType (MimeTypes::lookup(std::string(i->begin(), i->end())));
+ if (++i != i_end) throw InvalidHTTPRequestException();
+
+ fileFd_ = ::open(request_.url().c_str(),O_RDONLY);
+ if (fileFd_ < 0) throw satcom::lib::SystemException(errno);
+ struct ::stat s;
+ if (::fstat(fileFd_,&s) < 0) throw satcom::lib::SystemException(errno);
+
+ std::ostringstream response;
+ response << request_.version() << (request_.version().empty() ? "" : " ") << "200 OK\r\n";
+ response << "Content-Type: " << mimeType << "\r\n";
+ response << "Content-Length: " << s.st_size << "\r\n\r\n";
+
+ satcom::lib::WriteHelper<ClientHandle>
+ ::dispatch(client_, response.str(),
+ satcom::lib::membind(&HTTPConnection::startStream,this));
+
+ }
+ catch (std::exception const & ex) {
+ logger_.invalidRequest(ex.what());
+ server_.done(ptr(this));
+ }
+}
+
+prefix_ void
+g0dil::mediaserv::HTTPConnection::startStream(satcom::lib::WriteHelper<ClientHandle>::ptr helper)
+{
+ try {
+ helper->throw_error();
+
+ connection_.reset(new StreamConnection(fileFd_, bandwidth_, client_, StreamBufferMSecs,
+ boost::bind(&HTTPConnection::done,this)));
+ connection_->start();
+ }
+ catch (std::exception const & ex) {
+ logger_.failedRequest(request_, ex.what());
+ server_.done(ptr(this));
+ }
+}
+
+prefix_ void g0dil::mediaserv::HTTPConnection::done()
+{
+ logger_.request(request_, connection_->bytesSent());
+ server_.done(ptr(this));
+}
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+//#include "HTTPConnection.mpp"
+
+\f
+// Local Variables:
+// mode: c++
+// End:
--- /dev/null
+// $Id$
+//
+// Copyright (C) 2006
+
+#ifndef HH_HTTPConnection_
+#define HH_HTTPConnection_ 1
+
+// Custom includes
+#include <boost/utility.hpp>
+#include <boost/intrusive_ptr.hpp>
+#include <boost/scoped_ptr.hpp>
+#include "Socket/ClientSocketHandle.hh"
+#include "Utils/intrusive_refcount.hh"
+#include "Scheduler/ReadHelper.hh"
+#include "Scheduler/WriteHelper.hh"
+#include "HTTPLogger.hh"
+#include "HTTPRequest.hh"
+
+//#include "HTTPConnection.mpp"
+///////////////////////////////hh.p////////////////////////////////////////
+
+namespace g0dil {
+namespace mediaserv {
+
+ class SimpleHTTPServer;
+ class StreamConnection;
+
+ class HTTPConnection
+ : public satcom::lib::intrusive_refcount
+ {
+ public:
+ ///////////////////////////////////////////////////////////////////////////
+ // Types
+
+ typedef boost::intrusive_ptr<HTTPConnection> ptr;
+ typedef satcom::lib::ClientSocketHandle<
+ satcom::lib::MakeSocketPolicy<satcom::lib::ConnectedCommunicationPolicy,
+ satcom::lib::StreamFramingPolicy,
+ satcom::lib::ReadablePolicy,
+ satcom::lib::WriteablePolicy>::policy> ClientHandle;
+
+ static const unsigned MaxRequestSize = 16384;
+ static const unsigned StreamBufferMSecs = 4000;
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///\name Structors and default members
+ ///@{
+
+ HTTPConnection(ClientHandle client, SimpleHTTPServer & server, HTTPLogger & logger);
+ ~HTTPConnection();
+
+ ///@}
+ ///////////////////////////////////////////////////////////////////////////
+
+ void done();
+
+ protected:
+
+ private:
+ void handleRequest(satcom::lib::ReadHelper<ClientHandle>::ptr);
+ void startStream(satcom::lib::WriteHelper<ClientHandle>::ptr);
+
+ ClientHandle client_;
+ SimpleHTTPServer & server_;
+ HTTPLogger & logger_;
+ HTTPRequest request_;
+ boost::scoped_ptr<StreamConnection> connection_;
+ int fileFd_;
+ unsigned bandwidth_;
+ };
+
+}}
+
+///////////////////////////////hh.e////////////////////////////////////////
+//#include "HTTPConnection.cci"
+//#include "HTTPConnection.ct"
+//#include "HTTPConnection.cti"
+//#include "HTTPConnection.mpp"
+#endif
+
+\f
+// Local Variables:
+// mode: c++
+// End:
--- /dev/null
+// $Id$
+//
+// Copyright (C) 2006
+
+// TODO: error logging
+
+// Definition of non-inline non-template functions
+
+#include "HTTPLogger.hh"
+//#include "HTTPLogger.ih"
+
+// Custom includes
+#include "Socket/INetAddressing.hh"
+#include "Socket/CommunicationPolicy.hh"
+
+//#include "HTTPLogger.mpp"
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+namespace {
+
+ std::string currentDateTimeString()
+ {
+ time_t t;
+ time(&t);
+ char buffer[32];
+ strftime(buffer,32,"%d/%b/%Y:%H:%M:%S %z",localtime(&t));
+ buffer[31] = 0;
+ return std::string(buffer);
+ }
+
+}
+
+prefix_ g0dil::mediaserv::HTTPLogger::HTTPLogger(std::string logfile)
+ : logFile_(logfile.c_str(),std::ofstream::app)
+{
+ if (!logFile_)
+ throw InvalidLogFileException();
+ logFile_ << "(start)" << " - - [" << currentDateTimeString() << "] mediaserv started"
+ << std::endl;
+}
+
+prefix_ g0dil::mediaserv::HTTPLogger::~HTTPLogger()
+{
+ logFile_ << "(shutdown)" << " - - [" << currentDateTimeString() << "] mediaserv terminated"
+ << std::endl;
+}
+
+prefix_ void g0dil::mediaserv::HTTPLogger::invalidRequest(std::string message)
+{
+ logFile_ << "(unknown client)" << " - - [" << currentDateTimeString() << "] "
+ << "invalid request: " << message << std::endl;
+}
+
+prefix_ void g0dil::mediaserv::HTTPLogger::invalidRequest(HTTPRequest const & request,
+ std::string message)
+{
+ logFile_ << request.host() << " - - [" << currentDateTimeString() << "] ";
+ if (!request.method().empty())
+ logFile_ << "\"" << request.method() << " " << request.url() << " " << request.version() << "\" ";
+ logFile_ << "invalid request: " << message << std::endl;
+}
+
+prefix_ void g0dil::mediaserv::HTTPLogger::failedRequest(std::string message)
+{
+ logFile_ << "(unknown client)" << " - - [" << currentDateTimeString() << "] "
+ << "failed request: " << message << std::endl;
+}
+
+prefix_ void g0dil::mediaserv::HTTPLogger::failedRequest(HTTPRequest const & request,
+ std::string message)
+{
+ logFile_ << request.host() << " - - [" << currentDateTimeString() << "] ";
+ if (!request.method().empty())
+ logFile_ << "\"" << request.method() << " " << request.url() << " " << request.version() << "\" ";
+ logFile_ << "invalid request: " << message << std::endl;
+}
+
+prefix_ void g0dil::mediaserv::HTTPLogger::request(HTTPRequest const & request,
+ unsigned bytes)
+{
+ logFile_ << request.host() << " - - [" << currentDateTimeString() << "] "
+ << "\"" << request.method() << " " << request.url() << " " << request.version()
+ << "\" 200 " << bytes << " \"\" \"\"" << std::endl;
+}
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+//#include "HTTPLogger.mpp"
+
+\f
+// Local Variables:
+// mode: c++
+// End:
--- /dev/null
+// $Id$
+//
+// Copyright (C) 2006
+
+#ifndef HH_HTTPLogger_
+#define HH_HTTPLogger_ 1
+
+// Custom includes
+#include <fstream>
+#include "Socket/FileHandle.hh"
+#include "HTTPRequest.hh"
+
+//#include "HTTPLogger.mpp"
+///////////////////////////////hh.p////////////////////////////////////////
+
+namespace g0dil {
+namespace mediaserv {
+
+ class HTTPLogger
+ {
+ public:
+ ///////////////////////////////////////////////////////////////////////////
+ ///\name Structors and default members
+ ///@{
+
+ HTTPLogger(std::string logfile);
+ ~HTTPLogger();
+
+ ///@}
+ ///////////////////////////////////////////////////////////////////////////
+
+ void invalidRequest(std::string message);
+ void invalidRequest(HTTPRequest const & request, std::string message);
+ void failedRequest(std::string message);
+ void failedRequest(HTTPRequest const & request, std::string message);
+ void request(HTTPRequest const & request, unsigned bytes);
+
+ protected:
+
+ private:
+ std::ofstream logFile_;
+ };
+
+ struct InvalidLogFileException : public std::exception
+ { char const * what() const throw() { return "invalid log file"; } };
+
+}}
+
+///////////////////////////////hh.e////////////////////////////////////////
+//#include "HTTPLogger.cci"
+//#include "HTTPLogger.ct"
+//#include "HTTPLogger.cti"
+//#include "HTTPLogger.mpp"
+#endif
+
+\f
+// Local Variables:
+// mode: c++
+// End:
--- /dev/null
+// $Id$
+//
+// Copyright (C) 2006
+
+// Definition of non-inline non-template functions
+
+#include "HTTPRequest.hh"
+//#include "HTTPRequest.ih"
+
+// Custom includes
+#include <boost/algorithm/string.hpp>
+#include <boost/range.hpp>
+#include "Socket/ClientSocketHandle.hh"
+#include "Socket/INetAddressing.hh"
+#include "Socket/CommunicationPolicy.hh"
+
+//#include "HTTPRequest.mpp"
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+prefix_ g0dil::mediaserv::HTTPRequest::HTTPRequest()
+{}
+
+prefix_ g0dil::mediaserv::HTTPRequest::HTTPRequest(satcom::lib::FileHandle handle,
+ std::string const & request)
+{
+ parseRequest(handle,request);
+}
+
+prefix_ void g0dil::mediaserv::HTTPRequest::parseRequest(satcom::lib::FileHandle handle,
+ std::string const & request)
+{
+ typedef satcom::lib::ClientSocketHandle< satcom::lib::MakeSocketPolicy<
+ satcom::lib::INet4AddressingPolicy,
+ satcom::lib::ConnectedCommunicationPolicy >::policy> IPHandle;
+ try {
+ host_ = satcom::lib::dynamic_socket_cast<IPHandle>(handle).peer().host();
+ }
+ catch (std::bad_cast const *) {
+ host_ = "(unidentified address)";
+ }
+ boost::algorithm::split_iterator<std::string::const_iterator>
+ line (request, boost::algorithm::first_finder("\n"));
+ boost::algorithm::split_iterator<std::string::const_iterator> line_end;
+ if (line == line_end) return;
+ parseRequestURL(*line);
+ for (++line; line != line_end; ++line)
+ parseRequestHeader(*line);
+}
+
+prefix_ void g0dil::mediaserv::HTTPRequest::
+parseRequestURL(boost::iterator_range<std::string::const_iterator> line)
+{
+ boost::algorithm::split_iterator<std::string::const_iterator>
+ token (line, boost::algorithm::first_finder(" "));
+ boost::algorithm::split_iterator<std::string::const_iterator> token_end;
+
+ if (token == token_end)
+ throw InvalidHTTPRequestException();
+ method_ = std::string(token->begin(),token->end());
+ if (method_ != "GET")
+ throw InvalidHTTPRequestException();
+ if (++token == token_end)
+ throw InvalidHTTPRequestException();
+ url_ = std::string(token->begin(),token->end());
+ if (++token == token_end)
+ return;
+ version_ = std::string(token->begin(),token->end());
+ boost::trim(version_);
+ if (! boost::starts_with(version_,"HTTP/"))
+ throw InvalidHTTPRequestException();
+ if (++token != token_end)
+ throw InvalidHTTPRequestException();
+}
+
+prefix_ void g0dil::mediaserv::HTTPRequest::
+parseRequestHeader(boost::iterator_range<std::string::const_iterator> line)
+{
+ boost::iterator_range<std::string::const_iterator> i (boost::find_first(line,":"));
+ if (i.empty())
+ throw InvalidHTTPRequestException();
+ std::string key (line.begin(),i.begin());
+ std::string value (i.end(),line.end());
+ boost::to_lower(key);
+ boost::trim(value);
+ headers_.insert(std::make_pair(key,value));
+}
+
+prefix_ std::string const & g0dil::mediaserv::HTTPRequest::operator[](std::string const & key)
+ const
+{
+ static std::string empty;
+ Headers::const_iterator i (headers_.find(key));
+ if (i == headers_.end()) return empty;
+ return i->second;
+}
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+//#include "HTTPRequest.mpp"
+
+\f
+// Local Variables:
+// mode: c++
+// End:
--- /dev/null
+// $Id$
+//
+// Copyright (C) 2006
+
+// Definition of inline non-template functions
+
+// Custom includes
+
+#define prefix_ inline
+///////////////////////////////cci.p///////////////////////////////////////
+
+prefix_ std::string const & g0dil::mediaserv::HTTPRequest::host()
+ const
+{
+ return host_;
+}
+
+prefix_ std::string const & g0dil::mediaserv::HTTPRequest::method()
+ const
+{
+ return method_;
+}
+
+prefix_ std::string const & g0dil::mediaserv::HTTPRequest::url()
+ const
+{
+ return url_;
+}
+
+prefix_ std::string const & g0dil::mediaserv::HTTPRequest::version()
+ const
+{
+ return version_;
+}
+
+///////////////////////////////cci.e///////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// End:
--- /dev/null
+// $Id$
+//
+// Copyright (C) 2006
+
+#ifndef HH_HTTPRequest_
+#define HH_HTTPRequest_ 1
+
+// Custom includes
+#include <exception>
+#include <string>
+#include <map>
+#include <boost/range/iterator_range.hpp>
+#include "Socket/FileHandle.hh"
+
+//#include "HTTPRequest.mpp"
+///////////////////////////////hh.p////////////////////////////////////////
+
+namespace g0dil {
+namespace mediaserv {
+
+ class HTTPRequest
+ {
+ public:
+ ///////////////////////////////////////////////////////////////////////////
+ // Types
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///\name Structors and default members
+ ///@{
+
+ HTTPRequest();
+ HTTPRequest(satcom::lib::FileHandle handle, std::string const & request);
+
+ ///@}
+ ///////////////////////////////////////////////////////////////////////////
+ ///\name Accessors
+ ///@{
+
+ std::string const & host() const;
+ std::string const & method() const;
+ std::string const & url() const;
+ std::string const & version() const;
+ std::string const & operator[](std::string const & key) const;
+
+ ///@}
+ ///////////////////////////////////////////////////////////////////////////
+ ///\name Mutators
+ ///@{
+
+ void parseRequest(satcom::lib::FileHandle handle, std::string const & request);
+
+ ///@}
+
+ protected:
+
+ private:
+ void parseRequestURL(boost::iterator_range<std::string::const_iterator> line);
+ void parseRequestHeader(boost::iterator_range<std::string::const_iterator> line);
+
+ typedef std::map<std::string,std::string> Headers;
+
+ std::string host_;
+ std::string method_;
+ std::string url_;
+ std::string version_;
+ Headers headers_;
+ };
+
+ struct InvalidHTTPRequestException : public std::exception
+ { char const * what() const throw() { return "invalid http request"; } };
+
+}}
+
+///////////////////////////////hh.e////////////////////////////////////////
+#include "HTTPRequest.cci"
+//#include "HTTPRequest.ct"
+//#include "HTTPRequest.cti"
+//#include "HTTPRequest.mpp"
+#endif
+
+\f
+// Local Variables:
+// mode: c++
+// End:
// Unit tests
-//#include "Connection.test.hh"
-//#include "Connection.test.ih"
+//#include "HTTPRequest.test.hh"
+//#include "HTTPRequest.test.ih"
// Custom includes
-#include "Connection.hh"
+#include "HTTPRequest.hh"
#include <boost/test/auto_unit_test.hpp>
#include <boost/test/test_tools.hpp>
#define prefix_
///////////////////////////////cc.p////////////////////////////////////////
-BOOST_AUTO_UNIT_TEST(connection)
+BOOST_AUTO_UNIT_TEST(httpRequest)
{}
///////////////////////////////cc.e////////////////////////////////////////
--- /dev/null
+// $Id$
+//
+// Copyright (C) 2006
+
+// Definition of non-inline non-template functions
+
+#include "MimeTypes.hh"
+//#include "MimeTypes.ih"
+
+// Custom includes
+
+//#include "MimeTypes.mpp"
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+prefix_ std::string const & g0dil::mediaserv::MimeTypes::lookup(std::string extension)
+{
+ static std::string defaultType ("application/octet-stream");
+ Map::iterator i (instance().mimeTypes_.find(extension));
+ if (i == instance().mimeTypes_.end())
+ return defaultType;
+ else
+ return i->second;
+}
+
+prefix_ void g0dil::mediaserv::MimeTypes::add(std::string extension, std::string mimetype)
+{
+ instance().mimeTypes_[extension] = mimetype;
+}
+
+prefix_ g0dil::mediaserv::MimeTypes & g0dil::mediaserv::MimeTypes::instance()
+{
+ static MimeTypes instance;
+ return instance;
+}
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+//#include "MimeTypes.mpp"
+
+\f
+// Local Variables:
+// mode: c++
+// End:
--- /dev/null
+// $Id$
+//
+// Copyright (C) 2006
+
+#ifndef HH_MimeTypes_
+#define HH_MimeTypes_ 1
+
+// Custom includes
+#include <string>
+#include <map>
+
+//#include "MimeTypes.mpp"
+///////////////////////////////hh.p////////////////////////////////////////
+
+namespace g0dil {
+namespace mediaserv {
+
+ class MimeTypes
+ {
+ public:
+ ///////////////////////////////////////////////////////////////////////////
+ // Types
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///\name Structors and default members
+ ///@{
+
+ // default default constructor
+ // default copy constructor
+ // default copy assignment
+ // default destructor
+
+ // no conversion constructors
+
+ ///@}
+ ///////////////////////////////////////////////////////////////////////////
+
+ static std::string const & lookup(std::string extension);
+ static void add(std::string extension, std::string mimetype);
+
+ protected:
+
+ private:
+ typedef std::map<std::string,std::string> Map;
+
+ static MimeTypes & instance();
+
+ Map mimeTypes_;
+ };
+
+
+}}
+
+///////////////////////////////hh.e////////////////////////////////////////
+//#include "MimeTypes.cci"
+//#include "MimeTypes.ct"
+//#include "MimeTypes.cti"
+//#include "MimeTypes.mpp"
+#endif
+
+\f
+// Local Variables:
+// mode: c++
+// End:
--- /dev/null
+// $Id$
+//
+// Copyright (C) 2006
+
+// Definition of non-inline non-template functions
+
+// TODO: success logging
+// TODO: limit max number of clients
+
+#include "SimpleHTTPServer.hh"
+//#include "SimpleHTTPServer.ih"
+
+// Custom includes
+#include "Utils/membind.hh"
+
+//#include "SimpleHTTPServer.mpp"
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+g0dil::mediaserv::SimpleHTTPServer * g0dil::mediaserv::SimpleHTTPServer::instance_ = 0;
+
+prefix_ g0dil::mediaserv::SimpleHTTPServer::SimpleHTTPServer(ServerHandle socket,
+ HTTPLogger & logger)
+ : socket_(socket), logger_(logger)
+{
+ instance_ = this;
+ satcom::lib::Scheduler::instance()
+ .add(socket_,
+ satcom::lib::membind(&SimpleHTTPServer::newConnection,this),
+ satcom::lib::Scheduler::EV_READ);
+}
+
+prefix_ g0dil::mediaserv::SimpleHTTPServer::~SimpleHTTPServer()
+{
+ instance_ = 0;
+}
+
+prefix_ void
+g0dil::mediaserv::SimpleHTTPServer::newConnection(ServerHandle handle,
+ satcom::lib::Scheduler::EventId event)
+{
+ if (event != satcom::lib::Scheduler::EV_READ) {
+ logger_.failedRequest("unexpected event on server socket .. shuting down ..");
+ satcom::lib::Scheduler::instance().terminate();
+ return;
+ }
+ try {
+ ServerHandle::ClientSocketHandle client (socket_.accept());
+ if (! client.valid()) {
+ logger_.failedRequest("accept() would block !?");
+ return;
+ }
+ connections_.insert(HTTPConnection::ptr(new HTTPConnection(client,*this,logger_)));
+ }
+ catch (std::exception & ex) {
+ logger_.failedRequest(ex.what());
+ }
+}
+
+prefix_ void g0dil::mediaserv::SimpleHTTPServer::done(HTTPConnection::ptr connection)
+{
+ connections_.erase(connection);
+}
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+//#include "SimpleHTTPServer.mpp"
+
+\f
+// Local Variables:
+// mode: c++
+// End:
--- /dev/null
+// $Id$
+//
+// Copyright (C) 2006
+
+// Definition of inline non-template functions
+
+// Custom includes
+#include <boost/assert.hpp>
+
+#define prefix_ inline
+///////////////////////////////cci.p///////////////////////////////////////
+
+prefix_ g0dil::mediaserv::SimpleHTTPServer & g0dil::mediaserv::SimpleHTTPServer::instance()
+{
+ BOOST_ASSERT(instance_);
+ return *instance_;
+}
+
+///////////////////////////////cci.e///////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// End:
--- /dev/null
+// $Id$
+//
+// Copyright (C) 2006
+
+#ifndef HH_SimpleHTTPServer_
+#define HH_SimpleHTTPServer_ 1
+
+// Custom includes
+#include <set>
+#include <boost/utility.hpp>
+#include "Socket/ServerSocketHandle.hh"
+#include "Socket/CommunicationPolicy.hh"
+#include "Socket/FramingPolicy.hh"
+#include "Socket/ReadWritePolicy.hh"
+#include "Scheduler/Scheduler.hh"
+
+#include "HTTPLogger.hh"
+#include "HTTPConnection.hh"
+
+//#include "SimpleHTTPServer.mpp"
+///////////////////////////////hh.p////////////////////////////////////////
+
+namespace g0dil {
+namespace mediaserv {
+
+ class SimpleHTTPServer
+ : boost::noncopyable
+ {
+ public:
+ ///////////////////////////////////////////////////////////////////////////
+ // Types
+
+ typedef HTTPConnection::ClientHandle::ServerSocketHandle ServerHandle;
+
+ ///////////////////////////////////////////////////////////////////////////
+ ///\name Structors and default members
+ ///@{
+
+ SimpleHTTPServer(ServerHandle socket, HTTPLogger & logger);
+ ~SimpleHTTPServer();
+
+ static SimpleHTTPServer & instance();
+
+ ///@}
+ ///////////////////////////////////////////////////////////////////////////
+
+ void done(HTTPConnection::ptr connection);
+
+ protected:
+
+ private:
+ void newConnection(ServerHandle handle, satcom::lib::Scheduler::EventId event);
+
+ typedef std::set<HTTPConnection::ptr> Connections;
+
+ ServerHandle socket_;
+ HTTPLogger & logger_;
+ Connections connections_;
+
+ static SimpleHTTPServer * instance_;
+ };
+
+}}
+
+///////////////////////////////hh.e////////////////////////////////////////
+#include "SimpleHTTPServer.cci"
+//#include "SimpleHTTPServer.ct"
+//#include "SimpleHTTPServer.cti"
+//#include "SimpleHTTPServer.mpp"
+#endif
+
+\f
+// Local Variables:
+// mode: c++
+// End:
// Unit tests
-//#include "Connection.test.hh"
-//#include "Connection.test.ih"
+//#include "SimpleHTTPServer.test.hh"
+//#include "SimpleHTTPServer.test.ih"
// Custom includes
-#include "Connection.hh"
+#include "SimpleHTTPServer.hh"
#include <boost/test/auto_unit_test.hpp>
#include <boost/test/test_tools.hpp>
#define prefix_
///////////////////////////////cc.p////////////////////////////////////////
-BOOST_AUTO_UNIT_TEST(connection)
+BOOST_AUTO_UNIT_TEST(simpleHttpServer)
{}
///////////////////////////////cc.e////////////////////////////////////////
--- /dev/null
+// $Id$
+//
+// Copyright (C) 2006
+
+// Definition of non-inline non-template functions
+
+#include "StreamConnection.hh"
+//#include "StreamConnection.ih"
+
+// Custom includes
+#include <unistd.h>
+#include "SimpleHTTPServer.hh"
+
+//#include "StreamConnection.mpp"
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+prefix_ g0dil::mediaserv::StreamConnection::StreamConnection(int fileFd,
+ unsigned bytesPerSecond,
+ ClientHandle client,
+ unsigned bufferMSecs,
+ Callback callback)
+ : fileFd_(fileFd), bytesPerSecond_(bytesPerSecond), client_(client),
+ bufferMSecs_(bufferMSecs), callback_(callback), bytesWritten_(0),
+ start_(satcom::lib::now()), bufferSize_(0), terminate_(false)
+{
+ fillBuffer();
+}
+
+
+prefix_ void g0dil::mediaserv::StreamConnection::start()
+{
+ registerCallback();
+}
+
+prefix_ g0dil::mediaserv::StreamConnection::~StreamConnection()
+{
+ unregisterCallback();
+ // FIXME: unregisterTimeout
+}
+
+prefix_ void g0dil::mediaserv::StreamConnection::fillBuffer()
+{
+ bufferSize_ = ::read(fileFd_,buffer_,packetSize);
+ if (bufferSize_ < 0)
+ callback_();
+ else if (bufferSize_ < packetSize)
+ terminate_ = true;
+}
+
+prefix_ void g0dil::mediaserv::StreamConnection::callback(ClientHandle client,
+ satcom::lib::Scheduler::EventId event)
+{
+ if (event != satcom::lib::Scheduler::EV_WRITE) {
+ callback_();
+ return;
+ }
+ unsigned target (targetBytes());
+ if (target - bytesWritten_ >= bufferSize_) {
+ if (client_.write(buffer_,bufferSize_) < bufferSize_) {
+ callback_();
+ return;
+ }
+ bytesWritten_ += bufferSize_;
+ if (terminate_) {
+ callback_();
+ return;
+ } else
+ fillBuffer();
+ } else {
+ unregisterCallback();
+ registerTimeout(((bufferSize_-(target-bytesWritten_))*1000)/bytesPerSecond_);
+ }
+}
+
+prefix_ void g0dil::mediaserv::StreamConnection::timeout()
+{
+ registerCallback();
+}
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+//#include "StreamConnection.mpp"
+
+\f
+// Local Variables:
+// mode: c++
+// End:
--- /dev/null
+// $Id$
+//
+// Copyright (C) 2006
+
+// Definition of inline non-template functions
+
+// Custom includes
+#include "Utils/membind.hh"
+
+#define prefix_ inline
+///////////////////////////////cci.p///////////////////////////////////////
+
+prefix_ unsigned g0dil::mediaserv::StreamConnection::bytesSent()
+{
+ return bytesWritten_;
+}
+
+prefix_ void g0dil::mediaserv::StreamConnection::registerCallback()
+{
+ satcom::lib::Scheduler::instance()
+ .add(client_,satcom::lib::membind(&StreamConnection::callback,this),
+ satcom::lib::Scheduler::EV_WRITE);
+}
+
+prefix_ void g0dil::mediaserv::StreamConnection::unregisterCallback()
+{
+ satcom::lib::Scheduler::instance().remove(client_,satcom::lib::Scheduler::EV_WRITE);
+}
+
+prefix_ void g0dil::mediaserv::StreamConnection::registerTimeout(unsigned timeout)
+{
+ satcom::lib::Scheduler::instance()
+ .timeout(timeout,satcom::lib::membind(&StreamConnection::timeout,this));
+}
+
+prefix_ unsigned g0dil::mediaserv::StreamConnection::targetBytes()
+{
+ return ((bufferMSecs_ + ((satcom::lib::now()-start_)/1000u))*bytesPerSecond_)/1000u;
+}
+
+///////////////////////////////cci.e///////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// End:
//
// Copyright (C) 2006
-#ifndef HH_Connection_
-#define HH_Connection_ 1
+#ifndef HH_StreamConnection_
+#define HH_StreamConnection_ 1
// Custom includes
#include <boost/utility.hpp>
+#include <boost/intrusive_ptr.hpp>
+
#include "Utils/MicroTime.hh"
+#include "Utils/intrusive_refcount.hh"
#include "Scheduler/Scheduler.hh"
#include "Socket/ClientSocketHandle.hh"
#include "Socket/CommunicationPolicy.hh"
#include "Socket/FramingPolicy.hh"
-#include "Socket/BufferingPolicy.hh"
#include "Socket/ReadWritePolicy.hh"
-//#include "Connection.mpp"
+//#include "StreamConnection.mpp"
///////////////////////////////hh.p////////////////////////////////////////
namespace g0dil {
namespace mediaserv {
- class Connection : boost::noncopyable
+ class StreamConnection : public satcom::lib::intrusive_refcount
{
public:
///////////////////////////////////////////////////////////////////////////
typedef satcom::lib::ClientSocketHandle<
satcom::lib::MakeSocketPolicy<satcom::lib::ConnectedCommunicationPolicy,
satcom::lib::StreamFramingPolicy,
- satcom::lib::WriteablePolicy,
- satcom::lib::SocketBufferingPolicy>::policy> ClientHandle;
+ satcom::lib::WriteablePolicy>::policy> ClientHandle;
+
+ typedef boost::intrusive_ptr<StreamConnection> ptr;
+ typedef boost::function<void ()> Callback;
static const unsigned packetSize = 1400;
///\name Structors and default members
///@{
- Connection(int fileFd, unsigned bytesPerSecond, ClientHandle client,
- unsigned bufferMSecs);
+ StreamConnection(int fileFd, unsigned bytesPerSecond, ClientHandle client,
+ unsigned bufferMSecs, Callback callback);
+ ~StreamConnection();
///@}
+ ///////////////////////////////////////////////////////////////////////////
+
+ void start();
+ unsigned bytesSent();
protected:
unsigned bytesPerSecond_;
ClientHandle client_;
unsigned bufferMSecs_;
+ Callback callback_;
unsigned bytesWritten_;
satcom::lib::MicroTime start_;
}}
///////////////////////////////hh.e////////////////////////////////////////
-#include "Connection.cci"
-//#include "Connection.ct"
-//#include "Connection.cti"
-//#include "Connection.mpp"
+#include "StreamConnection.cci"
+//#include "StreamConnection.ct"
+//#include "StreamConnection.cti"
+//#include "StreamConnection.mpp"
#endif
\f
//#include "Connection.test.ih"
// Custom includes
-#include "Connection.hh"
+#include "StreamConnection.hh"
#include <boost/test/auto_unit_test.hpp>
#include <boost/test/test_tools.hpp>
//
// Copyright (C) 2006
+// TODO: open log-file as non-root
+// TODO: open socket as root ?
+// TODO: so best should be: start mediaserv as root and then drop privileges
+// TODO: mime-db
+
// Definition of non-inline non-template functions
//#include "main.hh"
//#include "main.ih"
// Custom includes
+#include <unistd.h>
+#include <iostream>
+
+#include "Server/HTTPLogger.hh"
+#include "Server/SimpleHTTPServer.hh"
+#include "Socket/TCPSocketHandle.hh"
//#include "main.mpp"
#define prefix_
///////////////////////////////cc.p////////////////////////////////////////
+namespace {
+ void errfail(char const * fn)
+ {
+ std::cerr << fn << ": (" << errno << ") " << strerror(errno) << "\n";
+ exit(1);
+ }
+
+}
+
int main(int argc, char** argv)
{
+ //try {
+ g0dil::mediaserv::HTTPLogger logger ("log/access.log");
+ //try {
+ if (chdir("wwwroot") < 0) errfail("chdir");
+ if (chroot(".") < 0) errfail("chroot");
+ if (setreuid(getuid(),getuid()) < 0) errfail("setreuid");
+ satcom::lib::TCPv4ServerSocketHandle socket (argv[1]);
+ socket.blocking(false);
+ socket.protocol().reuseaddr(true);
+ g0dil::mediaserv::SimpleHTTPServer server (socket,logger);
+ satcom::lib::Scheduler::instance().process();
+// }
+// catch (std::exception const & ex) {
+// logger.failedRequest(ex.what());
+// }
+// }
+// catch (std::exception const & ex) {
+// std::cerr << ex.what() << "\n";
+// exit(1);
+// }
return 0;
}
--- /dev/null
+// $Id$
+//
+// Copyright (C) 2006
+
+// Definition of non-inline non-template functions
+
+//#include "testclient.hh"
+//#include "testclient.ih"
+
+// Custom includes
+#include <iostream>
+#include "Socket/TCPSocketHandle.hh"
+#include "Utils/MicroTime.hh"
+
+//#include "testclient.mpp"
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+int main(int argc, char** argv)
+{
+ satcom::lib::TCPv4ClientSocketHandle handle (argv[1]);
+ handle.write(argv[2]);
+ handle.write(" HTTP/1.1\r\n");
+ if (argc>3) {
+ handle.write("Host: ");
+ handle.write(argv[3]);
+ handle.write("\r\n");
+ }
+ handle.write("\r\n");
+ unsigned size = 0;
+ satcom::lib::MicroTime offset = satcom::lib::now();
+ while (handle) {
+ size += handle.read().size();
+ std::cout << satcom::lib::now()-offset << " " << size << "\n";
+ }
+}
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+//#include "testclient.mpp"
+
+\f
+// Local Variables:
+// mode: c++
+// End: