Implemented Serialization of Containers
[sdk] / ecere / src / net / dcom.ec
1 namespace net;
2
3 #if defined(__WIN32__)
4
5 #define WIN32_LEAN_AND_MEAN
6 #include <winsock.h>
7 static WSADATA wsaData;
8
9 #elif defined(__unix__) || defined(__APPLE__)
10
11 default:
12 #define uint _uint
13 #include <sys/time.h>
14 #include <unistd.h>
15
16 #include <netinet/in.h>
17 #include <netdb.h>
18 #include <sys/socket.h>
19 #include <sys/wait.h>
20 #include <sys/types.h>
21 #include <sys/time.h>
22 #include <arpa/inet.h>
23 #undef uint
24 private:
25
26 typedef int SOCKET;
27 typedef struct hostent HOSTENT;
28 typedef struct sockaddr SOCKADDR;
29 typedef struct sockaddr_in SOCKADDR_IN;
30 typedef struct in_addr IN_ADDR;
31 #define closesocket(s) close(s)
32
33 #endif
34
35 import "network"
36
37 // SERVER
38
39 static enum DCOMPacketType
40 {
41    dcom_CreateInstance        = 3,
42    dcom_CallMethod            = 5,
43    dcom_CallVirtualMethod     = 6,
44    dcom_InstanceCreated       = 9,
45    dcom_VirtualMethodReturned = 10,
46    dcom_MethodReturned        = 11
47 };
48
49 static class DCOMPacket : Packet
50 {
51    DCOMPacketType type;
52 };
53 static class CreateInstancePacket : DCOMPacket
54 {
55    //int classID;
56    char className[1];
57 };
58
59 static class ObjectCreatedPacket : DCOMPacket
60 {
61    unsigned int objectID;
62 };
63
64 static class CallMethodPacket : DCOMPacket
65 {
66    int objectID;
67    int methodID;
68    unsigned int argsSize;
69    byte args[1];
70 };
71
72 static class CallVirtualMethodPacket : DCOMPacket
73 {
74    int methodID;
75    unsigned int argsSize;
76    byte args[1];
77 };
78
79 static class MethodReturnedPacket : DCOMPacket
80 {
81    unsigned int argsSize;
82    byte args[1];
83 };
84
85 static class VirtualMethodReturnedPacket : DCOMPacket
86 {
87    unsigned int objectID;
88    bool overridden;
89    unsigned int argsSize;
90    byte args[1];
91 };
92
93 public class DCOMServerObject
94 {
95 public:
96    Instance instance;
97
98    virtual void CallMethod(unsigned int __ecereMethodID, SerialBuffer __ecereBuffer);
99
100    dllexport bool CallVirtualMethod(unsigned int methodID)
101    {
102       if(serverSocket && serverSocket.connected)
103       {
104          unsigned int size = (uint)&((CallVirtualMethodPacket)0).args + virtualsBuffer.size; // sizeof(class CallVirtualMethodPacket) + virtualsBuffer.size - 1;
105          CallVirtualMethodPacket packet = (CallVirtualMethodPacket)new0 byte[size];
106          packet.type = (DCOMPacketType)htoled((DCOMPacketType)dcom_CallVirtualMethod);
107          packet.size = size;
108          packet.methodID = htoled(methodID);
109          packet.argsSize = htoled(virtualsBuffer.size);
110          virtualsBuffer.ReadData(packet.args, virtualsBuffer.size);
111          answered = false;
112
113          serverSocket.SendPacket(packet);
114          delete packet;
115
116          while(serverSocket && !answered)
117          {
118             if(GetCurrentThreadID() == serverSocket.thread.id)
119                serverSocket.Process();
120             else
121                serverSocket.thread.semaphore.Wait();
122          }
123          return overridden == true;
124       }
125       return false;
126    }
127 // private:
128    DCOMServerSocket serverSocket;
129    unsigned int id;
130    SerialBuffer buffer { };
131    SerialBuffer virtualsBuffer { };
132    bool answered, overridden;
133 };
134
135 #define GETLEDWORD(b) (uint32)(((b)[3] << 24) | ((b)[2] << 16) | ((b)[1] << 8) | (b)[0])
136
137 #define PUTLEDWORD(b, d) \
138    (b)[3] = (byte)(((d) >> 24) & 0xFF); \
139    (b)[2] = (byte)(((d) >> 16) & 0xFF); \
140    (b)[1] = (byte)(((d) >> 8)  & 0xFF); \
141    (b)[0] = (byte)( (d)        & 0xFF);
142
143 static uint32 htoled(uint32 value)
144 {
145    uint32 result;
146    PUTLEDWORD((byte *)&result, value);
147    return result;
148 }
149
150 static uint32 letohd(uint32 value)
151 {
152    return GETLEDWORD((byte *)&value);   
153 }
154
155 class DCOMServerThread : Thread
156 {
157    Socket socket;
158    Semaphore semaphore { };
159    bool connected;
160    unsigned int Main()
161    {
162       incref socket;
163       while(connected)
164       {
165          socket.Process();
166          semaphore.Release();
167       }
168       delete socket;
169       return 0;
170    }
171 };
172
173 class DCOMClientThread : Thread
174 {
175    Socket socket;
176    Semaphore semaphore { };
177    bool connected;
178    unsigned int Main()
179    {
180       incref socket;
181       while(connected)
182       {
183          socket.Process();
184          semaphore.Release();
185       }
186       delete socket;
187       return 0;
188    }
189 };
190
191 /*static */public class DCOMServerSocket : Socket
192 {
193    int numObjects;
194    DCOMServerObject * objects;
195    processAlone = true;
196    DCOMServerThread thread
197    {
198       socket = this, connected = true;
199    };
200
201    void OnReceivePacket(DCOMPacket packet)
202    {
203       switch((DCOMPacketType)letohd(packet.type))
204       {
205          case dcom_CreateInstance:
206          {
207             CreateInstancePacket createInstance = (CreateInstancePacket)packet;
208             Class _class = eSystem_FindClass(__thisModule.application, createInstance.className);
209             Class runClass = eSystem_FindClass(__thisModule.application, createInstance.className + 4);
210             DCOMServerObject object;
211             int vid;
212             
213             if(!_class)
214                _class = eSystem_FindClass(runClass.module, createInstance.className);
215             
216             objects = renew objects DCOMServerObject[numObjects+1];
217             object = objects[numObjects] = eInstance_New(_class);
218             object.serverSocket = this;
219             object.id = numObjects++;
220             object.instance = eInstance_New(runClass);   
221             object.instance._vTbl = new void *[object.instance._class.vTblSize + 1];
222             object.instance._vTbl++;
223             object.instance._vTbl[-1] = (void *)object;
224             memcpy(object.instance._vTbl, object.instance._class._vTbl, sizeof(int(*)()) * object.instance._class.vTblSize);               
225             for(vid = runClass.base.vTblSize; vid < runClass.vTblSize; vid++)
226             {
227                object.instance._vTbl[vid] = object._vTbl[vid - runClass.base.vTblSize + 11];
228             }
229
230             {
231                ObjectCreatedPacket sendPacket = ObjectCreatedPacket { };
232                sendPacket.type = (DCOMPacketType)htoled((DCOMPacketType)dcom_InstanceCreated);
233                sendPacket.size = sizeof(class ObjectCreatedPacket);
234                sendPacket.objectID = htoled(object.id);
235                SendPacket(sendPacket);
236                delete sendPacket;
237             }
238             break;
239          }
240          case dcom_CallMethod:
241          {
242             CallMethodPacket callMethod = (CallMethodPacket)packet;
243             callMethod.objectID = letohd(callMethod.objectID);
244             callMethod.argsSize = letohd(callMethod.argsSize);
245             if(callMethod.objectID < numObjects /*&& callMethod.methodID < numMethods*/)
246             {
247                DCOMServerObject object = objects[callMethod.objectID];
248
249                MethodReturnedPacket packet;
250                unsigned int size;
251                SerialBuffer buffer = object.buffer;
252
253                buffer.WriteData(callMethod.args, callMethod.argsSize);
254                // TOFIX: Hardcoded VTBL ID
255                object._vTbl[10](object, callMethod.methodID, buffer);
256
257                size = (uint)&((MethodReturnedPacket)0).args + buffer.size; // sizeof(class MethodReturnedPacket) + buffer.size - 1;
258                packet = (MethodReturnedPacket)new0 byte[size];
259                packet.type = (DCOMPacketType)htoled((DCOMPacketType)dcom_MethodReturned);
260                packet.size = size;
261                packet.argsSize = htoled(buffer.size);
262                buffer.ReadData(packet.args, buffer.size);
263                buffer.Free();
264                SendPacket(packet);
265                delete packet;
266             }
267             break;
268          }
269          case dcom_VirtualMethodReturned:
270          {
271             VirtualMethodReturnedPacket methodReturned = (VirtualMethodReturnedPacket)packet;
272             if(methodReturned.objectID < numObjects)
273             {
274                DCOMServerObject object = objects[methodReturned.objectID];
275                object.virtualsBuffer.WriteData(methodReturned.args, letohd(methodReturned.argsSize));
276                object.answered = true;
277                object.overridden = methodReturned.overridden;
278             }
279             break;
280          }
281       }
282    }
283
284    void OnDisconnect(int code)
285    {
286       int c;
287       thread.connected = false;
288       for(c = 0; c<numObjects; c++)
289       {
290          objects[c].instance._vTbl--;
291          delete objects[c].instance._vTbl;
292          delete objects[c].instance;
293          delete objects[c];         
294       }
295       delete objects;
296    }
297
298    ~DCOMServerSocket()
299    {
300       if(thread.started && GetCurrentThreadID() != thread.id)
301          thread.Wait();
302    }
303 };
304
305 class DCOMServiceThread : Thread
306 {
307    DCOMService service;
308    bool connected;
309    unsigned int Main()
310    {
311       DCOMService service = this.service;
312       incref service;
313       while(connected)
314       {
315          service.Process();
316       }
317       delete service;
318       return 0;
319    }
320 };
321
322 public class DCOMService : Service
323 {
324    port = 3114;
325    processAlone = true;
326    DCOMServiceThread thread
327    {
328       service = this, connected = true;
329    };
330    ~DCOMService()
331    {
332       if(thread.started && GetCurrentThreadID() != thread.id)
333          thread.Wait();
334    }
335
336    public bool Start()
337    {
338       bool result = Service::Start();
339       if(result)
340       {
341          thread.connected = true;
342          thread.Create();
343       }
344       return result;
345    }
346
347    public bool Stop()
348    {
349       bool result;
350       DCOMServerSocket socket;
351       thread.connected = false;
352       result = Service::Stop();
353       if(thread.started && GetCurrentThreadID() != thread.id)
354          thread.Wait();
355    }
356
357    void OnAccept()
358    {
359       DCOMServerSocket socket { };
360       incref socket;
361       socket.service = this;
362       if(socket.connected)
363          socket.thread.Create();
364       delete socket;
365    }
366 };
367
368 // CLIENT
369 public class DCOMClientObject : Socket
370 {
371 public:
372    unsigned int objectID;
373    bool answered;
374    SerialBuffer __ecereBuffer { };
375    SerialBuffer virtualsBuffer { };
376    processAlone = true;
377    private DCOMClientThread thread
378    {
379       socket = this, connected = true;
380    };
381
382    bool Connect(char * server, int port)
383    {
384       bool result = false;
385       if(Socket::Connect(server, port))
386       {
387          int len = strlen(_class.name) + 4 - strlen("DCOMClient_");
388          unsigned int size = sizeof(class CreateInstancePacket) + len;
389          CreateInstancePacket packet = (CreateInstancePacket)new0 byte[size];
390          packet.type = (DCOMPacketType)htoled((DCOMPacketType)dcom_CreateInstance);
391          packet.size = size;
392          CopyBytes(packet.className, "DCOM", 4);
393          CopyBytes(packet.className + 4, _class.name + strlen("DCOMClient_"), len-4+1);     
394          answered = false;
395          SendPacket(packet);
396          delete packet;
397          thread.socket = this;
398          thread.connected = true;
399          thread.Create();
400          while(!answered && thread)
401          {
402             //guiApp.WaitNetworkEvent();
403             //guiApp.ProcessNetworkEvents();
404             // Process();
405
406             if(GetCurrentThreadID() == thread.id)
407                Process();
408             else
409                thread.semaphore.Wait();
410          }
411          result = true;
412       }
413       return result;
414    }
415
416    virtual void CallVirtualMethod(unsigned int __ecereMethodID, SerialBuffer __ecereBuffer);
417
418    void OnReceivePacket(DCOMPacket p)
419    {
420       switch((DCOMPacketType)letohd(p.type))
421       {
422          case dcom_InstanceCreated:
423          {
424             ObjectCreatedPacket packet = (ObjectCreatedPacket)p;
425             objectID = letohd(packet.objectID);
426             answered = true;
427             break;
428          }
429          case dcom_MethodReturned:
430          {
431             MethodReturnedPacket packet = (MethodReturnedPacket)p;
432             __ecereBuffer.WriteData(packet.args, letohd(packet.argsSize));
433             answered = true;
434             break;
435          }
436          // Virtual Method Called
437          case dcom_CallVirtualMethod:
438          {
439             CallVirtualMethodPacket callMethod = (CallVirtualMethodPacket)p;
440             VirtualMethodReturnedPacket packet;
441             unsigned int size = (uint)&((VirtualMethodReturnedPacket)0).args; // sizeof(class VirtualMethodReturnedPacket);
442             SerialBuffer buffer = virtualsBuffer;
443             // TOFIX: Hardcoded VTBL ID
444             bool overridden = _vTbl[18 + callMethod.methodID] != _class._vTbl[18 + callMethod.methodID];
445             callMethod.argsSize = letohd(callMethod.argsSize);
446             if(overridden)
447             {
448                buffer.WriteData(callMethod.args, callMethod.argsSize);
449                // TOFIX: Hardcoded VTBL ID
450                _vTbl[17](this, callMethod.methodID, buffer);
451                size += buffer.size; // - 1;
452             }
453             packet = (VirtualMethodReturnedPacket)new0 byte[size];
454             packet.overridden = overridden;
455             packet.objectID = objectID;
456             packet.type = (DCOMPacketType)htoled((DCOMPacketType)dcom_VirtualMethodReturned);
457             packet.size = size;
458             packet.argsSize = htoled(buffer.size);
459             buffer.ReadData(packet.args, buffer.size);
460             buffer.Free();
461             SendPacket(packet);
462             delete packet;
463             break;
464          }
465       }
466    }
467
468    void OnDisconnect(int code)
469    {
470       if(thread)
471          thread.connected = false;
472       answered = 2;
473    }
474
475    dllexport bool CallMethod(unsigned int methodID)
476    {
477       if(connected)
478       {
479          unsigned int size = (uint)&((CallMethodPacket)0).args + __ecereBuffer.size; // sizeof(class CallMethodPacket) + __ecereBuffer.size - 1;
480          CallMethodPacket packet = (CallMethodPacket)new0 byte[size];
481          packet.type = (DCOMPacketType)htoled((DCOMPacketType)dcom_CallMethod);
482          packet.size = size;
483          packet.objectID = htoled(objectID);
484          packet.methodID = htoled(methodID);
485          packet.argsSize = htoled(__ecereBuffer.size);
486          __ecereBuffer.ReadData(packet.args, __ecereBuffer.size);
487          answered = false;
488          SendPacket(packet);
489          delete packet;
490
491          while(!answered && thread)
492          {
493             //guiApp.WaitNetworkEvent();
494             //guiApp.ProcessNetworkEvents();
495             //Process();
496             if(GetCurrentThreadID() == thread.id)
497                Process();
498             else
499                thread.semaphore.Wait();
500          }
501          return answered == true;
502       }
503       return false;
504    }
505
506    ~DCOMClientObject()
507    {
508       if(thread.started)
509       {
510          if(GetCurrentThreadID() != thread.id)
511             thread.Wait();
512       }
513    }
514 };