5 #define WIN32_LEAN_AND_MEAN
7 static WSADATA wsaData;
9 #elif defined(__unix__) || defined(__APPLE__)
17 #include <netinet/in.h>
19 #include <sys/socket.h>
21 #include <sys/types.h>
23 #include <arpa/inet.h>
29 typedef struct hostent HOSTENT;
30 typedef struct sockaddr SOCKADDR;
31 typedef struct sockaddr_in SOCKADDR_IN;
32 typedef struct in_addr IN_ADDR;
33 #define closesocket(s) close(s)
42 static enum DCOMPacketType
44 dcom_CreateInstance = 3,
46 dcom_CallVirtualMethod = 6,
47 dcom_InstanceCreated = 9,
48 dcom_VirtualMethodReturned = 10,
49 dcom_MethodReturned = 11
52 static class DCOMPacket : Packet
56 static class CreateInstancePacket : DCOMPacket
62 static class ObjectCreatedPacket : DCOMPacket
64 unsigned int objectID;
67 static class CallMethodPacket : DCOMPacket
72 unsigned int argsSize;
76 static class CallVirtualMethodPacket : DCOMPacket
81 unsigned int argsSize;
85 static class MethodReturnedPacket : DCOMPacket
89 unsigned int argsSize;
93 static class VirtualMethodReturnedPacket : DCOMPacket
95 unsigned int objectID;
96 unsigned int methodID;
99 unsigned int argsSize;
103 /*static */class VirtualCallAck : struct
111 SerialBuffer buffer { };
114 class CallAck : strict
120 SerialBuffer buffer { };
123 public class DCOMServerObject
125 VirtualCallAck VirtualCallAcknowledged(int methodID, int objectID, int callID)
127 Iterator<VirtualCallAck> it { acks };
130 VirtualCallAck ack = it.data;
131 if(ack.methodID == methodID && ack.objectID == objectID && ack.callID == callID)
143 virtual void CallMethod(unsigned int __ecereMethodID, SerialBuffer __ecereBuffer);
145 dllexport bool CallVirtualMethod(unsigned int methodID, bool hasReturnValue)
149 if(serverSocket && serverSocket.connected)
151 int currentThreadID = GetCurrentThreadID();
152 int callID = nextCallID++;
153 DCOMServerSocket socket = serverSocket;
154 DCOMServerSocket processingSocket;
155 unsigned int size = (uint)&((CallVirtualMethodPacket)0).args + argsBuffer.size; // sizeof(class CallVirtualMethodPacket) + virtualsBuffer.size - 1;
156 CallVirtualMethodPacket packet = (CallVirtualMethodPacket)new0 byte[size];
157 VirtualCallAck ack = null;
159 if(currentThreadID == serverSocket.thread.id)
160 processingSocket = serverSocket;
163 processingSocket = null;
164 if(serverSocket.service)
167 for(processingSocket = serverSocket.service.sockets.first;
169 processingSocket = (DCOMServerSocket)processingSocket.next)
171 next = processingSocket.next;
172 if(processingSocket.connected &&
173 processingSocket.thread.id == currentThreadID)
179 packet.type = (DCOMPacketType)htoled((DCOMPacketType)dcom_CallVirtualMethod);
181 packet.callID = callID;
182 packet.methodID = htoled(methodID);
183 packet.hasReturnValue = hasReturnValue;
184 packet.argsSize = htoled(argsBuffer.size);
185 argsBuffer.ReadData(packet.args, argsBuffer.size);
188 serverSocket.SendPacket(packet);
191 socket._refCount += 2;
193 processingSocket._refCount += 2;
199 if(!serverSocket || !serverSocket.connected || !serverSocket.thread)
201 if(ack = VirtualCallAcknowledged(methodID, id, callID))
206 if(processingSocket && processingSocket.connected)
207 processingSocket.ProcessTimeOut(0.01);
209 ecere::sys::Sleep(0.01);//serverSocket.thread.semaphore.Wait();
216 result = ack.overridden;
217 returnBuffer.WriteData(ack.buffer.buffer, ack.buffer.count);
224 if(socket._refCount > 1)
228 if(processingSocket && processingSocket._refCount > 1)
229 processingSocket._refCount--;
230 delete processingSocket;
241 DCOMServerSocket serverSocket;
243 SerialBuffer argsBuffer { };
244 SerialBuffer returnBuffer { };
245 List<VirtualCallAck> acks { };
249 nextCallID = GetRandom(1, 999999);//100;
257 #define GETLEDWORD(b) (uint32)(((b)[3] << 24) | ((b)[2] << 16) | ((b)[1] << 8) | (b)[0])
259 #define PUTLEDWORD(b, d) \
260 (b)[3] = (byte)(((d) >> 24) & 0xFF); \
261 (b)[2] = (byte)(((d) >> 16) & 0xFF); \
262 (b)[1] = (byte)(((d) >> 8) & 0xFF); \
263 (b)[0] = (byte)( (d) & 0xFF);
265 static uint32 htoled(uint32 value)
268 PUTLEDWORD((byte *)&result, value);
272 static uint32 letohd(uint32 value)
274 return GETLEDWORD((byte *)&value);
277 class DCOMServerThread : Thread
279 DCOMServerSocket socket;
280 Semaphore semaphore { };
288 socket.ProcessTimeOut(0.01);
290 socket.ProcessCalls();
299 class DCOMClientThread : Thread
302 Semaphore semaphore { };
306 socket._refCount += 2;
309 socket.ProcessTimeOut(0.01);
312 if(socket._refCount > 1) socket._refCount--;
318 /*static */public class DCOMServerSocket : Socket
321 DCOMServerObject * objects;
323 DCOMServerThread thread
325 socket = this, connected = true;
327 List<CallMethodPacket> calls { };
328 bool processingCalls;
332 CallMethodPacket callMethod;
333 Iterator <CallMethodPacket> it { calls };
338 if(!it.Next() || disconnected)
343 callMethod = it.data;
345 processingCalls = true;
348 if(callMethod.objectID < numObjects /*&& callMethod.methodID < numMethods*/)
350 DCOMServerObject object = objects[callMethod.objectID];
351 bool hasReturnValue = true;
352 MethodReturnedPacket packet;
354 SerialBuffer buffer { };
355 int methodID = callMethod.methodID;
356 int callID = callMethod.callID;
358 buffer.WriteData(callMethod.args, callMethod.argsSize);
362 size = (uint)&((MethodReturnedPacket)0).args;
363 packet = (MethodReturnedPacket)new0 byte[size];
364 packet.type = (DCOMPacketType)htoled((DCOMPacketType)dcom_MethodReturned);
366 packet.callID = callMethod.callID;
367 packet.methodID = callMethod.methodID;
374 // TOFIX: Hardcoded VTBL ID
375 object._vTbl[10](object, methodID, buffer);
379 size = (uint)&((MethodReturnedPacket)0).args + buffer.size; // sizeof(class MethodReturnedPacket) + buffer.size - 1;
380 packet = (MethodReturnedPacket)new0 byte[size];
381 packet.type = (DCOMPacketType)htoled((DCOMPacketType)dcom_MethodReturned);
383 packet.callID = callID;
384 packet.methodID = methodID;
385 packet.argsSize = htoled(buffer.size);
386 buffer.ReadData(packet.args, buffer.size);
392 if(object._refCount > 1)
397 processingCalls = false;
402 void OnReceivePacket(DCOMPacket packet)
405 switch((DCOMPacketType)letohd(packet.type))
407 case dcom_CreateInstance:
409 CreateInstancePacket createInstance = (CreateInstancePacket)packet;
410 Class _class = eSystem_FindClass(__thisModule.application, createInstance.className);
411 Class runClass = eSystem_FindClass(__thisModule.application, createInstance.className + 4);
412 DCOMServerObject object;
416 _class = eSystem_FindClass(runClass.module, createInstance.className);
418 objects = renew objects DCOMServerObject[numObjects+1];
419 object = objects[numObjects] = eInstance_New(_class);
421 object.serverSocket = this;
422 object.id = numObjects++;
423 object.instance = eInstance_New(runClass);
424 incref object.instance;
425 object.instance._vTbl = new void *[object.instance._class.vTblSize + 1];
426 object.instance._vTbl++;
427 object.instance._vTbl[-1] = (void *)object;
428 memcpy(object.instance._vTbl, object.instance._class._vTbl, sizeof(int(*)()) * object.instance._class.vTblSize);
429 for(vid = runClass.base.vTblSize; vid < runClass.vTblSize; vid++)
431 object.instance._vTbl[vid] = object._vTbl[vid - runClass.base.vTblSize + 11];
435 ObjectCreatedPacket sendPacket = ObjectCreatedPacket { };
436 sendPacket.type = (DCOMPacketType)htoled((DCOMPacketType)dcom_InstanceCreated);
437 sendPacket.size = sizeof(class ObjectCreatedPacket);
438 sendPacket.objectID = htoled(object.id);
439 SendPacket(sendPacket);
444 case dcom_CallMethod:
447 CallMethodPacket callMethod = (CallMethodPacket)packet;
448 callMethod.objectID = letohd(callMethod.objectID);
449 callMethod.argsSize = letohd(callMethod.argsSize);
451 p = (CallMethodPacket)new byte[callMethod.size];
452 memcpy(p, callMethod, callMethod.size);
457 case dcom_VirtualMethodReturned:
459 VirtualMethodReturnedPacket methodReturned = (VirtualMethodReturnedPacket)packet;
460 if(methodReturned.objectID < numObjects)
462 DCOMServerObject object = objects[methodReturned.objectID];
465 methodReturned.objectID,
466 methodReturned.methodID,
467 methodReturned.callID,
468 methodReturned.overridden
470 ack.buffer.WriteData(methodReturned.args, letohd(methodReturned.argsSize));
472 object.acks.Add(ack);
481 void OnDisconnect(int code)
485 thread.connected = false;
487 if(thread.started && GetCurrentThreadID() != 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() != thread.id)
543 bool result = Service::Start();
546 thread.connected = true;
555 DCOMServerSocket socket;
556 thread.connected = false;
557 result = Service::Stop();
558 if(thread.started && GetCurrentThreadID() != 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(char * server, int port)
609 if(Socket::Connect(server, port))
611 int len = 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() == 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;
676 unsigned int size = (uint)&((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 _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;
738 dllexport bool CallMethod(unsigned int methodID)
740 if(this && connected)
744 int callID = nextCallID++;
745 unsigned int size = (uint)&((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() == 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);
791 if(GetCurrentThreadID() != thread.id)
798 // A class to make set of things happen atomically
799 // e.g. to send a bunch of notifications all at once,
800 // without anything else happening in between
801 public class DCOMSendControl
807 while(sendingOut) guiApp.Unlock(), ecere::sys::Sleep(0.01), guiApp.Lock();