Usermode/libc - Fix strchr and strrchr behavior
[tpg/acess2.git] / Usermode / Libraries / libaxwin4.so_src / ipc.cpp
1 /*
2  * AxWin4 Interface Library
3  * - By John Hodge (thePowersGang)
4  *
5  * ipc.c
6  * - IPC Abstraction
7  */
8 #include <axwin4/axwin.h>
9 #include "include/common.hpp"
10 #include "include/IIPCChannel.hpp"
11 #include "include/CIPCChannel_AcessIPCPipe.hpp"
12 #include <ipc_proto.hpp>
13 #include <algorithm>
14 #include <mutex>
15 #include <stdexcept>
16
17 #include <cstring>
18 #include <cstdio>
19
20 namespace AxWin {
21
22 IIPCChannel*    gIPCChannel;
23 ::std::mutex    glSyncReply;
24 bool    gSyncReplyActive;
25 bool    gSyncReplyValid;
26 CDeserialiser   gSyncReplyBuf;
27
28 extern "C" bool AxWin4_Connect(const char *URI)
29 {
30         _SysDebug("AxWin4_Connect('%s')", URI);
31         if( gIPCChannel ) {
32                 return false;
33         }
34         try {
35                 if( strncmp(URI, "ipcpipe://", 3+4+3) == 0 )
36                 {
37                         gIPCChannel = new CIPCChannel_AcessIPCPipe(URI+3+4+3);
38                 }
39                 else
40                 {
41                         _SysDebug("Unknown protocol");
42                         return false;
43                 }
44         }
45         catch( const ::std::exception& e )
46         {
47                 fprintf(stderr, "AxWin4_Connect: %s\n", e.what());
48                 return false;
49         }
50         return true;
51 }
52
53 extern "C" bool AxWin4_PeekEventQueue(void)
54 {
55         return false;
56 }
57
58 extern "C" bool AxWin4_WaitEventQueue(uint64_t Timeout)
59 {
60         return AxWin4_WaitEventQueueSelect(0, NULL, NULL, NULL, Timeout);
61 }
62
63 extern "C" bool AxWin4_WaitEventQueueSelect(int nFDs, fd_set *rfds, fd_set *wfds, fd_set *efds, uint64_t Timeout)
64 {
65         fd_set  local_rfds;
66         if( !rfds ) {
67                 FD_ZERO(&local_rfds);
68                 rfds = &local_rfds;
69         }
70         
71         int64_t select_timeout = Timeout;
72         int64_t *select_timeout_p = (Timeout ? &select_timeout : 0);
73         
74         nFDs = ::std::max(nFDs, gIPCChannel->FillSelect(*rfds));
75         _SysSelect(nFDs, rfds, wfds, efds, select_timeout_p, 0);
76         return gIPCChannel->HandleSelect(*rfds);
77 }
78
79 void SendMessage(CSerialiser& message)
80 {
81         gIPCChannel->Send(message);
82 }
83 void RecvMessage(CDeserialiser& message)
84 {
85         uint8_t id = message.ReadU8();
86         _SysDebug("RecvMessage: id=%i", id);
87         switch(id)
88         {
89         case IPCMSG_PING:
90                 // If we hear ping, we must pong
91                 {
92                 CSerialiser     pong;
93                 pong.WriteU8(IPCMSG_REPLY);
94                 pong.WriteU8(IPCMSG_PING);
95                 SendMessage(pong);
96                 }
97                 break;
98         case IPCMSG_REPLY:
99                 // Flag reply and take a copy of this message
100                 if( !gSyncReplyActive )
101                 {
102                         _SysDebug("Unexpected reply message %i", message.ReadU8());
103                 }
104                 else if( gSyncReplyValid )
105                 {
106                         // Oh... that was unexpected
107                         _SysDebug("Unexpected second reply message %i", message.ReadU8());
108                 }
109                 else
110                 {
111                         gSyncReplyValid = true;
112                         gSyncReplyBuf = message;
113                 }
114                 break;
115         // TODO: Handle messages from server (input events, IPC)
116         // TODO: If an event is currently being processed, save the message in a queue to be handled when processing is complete
117         // - This will prevent deep recursion (and make server errors aparent)
118         case IPCMSG_INPUTEVENT:
119                 _SysDebug("TODO: Input events");
120                 break;
121         default:
122                 _SysDebug("TODO: RecvMessage(%i)", id);
123                 break;
124         }
125 }
126
127 CDeserialiser GetSyncReply(CSerialiser& request, unsigned int Message)
128 {
129         ::std::lock_guard<std::mutex>   lock(glSyncReply);
130         gSyncReplyActive = true;
131         gSyncReplyValid = false;
132         // Send once lock is acquired
133         SendMessage(request);
134         
135         while( !gSyncReplyValid )
136         {
137                 // Tick along
138                 if( !AxWin4_WaitEventQueue(0) )
139                         throw ::std::runtime_error("Connection dropped while waiting for reply");
140         }
141         gSyncReplyActive = false;
142         
143         uint8_t id = gSyncReplyBuf.ReadU8();
144         if( id != Message )
145         {
146                 _SysDebug("Unexpected reply message id=%i, expected %i",
147                         id, Message);
148                 throw ::std::runtime_error("Sequencing error, unexpected reply");
149         }
150         
151         // Use move to avoid copying
152         return ::std::move(gSyncReplyBuf);
153 }
154
155 extern "C" void AxWin4_GetScreenDimensions(unsigned int ScreenIndex, unsigned int *Width, unsigned int *Height)
156 {
157         CSerialiser     req;
158         req.WriteU8(IPCMSG_GETGLOBAL);
159         req.WriteU16(IPC_GLOBATTR_SCREENDIMS);
160         req.WriteU8(ScreenIndex);
161         
162         CDeserialiser   response = GetSyncReply(req, IPCMSG_GETGLOBAL);
163         if( response.ReadU16() != IPC_GLOBATTR_SCREENDIMS ) {
164                 
165         }
166         
167         *Width = response.ReadU16();
168         *Height = response.ReadU16();
169         
170         _SysDebug("AxWin4_GetScreenDimensions: %i = %ix%i", ScreenIndex, *Width, *Height);
171 }
172
173 IIPCChannel::~IIPCChannel()
174 {
175 }
176
177 };      // namespace AxWin
178

UCC git Repository :: git.ucc.asn.au