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)
41 #if !defined(__EMSCRIPTEN__)
45 static enum DCOMPacketType
47 dcom_CreateInstance = 3,
49 dcom_CallVirtualMethod = 6,
50 dcom_InstanceCreated = 9,
51 dcom_VirtualMethodReturned = 10,
52 dcom_MethodReturned = 11
55 static class DCOMPacket : Packet
59 static class CreateInstancePacket : DCOMPacket
65 static class ObjectCreatedPacket : DCOMPacket
67 unsigned int objectID;
70 static class CallMethodPacket : DCOMPacket
75 unsigned int argsSize;
79 static class CallVirtualMethodPacket : DCOMPacket
84 unsigned int argsSize;
88 static class MethodReturnedPacket : DCOMPacket
92 unsigned int argsSize;
96 static class VirtualMethodReturnedPacket : DCOMPacket
98 unsigned int objectID;
99 unsigned int methodID;
102 unsigned int argsSize;
106 /*static */class VirtualCallAck : struct
114 SerialBuffer buffer { };
117 class CallAck : struct
123 SerialBuffer buffer { };
126 public class DCOMServerObject
128 VirtualCallAck VirtualCallAcknowledged(int methodID, int objectID, int callID)
130 Iterator<VirtualCallAck> it { acks };
133 VirtualCallAck ack = it.data;
134 if(ack.methodID == methodID && ack.objectID == objectID && ack.callID == callID)
146 virtual void CallMethod(unsigned int __ecereMethodID, SerialBuffer __ecereBuffer);
148 dllexport bool CallVirtualMethod(unsigned int methodID, bool hasReturnValue)
152 if(serverSocket && serverSocket.connected)
154 int64 currentThreadID = GetCurrentThreadID();
155 int callID = nextCallID++;
156 DCOMServerSocket socket = serverSocket;
157 DCOMServerSocket processingSocket;
158 unsigned int size = (uint)(uintptr)&((CallVirtualMethodPacket)0).args + argsBuffer.size; // sizeof(class CallVirtualMethodPacket) + virtualsBuffer.size - 1;
159 CallVirtualMethodPacket packet = (CallVirtualMethodPacket)new0 byte[size];
160 VirtualCallAck ack = null;
162 if(currentThreadID == (int64)serverSocket.thread.id)
163 processingSocket = serverSocket;
166 processingSocket = null;
167 if(serverSocket.service)
170 for(processingSocket = serverSocket.service.sockets.first;
172 processingSocket = (DCOMServerSocket)next)
174 next = processingSocket.next;
175 if(processingSocket.connected &&
176 (int64)processingSocket.thread.id == currentThreadID)
182 packet.type = (DCOMPacketType)htoled((DCOMPacketType)dcom_CallVirtualMethod);
184 packet.callID = callID;
185 packet.methodID = htoled(methodID);
186 packet.hasReturnValue = hasReturnValue;
187 packet.argsSize = htoled(argsBuffer.size);
188 argsBuffer.ReadData(packet.args, argsBuffer.size);
191 serverSocket.SendPacket(packet);
194 socket._refCount += 2;
196 processingSocket._refCount += 2;
202 if(!serverSocket || !serverSocket.connected || !serverSocket.thread)
204 if((ack = VirtualCallAcknowledged(methodID, id, callID)))
209 if(processingSocket && processingSocket.connected)
210 processingSocket.ProcessTimeOut(0.01);
212 ecere::sys::Sleep(0.01);//serverSocket.thread.semaphore.Wait();
219 result = ack.overridden;
220 returnBuffer.WriteData(ack.buffer.buffer, ack.buffer.count);
227 if(socket._refCount > 1)
231 if(processingSocket && processingSocket._refCount > 1)
232 processingSocket._refCount--;
233 delete processingSocket;
244 DCOMServerSocket serverSocket;
246 SerialBuffer argsBuffer { };
247 SerialBuffer returnBuffer { };
248 List<VirtualCallAck> acks { };
252 nextCallID = GetRandom(1, 999999);//100;
260 #define GETLEDWORD(b) (uint32)(((b)[3] << 24) | ((b)[2] << 16) | ((b)[1] << 8) | (b)[0])
262 #define PUTLEDWORD(b, d) \
263 (b)[3] = (byte)(((d) >> 24) & 0xFF); \
264 (b)[2] = (byte)(((d) >> 16) & 0xFF); \
265 (b)[1] = (byte)(((d) >> 8) & 0xFF); \
266 (b)[0] = (byte)( (d) & 0xFF);
268 static uint32 htoled(uint32 value)
271 PUTLEDWORD((byte *)&result, value);
275 static uint32 letohd(uint32 value)
277 return GETLEDWORD((byte *)&value);
280 class DCOMServerThread : Thread
282 DCOMServerSocket socket;
283 Semaphore semaphore { };
291 socket.ProcessTimeOut(0.01);
293 socket.ProcessCalls();
302 class DCOMClientThread : Thread
305 Semaphore semaphore { };
309 socket._refCount += 2;
312 socket.ProcessTimeOut(0.01);
315 if(socket._refCount > 1) socket._refCount--;
321 /*static */public class DCOMServerSocket : Socket
324 DCOMServerObject * objects;
326 DCOMServerThread thread
328 socket = this, connected = true;
330 List<CallMethodPacket> calls { };
331 bool processingCalls;
335 CallMethodPacket callMethod;
336 Iterator <CallMethodPacket> it { calls };
341 if(!it.Next() || disconnected)
346 callMethod = it.data;
348 processingCalls = true;
351 if(callMethod.objectID < numObjects /*&& callMethod.methodID < numMethods*/)
353 DCOMServerObject object = objects[callMethod.objectID];
354 bool hasReturnValue = true;
355 MethodReturnedPacket packet;
357 SerialBuffer buffer { };
358 int methodID = callMethod.methodID;
359 int callID = callMethod.callID;
361 buffer.WriteData(callMethod.args, callMethod.argsSize);
365 size = (uint)(uintptr)&((MethodReturnedPacket)0).args;
366 packet = (MethodReturnedPacket)new0 byte[size];
367 packet.type = (DCOMPacketType)htoled((DCOMPacketType)dcom_MethodReturned);
369 packet.callID = callMethod.callID;
370 packet.methodID = callMethod.methodID;
377 // TOFIX: Hardcoded VTBL ID
378 ((void (*)(void *, uint, SerialBuffer))(void *)object._vTbl[10])(object, methodID, buffer);
382 size = (uint)(uintptr)&((MethodReturnedPacket)0).args + buffer.size; // sizeof(class MethodReturnedPacket) + buffer.size - 1;
383 packet = (MethodReturnedPacket)new0 byte[size];
384 packet.type = (DCOMPacketType)htoled((DCOMPacketType)dcom_MethodReturned);
386 packet.callID = callID;
387 packet.methodID = methodID;
388 packet.argsSize = htoled(buffer.size);
389 buffer.ReadData(packet.args, buffer.size);
395 if(object._refCount > 1)
400 processingCalls = false;
405 void OnReceivePacket(DCOMPacket packet)
408 switch((DCOMPacketType)letohd(packet.type))
410 case dcom_CreateInstance:
412 CreateInstancePacket createInstance = (CreateInstancePacket)packet;
413 Class _class = eSystem_FindClass(__thisModule.application, createInstance.className);
414 Class runClass = eSystem_FindClass(__thisModule.application, createInstance.className + 4);
415 DCOMServerObject object;
419 _class = eSystem_FindClass(runClass.module, createInstance.className);
421 objects = renew objects DCOMServerObject[numObjects+1];
422 object = objects[numObjects] = eInstance_New(_class);
424 object.serverSocket = this;
425 object.id = numObjects++;
426 object.instance = eInstance_New(runClass);
427 incref object.instance;
428 object.instance._vTbl = new void *[object.instance._class.vTblSize + 1];
429 object.instance._vTbl++;
430 object.instance._vTbl[-1] = (void *)object;
431 memcpy(object.instance._vTbl, object.instance._class._vTbl, sizeof(int(*)()) * object.instance._class.vTblSize);
432 for(vid = runClass.base.vTblSize; vid < runClass.vTblSize; vid++)
434 object.instance._vTbl[vid] = object._vTbl[vid - runClass.base.vTblSize + 11];
438 ObjectCreatedPacket sendPacket = ObjectCreatedPacket { };
439 sendPacket.type = (DCOMPacketType)htoled((DCOMPacketType)dcom_InstanceCreated);
440 sendPacket.size = sizeof(class ObjectCreatedPacket);
441 sendPacket.objectID = htoled(object.id);
442 SendPacket(sendPacket);
447 case dcom_CallMethod:
450 CallMethodPacket callMethod = (CallMethodPacket)packet;
451 callMethod.objectID = letohd(callMethod.objectID);
452 callMethod.argsSize = letohd(callMethod.argsSize);
454 p = (CallMethodPacket)new byte[callMethod.size];
455 memcpy(p, callMethod, callMethod.size);
460 case dcom_VirtualMethodReturned:
462 VirtualMethodReturnedPacket methodReturned = (VirtualMethodReturnedPacket)packet;
463 if(methodReturned.objectID < numObjects)
465 DCOMServerObject object = objects[methodReturned.objectID];
468 methodReturned.objectID,
469 methodReturned.methodID,
470 methodReturned.callID,
471 methodReturned.overridden
473 ack.buffer.WriteData(methodReturned.args, letohd(methodReturned.argsSize));
475 object.acks.Add(ack);
484 void OnDisconnect(int code)
487 thread.connected = false;
489 if(thread.started && GetCurrentThreadID() != (int64)thread.id)
498 for(c = 0; c<numObjects; c++)
500 objects[c].instance._vTbl--;
501 delete objects[c].instance._vTbl;
502 objects[c].instance._vTbl = objects[c].instance._class._vTbl;
503 delete objects[c].instance;
512 class DCOMServiceThread : Thread
518 DCOMService service = this.service;
529 public class DCOMService : Service
533 DCOMServiceThread thread
535 service = this, connected = true;
539 if(thread.started && GetCurrentThreadID() != (int64)thread.id)
545 bool result = Service::Start();
548 thread.connected = true;
557 thread.connected = false;
558 result = Service::Stop();
559 if(thread.started && GetCurrentThreadID() != (int64)thread.id)
566 DCOMServerSocket socket { };
568 socket.service = this;
570 socket.thread.Create();
576 public class DCOMClientObject : Socket
578 CallAck CallAcknowledged(int methodID, int objectID, int callID)
580 Iterator<CallAck> it { acks };
583 CallAck ack = it.data;
584 if(ack.methodID == methodID && ack.objectID == objectID && ack.callID == callID)
594 unsigned int objectID;
596 SerialBuffer __ecereBuffer { };
597 List<CallAck> acks { };
600 nextCallID = GetRandom(1, 999999);
603 private DCOMClientThread thread
605 socket = this, connected = true;
608 bool Connect(const char * server, int port)
611 if(Socket::Connect(server, port))
613 int len = (int)(strlen(_class.name) + 4 - strlen("DCOMClient_"));
614 unsigned int size = sizeof(class CreateInstancePacket) + len;
615 CreateInstancePacket packet = (CreateInstancePacket)new0 byte[size];
616 packet.type = (DCOMPacketType)htoled((DCOMPacketType)dcom_CreateInstance);
618 CopyBytes(packet.className, "DCOM", 4);
619 CopyBytes(packet.className + 4, _class.name + strlen("DCOMClient_"), len-4+1);
623 thread.socket = this;
624 thread.connected = true;
627 while(!answered && thread && connected)
629 //guiApp.WaitNetworkEvent();
630 //guiApp.ProcessNetworkEvents();
633 if(GetCurrentThreadID() == (int64)thread.id)
636 thread.semaphore.Wait();
644 virtual void CallVirtualMethod(unsigned int __ecereMethodID, SerialBuffer __ecereBuffer);
646 void OnReceivePacket(DCOMPacket p)
651 switch((DCOMPacketType)letohd(p.type))
653 case dcom_InstanceCreated:
655 ObjectCreatedPacket packet = (ObjectCreatedPacket)p;
656 objectID = letohd(packet.objectID);
660 case dcom_MethodReturned:
662 MethodReturnedPacket packet = (MethodReturnedPacket)p;
669 ack.buffer.WriteData(packet.args, letohd(packet.argsSize));
673 // Virtual Method Called
674 case dcom_CallVirtualMethod:
676 CallVirtualMethodPacket callMethod = (CallVirtualMethodPacket)p;
677 VirtualMethodReturnedPacket packet = null;
678 unsigned int size = (uint)(uintptr)&((VirtualMethodReturnedPacket)0).args; // sizeof(class VirtualMethodReturnedPacket);
679 SerialBuffer buffer { };
680 bool hasReturnValue = callMethod.hasReturnValue;
681 int methodID = callMethod.methodID;
682 int callID = callMethod.callID;
683 // TOFIX: Hardcoded VTBL ID
684 bool overridden = _vTbl[18 + methodID] != _class._vTbl[18 + methodID];
685 callMethod.argsSize = letohd(callMethod.argsSize);
689 packet = (VirtualMethodReturnedPacket)new0 byte[size];
690 packet.overridden = overridden;
691 packet.objectID = objectID;
692 packet.methodID = methodID;
693 packet.callID = callID;
694 packet.type = (DCOMPacketType)htoled((DCOMPacketType)dcom_VirtualMethodReturned);
702 buffer.WriteData(callMethod.args, callMethod.argsSize);
704 // TOFIX: Hardcoded VTBL ID
705 ((void (*)(void *, uint, SerialBuffer))(void *)_vTbl[17])(this, callMethod.methodID, buffer);
707 // WARNING: callMethod packet is invalidated !!!
709 size += buffer.size; // - 1;
713 packet = (VirtualMethodReturnedPacket)new0 byte[size];
714 packet.overridden = overridden;
715 packet.objectID = objectID;
716 packet.methodID = methodID;
717 packet.callID = callID;
718 packet.type = (DCOMPacketType)htoled((DCOMPacketType)dcom_VirtualMethodReturned);
720 packet.argsSize = htoled(buffer.size);
721 buffer.ReadData(packet.args, buffer.size);
733 void OnDisconnect(int code)
736 thread.connected = false;
737 answered = true; //2;
740 dllexport bool CallMethod(unsigned int methodID)
743 if(this && connected)
746 int callID = nextCallID++;
747 unsigned int size = (uint)(uintptr)&((CallMethodPacket)0).args + __ecereBuffer.size; // sizeof(class CallMethodPacket) + __ecereBuffer.size - 1;
748 CallMethodPacket packet = (CallMethodPacket)new0 byte[size];
749 packet.type = (DCOMPacketType)htoled((DCOMPacketType)dcom_CallMethod);
751 packet.objectID = htoled(objectID);
752 packet.methodID = htoled(methodID);
753 packet.callID = callID;
754 packet.argsSize = htoled(__ecereBuffer.size);
755 __ecereBuffer.ReadData(packet.args, __ecereBuffer.size);
761 if(!thread || !connected)
763 if((ack = CallAcknowledged(methodID, objectID, callID)))
767 //guiApp.WaitNetworkEvent();
768 //guiApp.ProcessNetworkEvents();
770 if(GetCurrentThreadID() == (int64)thread.id)
771 ProcessTimeOut(0.01);
773 ecere::sys::Sleep(0.01);//thread.semaphore.Wait();
779 __ecereBuffer.Free();
780 __ecereBuffer.WriteData(ack.buffer.buffer, ack.buffer.count);
792 if(GetCurrentThreadID() != (int64)thread.id)
799 // A class to make set of things happen atomically
800 // e.g. to send a bunch of notifications all at once,
801 // without anything else happening in between
802 public class DCOMSendControl
808 while(sendingOut) guiApp.Unlock(), ecere::sys::Sleep(0.01), guiApp.Lock();
818 #endif // !defined(__EMSCRIPTEN__)