5 #define WIN32_LEAN_AND_MEAN
10 #elif defined(__unix__) || defined(__APPLE__)
18 #include <netinet/in.h>
20 #include <sys/socket.h>
22 #include <sys/types.h>
24 #include <arpa/inet.h>
30 typedef struct hostent HOSTENT;
31 typedef struct sockaddr SOCKADDR;
32 typedef struct sockaddr_in SOCKADDR_IN;
33 typedef struct in_addr IN_ADDR;
34 #define closesocket(s) close(s)
43 static enum DCOMPacketType
45 dcom_CreateInstance = 3,
47 dcom_CallVirtualMethod = 6,
48 dcom_InstanceCreated = 9,
49 dcom_VirtualMethodReturned = 10,
50 dcom_MethodReturned = 11
53 static class DCOMPacket : Packet
57 static class CreateInstancePacket : DCOMPacket
63 static class ObjectCreatedPacket : DCOMPacket
65 unsigned int objectID;
68 static class CallMethodPacket : DCOMPacket
73 unsigned int argsSize;
77 static class CallVirtualMethodPacket : DCOMPacket
82 unsigned int argsSize;
86 static class MethodReturnedPacket : DCOMPacket
90 unsigned int argsSize;
94 static class VirtualMethodReturnedPacket : DCOMPacket
96 unsigned int objectID;
97 unsigned int methodID;
100 unsigned int argsSize;
104 /*static */class VirtualCallAck : struct
112 SerialBuffer buffer { };
115 class CallAck : struct
121 SerialBuffer buffer { };
124 public class DCOMServerObject
126 VirtualCallAck VirtualCallAcknowledged(int methodID, int objectID, int callID)
128 Iterator<VirtualCallAck> it { acks };
131 VirtualCallAck ack = it.data;
132 if(ack.methodID == methodID && ack.objectID == objectID && ack.callID == callID)
144 virtual void CallMethod(unsigned int __ecereMethodID, SerialBuffer __ecereBuffer);
146 dllexport bool CallVirtualMethod(unsigned int methodID, bool hasReturnValue)
150 if(serverSocket && serverSocket.connected)
152 int64 currentThreadID = GetCurrentThreadID();
153 int callID = nextCallID++;
154 DCOMServerSocket socket = serverSocket;
155 DCOMServerSocket processingSocket;
156 unsigned int size = (uint)(uintptr)&((CallVirtualMethodPacket)0).args + argsBuffer.size; // sizeof(class CallVirtualMethodPacket) + virtualsBuffer.size - 1;
157 CallVirtualMethodPacket packet = (CallVirtualMethodPacket)new0 byte[size];
158 VirtualCallAck ack = null;
160 if(currentThreadID == (int64)serverSocket.thread.id)
161 processingSocket = serverSocket;
164 processingSocket = null;
165 if(serverSocket.service)
168 for(processingSocket = serverSocket.service.sockets.first;
170 processingSocket = (DCOMServerSocket)next)
172 next = processingSocket.next;
173 if(processingSocket.connected &&
174 (int64)processingSocket.thread.id == currentThreadID)
180 packet.type = (DCOMPacketType)htoled((DCOMPacketType)dcom_CallVirtualMethod);
182 packet.callID = callID;
183 packet.methodID = htoled(methodID);
184 packet.hasReturnValue = hasReturnValue;
185 packet.argsSize = htoled(argsBuffer.size);
186 argsBuffer.ReadData(packet.args, argsBuffer.size);
189 serverSocket.SendPacket(packet);
192 socket._refCount += 2;
194 processingSocket._refCount += 2;
200 if(!serverSocket || !serverSocket.connected || !serverSocket.thread)
202 if((ack = VirtualCallAcknowledged(methodID, id, callID)))
207 if(processingSocket && processingSocket.connected)
208 processingSocket.ProcessTimeOut(0.01);
210 ecere::sys::Sleep(0.01);//serverSocket.thread.semaphore.Wait();
217 result = ack.overridden;
218 returnBuffer.WriteData(ack.buffer.buffer, ack.buffer.count);
225 if(socket._refCount > 1)
229 if(processingSocket && processingSocket._refCount > 1)
230 processingSocket._refCount--;
231 delete processingSocket;
242 DCOMServerSocket serverSocket;
244 SerialBuffer argsBuffer { };
245 SerialBuffer returnBuffer { };
246 List<VirtualCallAck> acks { };
250 nextCallID = GetRandom(1, 999999);//100;
258 #define GETLEDWORD(b) (uint32)(((b)[3] << 24) | ((b)[2] << 16) | ((b)[1] << 8) | (b)[0])
260 #define PUTLEDWORD(b, d) \
261 (b)[3] = (byte)(((d) >> 24) & 0xFF); \
262 (b)[2] = (byte)(((d) >> 16) & 0xFF); \
263 (b)[1] = (byte)(((d) >> 8) & 0xFF); \
264 (b)[0] = (byte)( (d) & 0xFF);
266 static uint32 htoled(uint32 value)
269 PUTLEDWORD((byte *)&result, value);
273 static uint32 letohd(uint32 value)
275 return GETLEDWORD((byte *)&value);
278 class DCOMServerThread : Thread
280 DCOMServerSocket socket;
281 Semaphore semaphore { };
289 socket.ProcessTimeOut(0.01);
291 socket.ProcessCalls();
300 class DCOMClientThread : Thread
303 Semaphore semaphore { };
307 socket._refCount += 2;
310 socket.ProcessTimeOut(0.01);
313 if(socket._refCount > 1) socket._refCount--;
319 /*static */public class DCOMServerSocket : Socket
322 DCOMServerObject * objects;
324 DCOMServerThread thread
326 socket = this, connected = true;
328 List<CallMethodPacket> calls { };
329 bool processingCalls;
333 CallMethodPacket callMethod;
334 Iterator <CallMethodPacket> it { calls };
339 if(!it.Next() || disconnected)
344 callMethod = it.data;
346 processingCalls = true;
349 if(callMethod.objectID < numObjects /*&& callMethod.methodID < numMethods*/)
351 DCOMServerObject object = objects[callMethod.objectID];
352 bool hasReturnValue = true;
353 MethodReturnedPacket packet;
355 SerialBuffer buffer { };
356 int methodID = callMethod.methodID;
357 int callID = callMethod.callID;
359 buffer.WriteData(callMethod.args, callMethod.argsSize);
363 size = (uint)(uintptr)&((MethodReturnedPacket)0).args;
364 packet = (MethodReturnedPacket)new0 byte[size];
365 packet.type = (DCOMPacketType)htoled((DCOMPacketType)dcom_MethodReturned);
367 packet.callID = callMethod.callID;
368 packet.methodID = callMethod.methodID;
375 // TOFIX: Hardcoded VTBL ID
376 ((void (*)(void *, uint, SerialBuffer))(void *)object._vTbl[10])(object, methodID, buffer);
380 size = (uint)(uintptr)&((MethodReturnedPacket)0).args + buffer.size; // sizeof(class MethodReturnedPacket) + buffer.size - 1;
381 packet = (MethodReturnedPacket)new0 byte[size];
382 packet.type = (DCOMPacketType)htoled((DCOMPacketType)dcom_MethodReturned);
384 packet.callID = callID;
385 packet.methodID = methodID;
386 packet.argsSize = htoled(buffer.size);
387 buffer.ReadData(packet.args, buffer.size);
393 if(object._refCount > 1)
398 processingCalls = false;
403 void OnReceivePacket(DCOMPacket packet)
406 switch((DCOMPacketType)letohd(packet.type))
408 case dcom_CreateInstance:
410 CreateInstancePacket createInstance = (CreateInstancePacket)packet;
411 Class _class = eSystem_FindClass(__thisModule.application, createInstance.className);
412 Class runClass = eSystem_FindClass(__thisModule.application, createInstance.className + 4);
413 DCOMServerObject object;
417 _class = eSystem_FindClass(runClass.module, createInstance.className);
419 objects = renew objects DCOMServerObject[numObjects+1];
420 object = objects[numObjects] = eInstance_New(_class);
422 object.serverSocket = this;
423 object.id = numObjects++;
424 object.instance = eInstance_New(runClass);
425 incref object.instance;
426 object.instance._vTbl = new void *[object.instance._class.vTblSize + 1];
427 object.instance._vTbl++;
428 object.instance._vTbl[-1] = (void *)object;
429 memcpy(object.instance._vTbl, object.instance._class._vTbl, sizeof(int(*)()) * object.instance._class.vTblSize);
430 for(vid = runClass.base.vTblSize; vid < runClass.vTblSize; vid++)
432 object.instance._vTbl[vid] = object._vTbl[vid - runClass.base.vTblSize + 11];
436 ObjectCreatedPacket sendPacket = ObjectCreatedPacket { };
437 sendPacket.type = (DCOMPacketType)htoled((DCOMPacketType)dcom_InstanceCreated);
438 sendPacket.size = sizeof(class ObjectCreatedPacket);
439 sendPacket.objectID = htoled(object.id);
440 SendPacket(sendPacket);
445 case dcom_CallMethod:
448 CallMethodPacket callMethod = (CallMethodPacket)packet;
449 callMethod.objectID = letohd(callMethod.objectID);
450 callMethod.argsSize = letohd(callMethod.argsSize);
452 p = (CallMethodPacket)new byte[callMethod.size];
453 memcpy(p, callMethod, callMethod.size);
458 case dcom_VirtualMethodReturned:
460 VirtualMethodReturnedPacket methodReturned = (VirtualMethodReturnedPacket)packet;
461 if(methodReturned.objectID < numObjects)
463 DCOMServerObject object = objects[methodReturned.objectID];
466 methodReturned.objectID,
467 methodReturned.methodID,
468 methodReturned.callID,
469 methodReturned.overridden
471 ack.buffer.WriteData(methodReturned.args, letohd(methodReturned.argsSize));
473 object.acks.Add(ack);
482 void OnDisconnect(int code)
485 thread.connected = false;
487 if(thread.started && GetCurrentThreadID() != (int64)thread.id)
496 for(c = 0; c<numObjects; c++)
498 objects[c].instance._vTbl--;
499 delete objects[c].instance._vTbl;
500 objects[c].instance._vTbl = objects[c].instance._class._vTbl;
501 delete objects[c].instance;
510 class DCOMServiceThread : Thread
516 DCOMService service = this.service;
527 public class DCOMService : Service
531 DCOMServiceThread thread
533 service = this, connected = true;
537 if(thread.started && GetCurrentThreadID() != (int64)thread.id)
543 bool result = Service::Start();
546 thread.connected = true;
555 thread.connected = false;
556 result = Service::Stop();
557 if(thread.started && GetCurrentThreadID() != (int64)thread.id)
564 DCOMServerSocket socket { };
566 socket.service = this;
568 socket.thread.Create();
574 public class DCOMClientObject : Socket
576 CallAck CallAcknowledged(int methodID, int objectID, int callID)
578 Iterator<CallAck> it { acks };
581 CallAck ack = it.data;
582 if(ack.methodID == methodID && ack.objectID == objectID && ack.callID == callID)
592 unsigned int objectID;
594 SerialBuffer __ecereBuffer { };
595 List<CallAck> acks { };
598 nextCallID = GetRandom(1, 999999);
601 private DCOMClientThread thread
603 socket = this, connected = true;
606 bool Connect(const char * server, int port)
609 if(Socket::Connect(server, port))
611 int len = (int)(strlen(_class.name) + 4 - strlen("DCOMClient_"));
612 unsigned int size = sizeof(class CreateInstancePacket) + len;
613 CreateInstancePacket packet = (CreateInstancePacket)new0 byte[size];
614 packet.type = (DCOMPacketType)htoled((DCOMPacketType)dcom_CreateInstance);
616 CopyBytes(packet.className, "DCOM", 4);
617 CopyBytes(packet.className + 4, _class.name + strlen("DCOMClient_"), len-4+1);
621 thread.socket = this;
622 thread.connected = true;
625 while(!answered && thread && connected)
627 //guiApp.WaitNetworkEvent();
628 //guiApp.ProcessNetworkEvents();
631 if(GetCurrentThreadID() == (int64)thread.id)
634 thread.semaphore.Wait();
642 virtual void CallVirtualMethod(unsigned int __ecereMethodID, SerialBuffer __ecereBuffer);
644 void OnReceivePacket(DCOMPacket p)
649 switch((DCOMPacketType)letohd(p.type))
651 case dcom_InstanceCreated:
653 ObjectCreatedPacket packet = (ObjectCreatedPacket)p;
654 objectID = letohd(packet.objectID);
658 case dcom_MethodReturned:
660 MethodReturnedPacket packet = (MethodReturnedPacket)p;
667 ack.buffer.WriteData(packet.args, letohd(packet.argsSize));
671 // Virtual Method Called
672 case dcom_CallVirtualMethod:
674 CallVirtualMethodPacket callMethod = (CallVirtualMethodPacket)p;
675 VirtualMethodReturnedPacket packet = null;
676 unsigned int size = (uint)(uintptr)&((VirtualMethodReturnedPacket)0).args; // sizeof(class VirtualMethodReturnedPacket);
677 SerialBuffer buffer { };
678 bool hasReturnValue = callMethod.hasReturnValue;
679 int methodID = callMethod.methodID;
680 int callID = callMethod.callID;
681 // TOFIX: Hardcoded VTBL ID
682 bool overridden = _vTbl[18 + methodID] != _class._vTbl[18 + methodID];
683 callMethod.argsSize = letohd(callMethod.argsSize);
687 packet = (VirtualMethodReturnedPacket)new0 byte[size];
688 packet.overridden = overridden;
689 packet.objectID = objectID;
690 packet.methodID = methodID;
691 packet.callID = callID;
692 packet.type = (DCOMPacketType)htoled((DCOMPacketType)dcom_VirtualMethodReturned);
700 buffer.WriteData(callMethod.args, callMethod.argsSize);
702 // TOFIX: Hardcoded VTBL ID
703 ((void (*)(void *, uint, SerialBuffer))(void *)_vTbl[17])(this, callMethod.methodID, buffer);
705 // WARNING: callMethod packet is invalidated !!!
707 size += buffer.size; // - 1;
711 packet = (VirtualMethodReturnedPacket)new0 byte[size];
712 packet.overridden = overridden;
713 packet.objectID = objectID;
714 packet.methodID = methodID;
715 packet.callID = callID;
716 packet.type = (DCOMPacketType)htoled((DCOMPacketType)dcom_VirtualMethodReturned);
718 packet.argsSize = htoled(buffer.size);
719 buffer.ReadData(packet.args, buffer.size);
731 void OnDisconnect(int code)
734 thread.connected = false;
735 answered = true; //2;
738 dllexport bool CallMethod(unsigned int methodID)
741 if(this && connected)
744 int callID = nextCallID++;
745 unsigned int size = (uint)(uintptr)&((CallMethodPacket)0).args + __ecereBuffer.size; // sizeof(class CallMethodPacket) + __ecereBuffer.size - 1;
746 CallMethodPacket packet = (CallMethodPacket)new0 byte[size];
747 packet.type = (DCOMPacketType)htoled((DCOMPacketType)dcom_CallMethod);
749 packet.objectID = htoled(objectID);
750 packet.methodID = htoled(methodID);
751 packet.callID = callID;
752 packet.argsSize = htoled(__ecereBuffer.size);
753 __ecereBuffer.ReadData(packet.args, __ecereBuffer.size);
759 if(!thread || !connected)
761 if((ack = CallAcknowledged(methodID, objectID, callID)))
765 //guiApp.WaitNetworkEvent();
766 //guiApp.ProcessNetworkEvents();
768 if(GetCurrentThreadID() == (int64)thread.id)
769 ProcessTimeOut(0.01);
771 ecere::sys::Sleep(0.01);//thread.semaphore.Wait();
777 __ecereBuffer.Free();
778 __ecereBuffer.WriteData(ack.buffer.buffer, ack.buffer.count);
790 if(GetCurrentThreadID() != (int64)thread.id)
797 // A class to make set of things happen atomically
798 // e.g. to send a bunch of notifications all at once,
799 // without anything else happening in between
800 public class DCOMSendControl
806 while(sendingOut) guiApp.Unlock(), ecere::sys::Sleep(0.01), guiApp.Lock();