From b6b933675d8501ee7258ece3768496f13571ee62 Mon Sep 17 00:00:00 2001 From: Ebersold Date: Fri, 22 Jul 2022 21:44:51 +0200 Subject: [PATCH] Good progress on FCGI. I'm able to reach the STDIN state. --- aeb/fcgi/fcgi.h | 21 ++-- aeb/fcgi/fcgi_endian.h | 55 +++++++++ aeb/fcgi/fcgi_handler.h | 142 ++++++++++++++++++++--- aeb/fcgi/fcgi_request.h | 200 ++++++++++++++++++++++++++++++++ aeb/net/basic_socket_acceptor.h | 2 + tests/fcgi_helloworld.cpp | 9 +- 6 files changed, 400 insertions(+), 29 deletions(-) create mode 100644 aeb/fcgi/fcgi_endian.h create mode 100644 aeb/fcgi/fcgi_request.h diff --git a/aeb/fcgi/fcgi.h b/aeb/fcgi/fcgi.h index 54adef6..f5a01aa 100644 --- a/aeb/fcgi/fcgi.h +++ b/aeb/fcgi/fcgi.h @@ -1,6 +1,11 @@ #ifndef __FCGI_H__ #define __FCGI_H__ +#include + +#include +#include + namespace aeb { namespace fcgi { @@ -9,22 +14,22 @@ namespace fcgi { * */ template -class acceptor : public basic_socket_acceptor +class acceptor : public aeb::net::basic_socket_acceptor { public: typedef Descriptor socket_type; - acceptor(const ip::basic_endpoint &e) : - basic_socket_acceptor(e) + acceptor(const aeb::net::ip::basic_endpoint &e) : + aeb::net::basic_socket_acceptor(e) { int val = 1; - m_socket.set_option(SO_REUSEADDR,val); + aeb::net::basic_socket_acceptor::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(this->m_descriptor,tmp.data(),&len,ec); @@ -32,12 +37,12 @@ class acceptor : public basic_socket_acceptor 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; }; diff --git a/aeb/fcgi/fcgi_endian.h b/aeb/fcgi/fcgi_endian.h new file mode 100644 index 0000000..6af0793 --- /dev/null +++ b/aeb/fcgi/fcgi_endian.h @@ -0,0 +1,55 @@ +#ifndef __FCGI_ENDIAN_H__ +#define __FCGI_ENDIAN_H__ + +namespace aeb { +namespace fcgi { + +template +class endianBase +{ + protected: + static T swap(const T &_val); +}; + +template <> +uint16_t endianBase::swap(const uint16_t &_val) +{ + return ( (_val & 0xFF00) >> 8) | ( (_val & 0x00FF) <<8 ); +} + +template <> +uint32_t endianBase::swap(const uint32_t &_val) +{ + return ( (_val & 0xFF000000) >> 24) + | ( (_val & 0x00FF0000) >> 8 ) + | ( (_val & 0x0000FF00) << 8) + | ( (_val & 0x000000FF) << 24 ); +} + +/** + * @brief + */ +template +class bigEndian : public endianBase +{ + protected: + T m_Data; + + protected: + static T doSwap(const T &_b) { return endianBase::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< +template +class handler : + public aeb::net::event_handler { private: int m_ref; + + const int BUFFER_SIZE = 4096; public: - typedef basic_socket_stream Stream; + typedef aeb::net::basic_socket_stream Stream; /// aeb::ssl::stream ? or detail::socket_type - typedef basic_socket_stream SSLStream; + typedef aeb::net::basic_socket_stream SSLStream; - typedef aeb::intrusive_ptr ptr; + typedef aeb::intrusive_ptr ptr; + typedef aeb::net::event_handler Parent; + typedef aeb::net::io_dispatcher io_service; + typedef aeb::fcgi::request 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 ="<::get_instance(); + + io->register_handler(0,this); + }; - virtual ~handler() ; + virtual ~handler() + { + std::cout<<"handler::~handler"<::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<(&_header) + , sizeof(aeb::fcgi::Header)); + if ( res== 0) + { + io_service *io = aeb::singleton::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 ("<(&_req) + , length>sizeof(_req)?sizeof(_req):length); + std::cout<<"process_header begin("<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 ("<BUFFER_SIZE?BUFFER_SIZE:length); + std::cout<<"process_header ERR ("<BUFFER_SIZE?BUFFER_SIZE:length); + std::cout<<"process_header data("<BUFFER_SIZE?BUFFER_SIZE:length); + std::cout<<"process_header Unkown ("< m_Id; + //! Request length + bigEndian 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 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 valueLength; + }; + + struct NameValuePairHeader41 + { + bigEndian nameLength; + uint8_t valueLength; + }; + + struct NameValuePairHeader44 + { + bigEndian nameLength; + bigEndian 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 + 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 Stream; + /// + typedef aeb::intrusive_ptr 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(_Buffer); + NameValuePairHeader14 *_h14 = reinterpret_cast(_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<<")"<nameLength > 127) && (_h11->valueLength < 127)) + { + std::cout<<"not yet 1"<nameLength < 127) && (_h11->valueLength > 127)) + { + std::cout<<"not yet enter nameLength="<<(int)_h14->nameLength<<" vl="<<(int)_h11->valueLength<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 "<m_descriptor,max_s); return result; } + protected: + inline socket_type &get_socket() {return m_socket;} protected: endpoint_type m_endpoint; socket_type m_socket; diff --git a/tests/fcgi_helloworld.cpp b/tests/fcgi_helloworld.cpp index 78b0d53..8be9d5d 100644 --- a/tests/fcgi_helloworld.cpp +++ b/tests/fcgi_helloworld.cpp @@ -17,12 +17,15 @@ #endif #include +#include #include using namespace aeb::net; + typedef aeb::net::io_dispatcher io_service; typedef aeb::net::basic_socket tcp_socket; +typedef aeb::fcgi::handler fcgi_handler; /** * @brief main entry point. A simple example to use * the fcgi implementation. Will use this test @@ -35,11 +38,13 @@ int main(int argc,char **argv) ip::basic_endpoint ep(ip::tcp::v4(),10224); - aeb::fcgi::acceptor a(ep); + aeb::fcgi::acceptor a(ep); a.listen(); -: io_service *io = aeb::singleton::get_instance(); + io_service *io = aeb::singleton::get_instance(); io->register_handler(2,&a); -- 2.30.2