#ifndef __FCGI_H__
#define __FCGI_H__
+#include <aeb/fcgi/fcgi_endian.h>
+
+#include <aeb/fcgi/fcgi_request.h>
+#include <aeb/fcgi/fcgi_handler.h>
+
namespace aeb {
namespace fcgi {
*
*/
template <typename Descriptor,typename InternetProtocol,typename RequestHandler>
-class acceptor : public basic_socket_acceptor<Descriptor,InternetProtocol>
+class acceptor : public aeb::net::basic_socket_acceptor<Descriptor,InternetProtocol>
{
public:
typedef Descriptor socket_type;
- acceptor(const ip::basic_endpoint<InternetProtocol> &e) :
- basic_socket_acceptor<Descriptor,InternetProtcol>(e)
+ acceptor(const aeb::net::ip::basic_endpoint<InternetProtocol> &e) :
+ aeb::net::basic_socket_acceptor<Descriptor,InternetProtocol>(e)
{
int val = 1;
- m_socket.set_option(SO_REUSEADDR,val);
+ aeb::net::basic_socket_acceptor<Descriptor,InternetProtocol>::m_socket.set_option(SO_REUSEADDR,val);
};
// Acceptor main entry
void on_accept()
{
- endpoint_type tmp;
+ typename InternetProtocol::endpoint_type tmp;
int len = tmp.size();
- detail::socket_type s;
+ socket_type s;
aeb::sys::error ec;
s = aeb::net::accept<socklen_t>(this->m_descriptor,tmp.data(),&len,ec);
if (s != aeb::net::detail::invalid_socket)
{
- m_r = RequestHandler::ptr(new RequestHandler(s)) ;
+ m_r = typename RequestHandler::ptr(new RequestHandler(s)) ;
m_r->add_ref(); //because request_handler will kill himself
}
};
protected:
- RequestHandler::ptr m_r;
+ typename RequestHandler::ptr m_r;
};
--- /dev/null
+#ifndef __FCGI_ENDIAN_H__
+#define __FCGI_ENDIAN_H__
+
+namespace aeb {
+namespace fcgi {
+
+template <typename T>
+class endianBase
+{
+ protected:
+ static T swap(const T &_val);
+};
+
+template <>
+uint16_t endianBase<uint16_t>::swap(const uint16_t &_val)
+{
+ return ( (_val & 0xFF00) >> 8) | ( (_val & 0x00FF) <<8 );
+}
+
+template <>
+uint32_t endianBase<uint32_t>::swap(const uint32_t &_val)
+{
+ return ( (_val & 0xFF000000) >> 24)
+ | ( (_val & 0x00FF0000) >> 8 )
+ | ( (_val & 0x0000FF00) << 8)
+ | ( (_val & 0x000000FF) << 24 );
+}
+
+/**
+ * @brief
+ */
+template <typename T>
+class bigEndian : public endianBase<T>
+{
+ protected:
+ T m_Data;
+
+ protected:
+ static T doSwap(const T &_b) { return endianBase<T>::swap(_b); };
+ public:
+ bigEndian() = default;
+
+ // Build from platform
+ bigEndian(const T& _val) : m_Data(doSwap(_val)) {}
+
+ // Store out
+ operator T() const { return doSwap(m_Data); }
+
+ friend std::ostream &operator <<(std::ostream &out,const bigEndian b) {out<<T(b) ; return out;}
+};
+
+}; // End fcgi
+}; // End aeb
+
+#endif
-#ifndef __FCGI_H__
-#define __FCGI_H__
+#ifndef __FCGI_HANDLER_H__
+#define __FCGI_HANDLER_H__
namespace aeb {
namespace fcgi {
* on top of which we will have the Request handler. :w
*
*/
-
-class handler : public event_handler<detail::socket_type,ip::tcp>
+template <typename Descriptor,typename InternetProtocol>
+class handler :
+ public aeb::net::event_handler<Descriptor
+ ,InternetProtocol >
{
private:
int m_ref;
+
+ const int BUFFER_SIZE = 4096;
public:
- typedef basic_socket_stream<ip::tcp> Stream;
+ typedef aeb::net::basic_socket_stream<InternetProtocol> Stream;
/// aeb::ssl::stream<ip::tcp> ? or detail::socket_type
- typedef basic_socket_stream<ip::tcp> SSLStream;
+ typedef aeb::net::basic_socket_stream<InternetProtocol> SSLStream;
- typedef aeb::intrusive_ptr<ws_handler> ptr;
+ typedef aeb::intrusive_ptr<handler> ptr;
+ typedef aeb::net::event_handler<Descriptor
+ ,InternetProtocol > Parent;
+ typedef aeb::net::io_dispatcher<Descriptor,InternetProtocol> io_service;
+ typedef aeb::fcgi::request<Descriptor,InternetProtocol> Request;
inline void add_ref() {m_ref++;};
inline void release() {
if (--m_ref == 0) delete this;
};
- bool available () const;
+ bool available () const;
public:
- handler(detail::socket_type s);
+ handler(aeb::net::detail::socket_type s) : Parent(s) ,m_socket(s)
+ {
+ std::cout<<"handler::handler ok create fcgi handler with socket ="<<s<<std::endl;
+ io_service *io = aeb::singleton<io_service>::get_instance();
+
+ io->register_handler(0,this);
+ };
- virtual ~handler() ;
+ virtual ~handler()
+ {
+ std::cout<<"handler::~handler"<<std::endl;
+ io_service *io = aeb::singleton<io_service>::get_instance();
+ io->unregister_handler(0,this);
+ m_socket.close();
+ }
+ ;
- virtual void onClose(unsigned short _code) ;
+ virtual void onClose(unsigned short _code)
+ { std::cout<<"handler::onClose "<<_code<<std::endl; } ;
- void on_write() ;
+ void on_write()
+ { std::cout<<"handler::on_write "<<std::endl; } ;
- void on_read() ;
-
- void on_accept();
+ void on_read()
+ {
+ aeb::fcgi::Header _header;
+ int res=m_socket.receive( reinterpret_cast<char *>(&_header)
+ , sizeof(aeb::fcgi::Header));
+ if ( res== 0)
+ {
+ io_service *io = aeb::singleton<io_service>::get_instance();
+ io->unregister_handler(0,this);
+ release();
+ } else if (res == sizeof(aeb::fcgi::Header))
+ {
+ process_header(_header,_header.m_Length) ;
+ } else {
+ std::cout<<"on_read ("<<res<<") not a Header"<<std::endl;
+ }
+ }
+ ;
+ // Not sure this is called
+ void on_accept()
+ { std::cout<<"handler::on_accept "<<std::endl; } ;
void io_register();
void io_unregister();
// reuse handler with a new socket
void reuse(aeb::net::detail::socket_type s);
-
+ private:
+ //
+ void process_header(aeb::fcgi::Header &_h,uint16_t length)
+ {
+ char s[BUFFER_SIZE];
+ memset(s,0x00,BUFFER_SIZE);
+ std::cout<<"p_header Type:"<<(int)_h.m_Type<<" Id:"<<_h.m_Id<<" length :"<<length<<std::endl;
+ switch (_h.m_Type)
+ {
+ case aeb::fcgi::RecordType::BEGIN_REQ :
+ {
+ aeb::fcgi::BeginRequest _req;
+ int res=m_socket.receive( reinterpret_cast<char *>(&_req)
+ , length>sizeof(_req)?sizeof(_req):length);
+ std::cout<<"process_header begin("<<res<<") Role: "<<_req.m_Role<<std::endl;
+ }
+ break;
+ case aeb::fcgi::RecordType::ABORT_REQ :
+ break;
+ case aeb::fcgi::RecordType::END_REQ :
+ break;
+ case aeb::fcgi::RecordType::PARAMS :
+ {
+ Request _req(_h);
+ if (length >0)
+ _req.process_parameters(m_socket,length);
+ int res=m_socket.receive(s,_h.m_PaddingLength);
+ }
+ break;
+ case aeb::fcgi::RecordType::IN :
+ {
+ int res=m_socket.receive(s,length>BUFFER_SIZE?BUFFER_SIZE:length);
+ std::cout<<"process_header IN ("<<res<<"):"<<s<<std::endl;
+ }
+ break;
+ case aeb::fcgi::RecordType::OUT :
+ break;
+ case aeb::fcgi::RecordType::ERR :
+ {
+ int res=m_socket.receive(s,length>BUFFER_SIZE?BUFFER_SIZE:length);
+ std::cout<<"process_header ERR ("<<res<<"):"<<s<<std::endl;
+ }
+ break;
+ case aeb::fcgi::RecordType::DATA :
+ {
+ int res=m_socket.receive(s,length>BUFFER_SIZE?BUFFER_SIZE:length);
+ std::cout<<"process_header data("<<res<<"):"<<s<<std::endl;
+ }
+ break;
+ case aeb::fcgi::RecordType::GET_VALUES :
+ break;
+ case aeb::fcgi::RecordType::GET_RESULT :
+ break;
+ default:
+ {
+ int res=m_socket.receive(s,length>BUFFER_SIZE?BUFFER_SIZE:length);
+ std::cout<<"process_header Unkown ("<<res<<","<<(int)_h.m_Type<<"):"<<s<<std::endl;
+ }
+ break;
+
+ };
+ }
protected:
- handler(const ws_handler &p) ;
+ handler(const handler &p) ;
// Should own an endpoint
- long m_max_frame_size;
+ long m_max_frame_size;
+ Stream m_socket;
};
/**
*/
-#endif /*WS_HANDLER_H*/
}
}
+#endif /*WS_HANDLER_H*/
+
--- /dev/null
+#ifndef __FCGI_REQUEST_H__
+#define __FCGI_REQUEST_H__
+
+namespace aeb {
+namespace fcgi {
+
+ //! Fastcgi Id
+ typedef uint16_t Id;
+
+ enum class RecordType : uint8_t
+ {
+ BEGIN_REQ = 1
+ ,ABORT_REQ = 2
+ ,END_REQ = 3
+ ,PARAMS = 4
+ ,IN = 5
+ ,OUT = 6
+ ,ERR = 7
+ ,DATA = 8
+ ,GET_VALUES = 9
+ ,GET_RESULT = 10
+ ,UNKNOWN = 11
+ };
+
+ enum class Role : uint16_t
+ {
+ RESPONDER = 1
+ ,AUTORIZER = 2
+ ,FILTER = 3
+ };
+
+ enum class RequestStatus : uint8_t
+ {
+ REQUEST_COMPLETE = 0
+ ,CANT_MPX_CONN = 1
+ ,OVERLOADED = 2
+ ,UNKNOWN_ROLE = 3
+ };
+
+#pragma pack(push,1)
+
+ struct Header
+ {
+ //! Factgi version
+ uint8_t m_Version;
+ //! Record type
+ RecordType m_Type;
+ //! Request Id
+ bigEndian<uint16_t> m_Id;
+ //! Request length
+ bigEndian<uint16_t> m_Length;
+ //! Padding length
+ uint8_t m_PaddingLength;
+ //! Reserved
+ uint8_t m_Reserved;
+ };
+
+ //
+ //Helper bodies
+ //
+
+ /**
+ *
+ */
+ struct BeginRequest
+ {
+ //!
+ //int m_KeepConn; // Should be always 1
+ //! Role
+ bigEndian<uint16_t> m_Role;
+ //! Flags
+ uint8_t m_Flags;
+ //! reserved
+ uint8_t m_Reserved[5];
+ };
+
+ /**
+ *
+ */
+ struct UnknownType
+ {
+ RecordType m_Type;
+ uint8_t m_Reserved[7];
+ };
+ /**
+ * Named Value Pairs
+ */
+ struct NameValuePairHeader11
+ {
+ uint8_t nameLength;
+ uint8_t valueLength;
+ };
+
+ struct NameValuePairHeader14
+ {
+ uint8_t nameLength;
+ bigEndian<uint32_t> valueLength;
+ };
+
+ struct NameValuePairHeader41
+ {
+ bigEndian<uint32_t> nameLength;
+ uint8_t valueLength;
+ };
+
+ struct NameValuePairHeader44
+ {
+ bigEndian<uint32_t> nameLength;
+ bigEndian<uint32_t> valueLength;
+ };
+#pragma pack(pop)
+ /**
+ *
+ */
+ struct EndRequet
+ {
+ //! Return application request status
+ int32_t m_ApplicationStatus;
+ //! Return Fastcgi protocol status
+ RequestStatus m_ProtocolStatus;
+ //! Reserverd
+ uint8_t m_Reserved[3];
+ };
+
+ /**
+ * @brief
+ */
+ template <typename Descriptor,typename InternetProtocol>
+ class request
+ {
+ private:
+ enum class State : uint32_t {
+ ST_Init
+ , ST_Params
+ , ST_StdIn
+ , ST_StdOut
+ , ST_Error
+ } ;
+ private:
+ /// Reference counter...
+ int m_ref;
+ ///
+ State m_State;
+ public:
+ ///
+ typedef aeb::net::basic_socket_stream<InternetProtocol> Stream;
+ ///
+ typedef aeb::intrusive_ptr<request> ptr;
+
+ request(aeb::fcgi::Header &_h) : m_State(State::ST_Init) , m_Id(_h.m_Id)
+ {
+ }
+ /**
+ * @brief read all parameters
+ */
+ void process_parameters(Stream &_s,uint16_t _length)
+ {
+ char _Buffer[4096];
+ int res = 0;
+ uint16_t _totalRead = 0;
+ NameValuePairHeader11 *_h11 = reinterpret_cast<NameValuePairHeader11 *>(_Buffer);
+ NameValuePairHeader14 *_h14 = reinterpret_cast<NameValuePairHeader14 *>(_Buffer);
+ do {
+ res = _s.receive(_Buffer,2);
+ _totalRead+=res;
+ if ( (_h11->nameLength < 127) && (_h11->valueLength < 127))
+ {
+ res = _s.receive(_Buffer+2,_h11->nameLength + _h11->valueLength);
+ _totalRead+=res;
+ std::string name(_Buffer+2,_h11->nameLength);
+ std::string value(_Buffer+2+_h11->nameLength,_h11->valueLength);
+ std::cout<<"Got Parameter ("<<(int)_h11->nameLength<<","<<(int)_h11->valueLength<<")"<<name<<" "<<value<<std::endl;
+ } else
+ if ( (_h11->nameLength > 127) && (_h11->valueLength < 127))
+ {
+ std::cout<<"not yet 1"<<std::endl;
+ } else
+ if ( (_h11->nameLength < 127) && (_h11->valueLength > 127))
+ {
+ std::cout<<"not yet enter nameLength="<<(int)_h14->nameLength<<" vl="<<(int)_h11->valueLength<<std::endl;
+ res = _s.receive(_Buffer+2,3);
+ _totalRead+=res;
+ // Read name and value
+ res = _s.receive(_Buffer+5,_h11->nameLength + _h14->valueLength & 0x7FFFFFFF);
+ _totalRead+=res;
+ std::string name(_Buffer+5,_h11->nameLength);
+ std::string value(_Buffer+5+_h11->nameLength,_h14->valueLength & 0x7FFFFFFF);
+ std::cout<<"Got Parameter "<<name<<" "<<value<<std::endl;
+ }
+ } while ( _totalRead != _length);
+ //res = _s.receive(_Buffer,2);
+ //std::cout<<"Final Read "<<res<<std::endl;
+ }
+ private:
+ uint16_t m_Id;
+ };
+
+}; // end fcgi
+}; // end aeb
+#endif
LOG_AEB_DEBUG_FMT("~basic_socket_acceptor::listen socket %d max_s=%d",this->m_descriptor,max_s);\r
return result;\r
}\r
+ protected:\r
+ inline socket_type &get_socket() {return m_socket;} \r
protected:\r
endpoint_type m_endpoint;\r
socket_type m_socket; \r
#endif
#include <aeb/fcgi/fcgi.h>
+#include <aeb/fcgi/fcgi_request.h>
#include <aeb/fcgi/fcgi_handler.h>
using namespace aeb::net;
+
typedef aeb::net::io_dispatcher<aeb::net::detail::socket_type,ip::tcp> io_service;
typedef aeb::net::basic_socket<ip::tcp> tcp_socket;
+typedef aeb::fcgi::handler<aeb::net::detail::socket_type,ip::tcp > fcgi_handler;
/**
* @brief main entry point. A simple example to use
* the fcgi implementation. Will use this test
ip::basic_endpoint<ip::tcp> ep(ip::tcp::v4(),10224);
- aeb::fcgi::acceptor a(ep);
+ aeb::fcgi::acceptor<aeb::net::detail::socket_type
+ ,ip::tcp
+ ,fcgi_handler > a(ep);
a.listen();
-: io_service *io = aeb::singleton<io_service>::get_instance();
+ io_service *io = aeb::singleton<io_service>::get_instance();
io->register_handler(2,&a);