From: John Hodge Date: Mon, 26 May 2014 09:41:30 +0000 (+0800) Subject: Usermode/AxWin4 - Server implementation runnable X-Git-Url: https://git.ucc.asn.au/?a=commitdiff_plain;h=8ae0b1147e613573a45fcd8e6f2f6af2aeff54ac;p=tpg%2Facess2.git Usermode/AxWin4 - Server implementation runnable --- diff --git a/Usermode/Applications/axwin4_src/Common/include/serialisation.hpp b/Usermode/Applications/axwin4_src/Common/include/serialisation.hpp index 32ba4659..d680043d 100644 --- a/Usermode/Applications/axwin4_src/Common/include/serialisation.hpp +++ b/Usermode/Applications/axwin4_src/Common/include/serialisation.hpp @@ -28,10 +28,11 @@ class CDeserialiser size_t m_offset; public: CDeserialiser(size_t Length, const uint8_t *Buffer); + bool IsConsumed() const; ::uint8_t ReadU8(); ::uint16_t ReadU16(); ::int16_t ReadS16(); - ::std::string ReadString(); + const ::std::string ReadString(); }; class CSerialiser @@ -42,6 +43,7 @@ public: void WriteU8(::uint8_t val); void WriteU16(::uint16_t val); void WriteS16(::int16_t val); + void WriteBuffer(size_t n, const void* val); void WriteString(const char* val, size_t n); void WriteString(const char* val) { WriteString(val, ::std::char_traits::length(val)); @@ -50,6 +52,8 @@ public: WriteString(val.data(), val.size()); } void WriteSub(const CSerialiser& val); + + const ::std::vector& Compact(); }; }; diff --git a/Usermode/Applications/axwin4_src/Common/serialisation.cpp b/Usermode/Applications/axwin4_src/Common/serialisation.cpp index 4388eab7..8dad5d33 100644 --- a/Usermode/Applications/axwin4_src/Common/serialisation.cpp +++ b/Usermode/Applications/axwin4_src/Common/serialisation.cpp @@ -7,6 +7,7 @@ */ #include #include +#include namespace AxWin { @@ -17,24 +18,52 @@ CDeserialiser::CDeserialiser(size_t Length, const uint8_t *Buffer): { } +bool CDeserialiser::IsConsumed() const +{ + return m_offset == m_length; +} + ::uint8_t CDeserialiser::ReadU8() { - return 0; + if( m_offset + 1 >= m_length ) + throw ::std::out_of_range("CDeserialiser::ReadU8"); + uint8_t rv = m_data[m_offset]; + m_offset ++; + return rv; } ::uint16_t CDeserialiser::ReadU16() { - return 0; + if( m_offset + 2 >= m_length ) + throw ::std::out_of_range("CDeserialiser::ReadU16"); + + uint16_t rv = m_data[m_offset] | ((uint16_t)m_data[m_offset+1] << 8); + m_offset += 2; + return rv; } ::int16_t CDeserialiser::ReadS16() { - return 0; + uint16_t rv_u = ReadU16(); + if( rv_u < 0x8000 ) + return rv_u; + else + return ~rv_u + 1; } -::std::string CDeserialiser::ReadString() +const ::std::string CDeserialiser::ReadString() { - return ""; + if( m_offset + 1 >= m_length ) + throw ::std::out_of_range("CDeserialiser::ReadString"); + uint8_t len = m_data[m_offset]; + m_offset ++; + + if( m_offset + len >= m_length ) + throw ::std::out_of_range("CDeserialiser::ReadString"); + + ::std::string ret( reinterpret_cast(m_data+m_offset), len ); + m_offset += len; + return ret; } CSerialiser::CSerialiser() @@ -65,21 +94,39 @@ void CSerialiser::WriteS16(::int16_t Value) } } +void CSerialiser::WriteBuffer(size_t n, const void* val) +{ + const uint8_t* val8 = static_cast(val); + if( n > 0xFFFF ) + throw ::std::length_error("CSerialiser::WriteBuffer"); + m_data.reserve( m_data.size() + 2 + n ); + WriteU16(n); + for( size_t i = 0; i < n; i ++ ) + m_data.push_back(val8[i]); +} + void CSerialiser::WriteString(const char* val, size_t n) { - //if( n >= 256 ) - // throw ::std::out_of_range("CSerialiser::WriteString"); + if( n > 0xFF ) + throw ::std::length_error("CSerialiser::WriteString"); + m_data.reserve( m_data.size() + 1 + n ); WriteU8(n); for( size_t i = 0; i < n; i ++ ) - WriteU8(val[i]); + m_data.push_back(val[i]); } void CSerialiser::WriteSub(const CSerialiser& val) { + // TODO: Append reference to sub-buffer contents m_data.reserve( m_data.size() + val.m_data.size() ); for( auto byte : val.m_data ) m_data.push_back( byte ); } +const ::std::vector& CSerialiser::Compact() +{ + return m_data; +} + }; // namespace AxWin diff --git a/Usermode/Applications/axwin4_src/Server/CClient.cpp b/Usermode/Applications/axwin4_src/Server/CClient.cpp index 6f1f2562..f61ca31a 100644 --- a/Usermode/Applications/axwin4_src/Server/CClient.cpp +++ b/Usermode/Applications/axwin4_src/Server/CClient.cpp @@ -6,15 +6,22 @@ * - IPC Client */ #include +#include +#include namespace AxWin { -CClient::CClient(IIPCChannel& channel): +CClient::CClient(::AxWin::IIPCChannel& channel): m_channel(channel) { } +CClient::~CClient() +{ + ::AxWin::IPC::DeregisterClient(*this); +} + CWindow* CClient::GetWindow(int ID) { if( ID == 0 ) @@ -31,8 +38,23 @@ void CClient::SetWindow(int ID, CWindow* window) m_windows[ID] = window; } -void CClient::SendMessage(CSerialiser& reply) +void CClient::HandleMessage(CDeserialiser& message) { + try { + IPC::HandleMessage(*this, message); + if( !message.IsConsumed() ) + { + _SysDebug("NOTICE - CClient::HandleMessage - Trailing data in message"); + } + } + catch( const ::std::exception& e ) + { + _SysDebug("ERROR - Exception while processing message from client: %s", e.what()); + } + catch( ... ) + { + _SysDebug("ERROR - Unknown exception while processing message from client"); + } } }; // namespace AxWin diff --git a/Usermode/Applications/axwin4_src/Server/CIPCChannel_AcessIPCPipe.cpp b/Usermode/Applications/axwin4_src/Server/CIPCChannel_AcessIPCPipe.cpp index 16863496..183253b8 100644 --- a/Usermode/Applications/axwin4_src/Server/CIPCChannel_AcessIPCPipe.cpp +++ b/Usermode/Applications/axwin4_src/Server/CIPCChannel_AcessIPCPipe.cpp @@ -5,25 +5,111 @@ * CIPCChannel_AcessIPCPipe.cpp * - IPC Channel :: Acess' IPC Pipe /Devices/ipcpipe/ */ +#include #include +#include +#include +#include +#include namespace AxWin { CIPCChannel_AcessIPCPipe::CIPCChannel_AcessIPCPipe(const ::std::string& suffix) { - + ::std::string path = "/Devices/ipcpipe/" + suffix; + m_fd = _SysOpen(path.c_str(), OPENFLAG_CREATE); + if(m_fd == -1) { + _SysDebug("Failed to open %s: %s", path.c_str(), strerror(errno)); + throw ::std::system_error(errno, ::std::system_category()); + } } CIPCChannel_AcessIPCPipe::~CIPCChannel_AcessIPCPipe() { + _SysClose(m_fd); } int CIPCChannel_AcessIPCPipe::FillSelect(fd_set& rfds) { - return 0; + _SysDebug("CIPCChannel_AcessIPCPipe::FillSelect"); + int maxfd = m_fd; + FD_SET(m_fd, &rfds); + + for( auto& clientref : m_clients ) + { + _SysDebug("CIPCChannel_AcessIPCPipe::FillSelect - FD%i", clientref.m_fd); + maxfd = ::std::max(maxfd, clientref.m_fd); + FD_SET(clientref.m_fd, &rfds); + } + + return maxfd+1; } void CIPCChannel_AcessIPCPipe::HandleSelect(const fd_set& rfds) { + _SysDebug("CIPCChannel_AcessIPCPipe::HandleSelect"); + if( FD_ISSET(m_fd, &rfds) ) + { + _SysDebug("CIPCChannel_AcessIPCPipe::HandleSelect - New client on FD %i", m_fd); + int newfd = _SysOpenChild(m_fd, "newclient", OPENFLAG_READ|OPENFLAG_WRITE); + _SysDebug("newfd = %i", newfd); + + // emplace creates a new object within the list + m_clients.emplace( m_clients.end(), *this, newfd ); + IPC::RegisterClient( m_clients.back() ); + } + + for( auto it = m_clients.begin(); it != m_clients.end(); ) + { + CClient_AcessIPCPipe& clientref = *it; + _SysDebug("CIPCChannel_AcessIPCPipe::HandleSelect - Trying FD%i", clientref.m_fd); + ++ it; + + if( FD_ISSET(clientref.m_fd, &rfds) ) + { + try { + clientref.HandleReceive(); + } + catch( const ::std::exception& e ) { + _SysDebug("ERROR - Exception processing IPCPipe FD%i: %s", + clientref.m_fd, e.what() + ); + it = m_clients.erase(--it); + } + } + } + _SysDebug("CIPCChannel_AcessIPCPipe::HandleSelect - END"); +} + + +CClient_AcessIPCPipe::CClient_AcessIPCPipe(::AxWin::IIPCChannel& channel, int fd): + CClient(channel), + m_fd(fd), + m_rxbuf(0x1000) +{ +} + +CClient_AcessIPCPipe::~CClient_AcessIPCPipe() +{ + _SysClose(m_fd); + _SysDebug("Closed client FD%i", m_fd); +} + +void CClient_AcessIPCPipe::SendMessage(CSerialiser& message) +{ + const ::std::vector& data = message.Compact(); + + _SysDebug("CClient_AcessIPCPipe::SendMessage - %i bytes to %i", data.size(), m_fd); + _SysWrite(m_fd, data.data(), data.size()); +} + +void CClient_AcessIPCPipe::HandleReceive() +{ + size_t len = _SysRead(m_fd, &m_rxbuf[0], m_rxbuf.capacity()); + if( len == (size_t)-1 ) + throw ::std::system_error(errno, ::std::system_category()); + + CDeserialiser message(len, &m_rxbuf[0]); + CClient::HandleMessage(message); } }; diff --git a/Usermode/Applications/axwin4_src/Server/Makefile b/Usermode/Applications/axwin4_src/Server/Makefile index 6f88f14d..18b7d370 100644 --- a/Usermode/Applications/axwin4_src/Server/Makefile +++ b/Usermode/Applications/axwin4_src/Server/Makefile @@ -1,6 +1,8 @@ include ../../Makefile.cfg +DIR := Apps/AxWin/4.0 + CPPFLAGS += -Iinclude/ -I../Common/include/ OBJ := main.o ipc.o CConfig.o video.o input.o timing.o OBJ += compositor.o CWindow.o diff --git a/Usermode/Applications/axwin4_src/Server/include/CClient.hpp b/Usermode/Applications/axwin4_src/Server/include/CClient.hpp index 44961da7..6e8a09b1 100644 --- a/Usermode/Applications/axwin4_src/Server/include/CClient.hpp +++ b/Usermode/Applications/axwin4_src/Server/include/CClient.hpp @@ -11,10 +11,10 @@ #include "CWindow.hpp" #include "serialisation.hpp" -class IIPCChannel; - namespace AxWin { +class IIPCChannel; + class CClient { IIPCChannel& m_channel; @@ -22,13 +22,14 @@ class CClient //::std::map m_windows; CWindow* m_windows[1]; public: - CClient(IIPCChannel& channel); - ~CClient(); + CClient(::AxWin::IIPCChannel& channel); + virtual ~CClient(); CWindow* GetWindow(int ID); void SetWindow(int ID, CWindow* window); - void SendMessage(CSerialiser& reply); + virtual void SendMessage(CSerialiser& reply) = 0; + void HandleMessage(CDeserialiser& message); }; diff --git a/Usermode/Applications/axwin4_src/Server/include/CIPCChannel_AcessIPCPipe.hpp b/Usermode/Applications/axwin4_src/Server/include/CIPCChannel_AcessIPCPipe.hpp index 1e24b0e7..4a717d43 100644 --- a/Usermode/Applications/axwin4_src/Server/include/CIPCChannel_AcessIPCPipe.hpp +++ b/Usermode/Applications/axwin4_src/Server/include/CIPCChannel_AcessIPCPipe.hpp @@ -9,20 +9,31 @@ #define _CIPCCHANNEL_ACESSIPCPIPE_HPP_ #include +#include #include #include namespace AxWin { -class CClient_AcessIPCPipe +class CClient_AcessIPCPipe: + public CClient { + friend class CIPCChannel_AcessIPCPipe; + int m_fd; + ::std::vector m_rxbuf; public: + CClient_AcessIPCPipe(IIPCChannel& channel, int fd); + ~CClient_AcessIPCPipe(); + + void SendMessage(CSerialiser& message); + + void HandleReceive(); }; class CIPCChannel_AcessIPCPipe: public IIPCChannel { - int m_mainFD; + int m_fd; ::std::list m_clients; public: CIPCChannel_AcessIPCPipe(const ::std::string& suffix); diff --git a/Usermode/Applications/axwin4_src/Server/include/ipc.hpp b/Usermode/Applications/axwin4_src/Server/include/ipc.hpp index d801953f..cb06f67e 100644 --- a/Usermode/Applications/axwin4_src/Server/include/ipc.hpp +++ b/Usermode/Applications/axwin4_src/Server/include/ipc.hpp @@ -14,16 +14,22 @@ extern "C" { #include }; +#include #include namespace AxWin { + class CCompositor; +class CClient; namespace IPC { extern void Initialise(const CConfigIPC& config, CCompositor& compositor); extern int FillSelect(::fd_set& rfds); -extern void HandleSelect(::fd_set& rfds); +extern void HandleSelect(const ::fd_set& rfds); +extern void RegisterClient(CClient& client); +extern void DeregisterClient(CClient& client); +extern void HandleMessage(CClient& client, CDeserialiser& message); class CClientFailure: public ::std::exception diff --git a/Usermode/Applications/axwin4_src/Server/input.cpp b/Usermode/Applications/axwin4_src/Server/input.cpp index 7519b877..c120ed45 100644 --- a/Usermode/Applications/axwin4_src/Server/input.cpp +++ b/Usermode/Applications/axwin4_src/Server/input.cpp @@ -23,7 +23,8 @@ CInput::CInput(const ::AxWin::CConfigInput& config, CCompositor& compositor): int CInput::FillSelect(::fd_set& rfds) { FD_SET(m_keyboardFD, &rfds); - FD_SET(m_mouseFD, &rfds); + if( m_mouseFD != -1 ) + FD_SET(m_mouseFD, &rfds); return ::std::max(m_keyboardFD, m_mouseFD)+1; } @@ -31,10 +32,38 @@ void CInput::HandleSelect(::fd_set& rfds) { if( FD_ISSET(m_keyboardFD, &rfds) ) { - // TODO: Read keystroke and handle + uint32_t codepoint; + static uint32_t scancode; + #define KEY_CODEPOINT_MASK 0x3FFFFFFF + + size_t readlen = _SysRead(m_keyboardFD, &codepoint, sizeof(codepoint)); + if( readlen != sizeof(codepoint) ) + { + // oops, error + _SysDebug("Terminal read failed? (%i != %i)", readlen, sizeof(codepoint)); + } + +// _SysDebug("Keypress 0x%x", codepoint); + + switch(codepoint & 0xC0000000) + { + case 0x00000000: // Key pressed + //WM_Input_KeyDown(codepoint & KEY_CODEPOINT_MASK, scancode); + case 0x80000000: // Key release + //WM_Input_KeyFire(codepoint & KEY_CODEPOINT_MASK, scancode); + scancode = 0; + break; + case 0x40000000: // Key refire + //WM_Input_KeyUp(codepoint & KEY_CODEPOINT_MASK, scancode); + scancode = 0; + break; + case 0xC0000000: // Raw scancode + scancode = codepoint & KEY_CODEPOINT_MASK; + break; + } } - if( FD_ISSET(m_mouseFD, &rfds) ) + if( m_mouseFD != -1 && FD_ISSET(m_mouseFD, &rfds) ) { // TODO: Read mouse event and handle } diff --git a/Usermode/Applications/axwin4_src/Server/ipc.cpp b/Usermode/Applications/axwin4_src/Server/ipc.cpp index f842578b..46ba551e 100644 --- a/Usermode/Applications/axwin4_src/Server/ipc.cpp +++ b/Usermode/Applications/axwin4_src/Server/ipc.cpp @@ -39,17 +39,21 @@ void Initialise(const CConfigIPC& config, CCompositor& compositor) int FillSelect(fd_set& rfds) { int ret = 0; + _SysDebug("IPC::FillSelect"); for( auto channel : glChannels ) { + _SysDebug("IPC::FillSelect - channel=%p", channel); ret = ::std::max(ret, channel->FillSelect(rfds)); } return ret; } -void HandleSelect(fd_set& rfds) +void HandleSelect(const fd_set& rfds) { + _SysDebug("IPC::HandleSelect"); for( auto channel : glChannels ) { + _SysDebug("IPC::HandleSelect - channel=%p", channel); channel->HandleSelect(rfds); } } diff --git a/Usermode/Applications/axwin4_src/Server/main.cpp b/Usermode/Applications/axwin4_src/Server/main.cpp index acea9275..0cd048f8 100644 --- a/Usermode/Applications/axwin4_src/Server/main.cpp +++ b/Usermode/Applications/axwin4_src/Server/main.cpp @@ -15,6 +15,9 @@ #include #include +#include +#include + extern "C" { #include #include @@ -32,32 +35,91 @@ int main(int argc, char *argv[]) } catch(const std::exception& e) { fprintf(stderr, "Exception: %s\n", e.what()); + _SysDebug("Config threw exception: %s", e.what()); + return 1; + } + + CVideo* vid = 0; + CCompositor* compositor = 0; + CInput* input = 0; + + try { + // - Open graphics + vid = new CVideo(config.m_video); + ::_SysDebug("vid = %p", vid); + // - Initialise compositor structures + compositor = new CCompositor(/*config.m_compositor,*/ *vid); + ::_SysDebug("compositor = %p", compositor); + // - Open input + input = new CInput(config.m_input, *compositor); + ::_SysDebug("input = %p", input); + // > Handles hotkeys? + // - Bind IPC channels + IPC::Initialise(config.m_ipc, *compositor); + ::_SysDebug("IPC up"); + // - Start root child process (from config) + // TODO: Spin up child process + + { + const char *interface_app = "/Acess/Apps/AxWin/4.0/AxWinUI"; + const char *argv[] = {interface_app, NULL}; + int rv = _SysSpawn(interface_app, argv, NULL, 0, NULL, NULL); + if( rv < 0 ) { + _SysDebug("_SysSpawn chucked a sad, rv=%i, errno=%i", rv, _errno); + throw ::std::system_error(errno, ::std::system_category()); + } + } + } + catch(const ::std::exception& e) { + fprintf(stderr, "Startup threw exception: %s\n", e.what()); + _SysDebug("Startup threw exception: %s", e.what()); + delete input; + delete compositor; + delete vid; return 1; } - // - Open graphics - CVideo* vid = new CVideo(config.m_video); - // - Initialise compositor structures - CCompositor* compositor = new CCompositor(/*config.m_compositor,*/ *vid); - // - Open input - CInput* input = new CInput(config.m_input, *compositor); - // > Handles hotkeys? - // - Bind IPC channels - IPC::Initialise(config.m_ipc, *compositor); - // - Start root child process (from config) - // TODO: Spin up child process // - Event loop for( ;; ) { int nfd = 0; - fd_set rfds; + fd_set rfds, efds; + FD_ZERO(&rfds); + FD_ZERO(&efds); + nfd = ::std::max(nfd, input->FillSelect(rfds)); nfd = ::std::max(nfd, IPC::FillSelect(rfds)); + for( int i = 0; i < nfd; i ++ ) + if( FD_ISSET(i, &rfds) ) + FD_SET(i, &efds); + + for( int i = 0; i < nfd; i ++ ) { + if( FD_ISSET(i, &rfds) ) { + _SysDebug("FD%i", i); + } + } + // TODO: Support _SysSendMessage IPC? int64_t timeout = Timing::GetTimeToNextEvent(); - int rv = ::_SysSelect(nfd, &rfds, NULL, &rfds, &timeout, 0); + int64_t *timeoutp; + if( timeout >= 0 ) { + ::_SysDebug("Calling select with timeout %lli", timeout); + timeoutp = &timeout; + } + else { + ::_SysDebug("Calling select with no timeout"); + timeoutp = 0; + } + int rv = ::_SysSelect(nfd, &rfds, NULL, NULL/*&efds*/, timeoutp, 0); + + for( int i = 0; i < nfd; i ++ ) { + if( FD_ISSET(i, &rfds) ) { + _SysDebug("FD%i", i); + } + } + _SysDebug("rv=%i, timeout=%lli", rv, timeout); Timing::CheckEvents(); diff --git a/Usermode/Applications/axwin4_src/Server/timing.cpp b/Usermode/Applications/axwin4_src/Server/timing.cpp index 18740098..e61c8e2c 100644 --- a/Usermode/Applications/axwin4_src/Server/timing.cpp +++ b/Usermode/Applications/axwin4_src/Server/timing.cpp @@ -12,7 +12,7 @@ namespace Timing { int64_t GetTimeToNextEvent() { - return 10*1000; + return -1; } void CheckEvents()