5 #define WIN32_LEAN_AND_MEAN
9 static WSADATA wsaData;
11 #elif defined(__unix__) || defined(__APPLE__)
19 #include <netinet/in.h>
21 #include <sys/socket.h>
23 #include <sys/types.h>
25 #include <arpa/inet.h>
31 typedef struct hostent HOSTENT;
32 typedef struct sockaddr SOCKADDR;
33 typedef struct sockaddr_in SOCKADDR_IN;
34 typedef struct in_addr IN_ADDR;
35 #define closesocket(s) close(s)
44 static enum DCOMPacketType
46 dcom_CreateInstance = 3,
48 dcom_CallVirtualMethod = 6,
49 dcom_InstanceCreated = 9,
50 dcom_VirtualMethodReturned = 10,
51 dcom_MethodReturned = 11
54 static class DCOMPacket : Packet
58 static class CreateInstancePacket : DCOMPacket
64 static class ObjectCreatedPacket : DCOMPacket
66 unsigned int objectID;
69 static class CallMethodPacket : DCOMPacket
74 unsigned int argsSize;
78 static class CallVirtualMethodPacket : DCOMPacket
83 unsigned int argsSize;
87 static class MethodReturnedPacket : DCOMPacket
91 unsigned int argsSize;
95 static class VirtualMethodReturnedPacket : DCOMPacket
97 unsigned int objectID;
98 unsigned int methodID;
101 unsigned int argsSize;
105 /*static */class VirtualCallAck : struct
113 SerialBuffer buffer { };
116 class CallAck : strict
122 SerialBuffer buffer { };
125 public class DCOMServerObject
127 VirtualCallAck VirtualCallAcknowledged(int methodID, int objectID, int callID)
129 Iterator<VirtualCallAck> it { acks };
132 VirtualCallAck ack = it.data;
133 if(ack.methodID == methodID && ack.objectID == objectID && ack.callID == callID)
145 virtual void CallMethod(unsigned int __ecereMethodID, SerialBuffer __ecereBuffer);
147 dllexport bool CallVirtualMethod(unsigned int methodID, bool hasReturnValue)
151 if(serverSocket && serverSocket.connected)
153 int64 currentThreadID = GetCurrentThreadID();
154 int callID = nextCallID++;
155 DCOMServerSocket socket = serverSocket;
156 DCOMServerSocket processingSocket;
157 unsigned int size = (uint)&((CallVirtualMethodPacket)0).args + argsBuffer.size; // sizeof(class CallVirtualMethodPacket) + virtualsBuffer.size - 1;
158 CallVirtualMethodPacket packet = (CallVirtualMethodPacket)new0 byte[size];
159 VirtualCallAck ack = null;
161 if(currentThreadID == serverSocket.thread.id)
162 processingSocket = serverSocket;
165 processingSocket = null;
166 if(serverSocket.service)
169 for(processingSocket = serverSocket.service.sockets.first;
171 processingSocket = (DCOMServerSocket)processingSocket.next)
173 next = processingSocket.next;
174 if(processingSocket.connected &&
175 processingSocket.thread.id == currentThreadID)
181 packet.type = (DCOMPacketType)htoled((DCOMPacketType)dcom_CallVirtualMethod);
183 packet.callID = callID;
184 packet.methodID = htoled(methodID);
185 packet.hasReturnValue = hasReturnValue;
186 packet.argsSize = htoled(argsBuffer.size);
187 argsBuffer.ReadData(packet.args, argsBuffer.size);
190 serverSocket.SendPacket(packet);
193 socket._refCount += 2;
195 processingSocket._refCount += 2;
201 if(!serverSocket || !serverSocket.connected || !serverSocket.thread)
203 if(ack = VirtualCallAcknowledged(methodID, id, callID))
208 if(processingSocket && processingSocket.connected)
209 processingSocket.ProcessTimeOut(0.01);
211 ecere::sys::Sleep(0.01);//serverSocket.thread.semaphore.Wait();
218 result = ack.overridden;
219 returnBuffer.WriteData(ack.buffer.buffer, ack.buffer.count);
226 if(socket._refCount > 1)
230 if(processingSocket && processingSocket._refCount > 1)
231 processingSocket._refCount--;
232 delete processingSocket;
243 DCOMServerSocket serverSocket;
245 SerialBuffer argsBuffer { };
246 SerialBuffer returnBuffer { };
247 List<VirtualCallAck> acks { };
251 nextCallID = GetRandom(1, 999999);//100;
259 #define GETLEDWORD(b) (uint32)(((b)[3] << 24) | ((b)[2] << 16) | ((b)[1] << 8) | (b)[0])
261 #define PUTLEDWORD(b, d) \
262 (b)[3] = (byte)(((d) >> 24) & 0xFF); \
263 (b)[2] = (byte)(((d) >> 16) & 0xFF); \
264 (b)[1] = (byte)(((d) >> 8) & 0xFF); \
265 (b)[0] = (byte)( (d) & 0xFF);
267 static uint32 htoled(uint32 value)
270 PUTLEDWORD((byte *)&result, value);
274 static uint32 letohd(uint32 value)
276 return GETLEDWORD((byte *)&value);
279 class DCOMServerThread : Thread
281 DCOMServerSocket socket;
282 Semaphore semaphore { };
290 socket.ProcessTimeOut(0.01);
292 socket.ProcessCalls();
301 class DCOMClientThread : Thread
304 Semaphore semaphore { };
308 socket._refCount += 2;
311 socket.ProcessTimeOut(0.01);
314 if(socket._refCount > 1) socket._refCount--;
320 /*static */public class DCOMServerSocket : Socket
323 DCOMServerObject * objects;
325 DCOMServerThread thread
327 socket = this, connected = true;
329 List<CallMethodPacket> calls { };
330 bool processingCalls;
334 CallMethodPacket callMethod;
335 Iterator <CallMethodPacket> it { calls };
340 if(!it.Next() || disconnected)
345 callMethod = it.data;
347 processingCalls = true;
350 if(callMethod.objectID < numObjects /*&& callMethod.methodID < numMethods*/)
352 DCOMServerObject object = objects[callMethod.objectID];
353 bool hasReturnValue = true;
354 MethodReturnedPacket packet;
356 SerialBuffer buffer { };
357 int methodID = callMethod.methodID;
358 int callID = callMethod.callID;
360 buffer.WriteData(callMethod.args, callMethod.argsSize);
364 size = (uint)&((MethodReturnedPacket)0).args;
365 packet = (MethodReturnedPacket)new0 byte[size];
366 packet.type = (DCOMPacketType)htoled((DCOMPacketType)dcom_MethodReturned);
368 packet.callID = callMethod.callID;
369 packet.methodID = callMethod.methodID;
376 // TOFIX: Hardcoded VTBL ID
377 ((void (*)(void *, uint, SerialBuffer))(void *)object._vTbl[10])(object, methodID, buffer);
381 size = (uint)&((MethodReturnedPacket)0).args + buffer.size; // sizeof(class MethodReturnedPacket) + buffer.size - 1;
382 packet = (MethodReturnedPacket)new0 byte[size];
383 packet.type = (DCOMPacketType)htoled((DCOMPacketType)dcom_MethodReturned);
385 packet.callID = callID;
386 packet.methodID = methodID;
387 packet.argsSize = htoled(buffer.size);
388 buffer.ReadData(packet.args, buffer.size);
394 if(object._refCount > 1)
399 processingCalls = false;
404 void OnReceivePacket(DCOMPacket packet)
407 switch((DCOMPacketType)letohd(packet.type))
409 case dcom_CreateInstance:
411 CreateInstancePacket createInstance = (CreateInstancePacket)packet;
412 Class _class = eSystem_FindClass(__thisModule.application, createInstance.className);
413 Class runClass = eSystem_FindClass(__thisModule.application, createInstance.className + 4);
414 DCOMServerObject object;
418 _class = eSystem_FindClass(runClass.module, createInstance.className);
420 objects = renew objects DCOMServerObject[numObjects+1];
421 object = objects[numObjects] = eInstance_New(_class);
423 object.serverSocket = this;
424 object.id = numObjects++;
425 object.instance = eInstance_New(runClass);
426 incref object.instance;
427 object.instance._vTbl = new void *[object.instance._class.vTblSize + 1];
428 object.instance._vTbl++;
429 object.instance._vTbl[-1] = (void *)object;
430 memcpy(object.instance._vTbl, object.instance._class._vTbl, sizeof(int(*)()) * object.instance._class.vTblSize);
431 for(vid = runClass.base.vTblSize; vid < runClass.vTblSize; vid++)
433 object.instance._vTbl[vid] = object._vTbl[vid - runClass.base.vTblSize + 11];
437 ObjectCreatedPacket sendPacket = ObjectCreatedPacket { };
438 sendPacket.type = (DCOMPacketType)htoled((DCOMPacketType)dcom_InstanceCreated);
439 sendPacket.size = sizeof(class ObjectCreatedPacket);
440 sendPacket.objectID = htoled(object.id);
441 SendPacket(sendPacket);
446 case dcom_CallMethod:
449 CallMethodPacket callMethod = (CallMethodPacket)packet;
450 callMethod.objectID = letohd(callMethod.objectID);
451 callMethod.argsSize = letohd(callMethod.argsSize);
453 p = (CallMethodPacket)new byte[callMethod.size];
454 memcpy(p, callMethod, callMethod.size);
459 case dcom_VirtualMethodReturned:
461 VirtualMethodReturnedPacket methodReturned = (VirtualMethodReturnedPacket)packet;
462 if(methodReturned.objectID < numObjects)
464 DCOMServerObject object = objects[methodReturned.objectID];
467 methodReturned.objectID,
468 methodReturned.methodID,
469 methodReturned.callID,
470 methodReturned.overridden
472 ack.buffer.WriteData(methodReturned.args, letohd(methodReturned.argsSize));
474 object.acks.Add(ack);
483 void OnDisconnect(int code)
487 thread.connected = false;
489 if(thread.started && GetCurrentThreadID() != 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() != thread.id)
545 bool result = Service::Start();
548 thread.connected = true;
557 DCOMServerSocket socket;
558 thread.connected = false;
559 result = Service::Stop();
560 if(thread.started && GetCurrentThreadID() != 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(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() == 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;
678 unsigned int size = (uint)&((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;
740 dllexport bool CallMethod(unsigned int methodID)
742 if(this && connected)
746 int callID = nextCallID++;
747 unsigned int size = (uint)&((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() == 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);
793 if(GetCurrentThreadID() != thread.id)
800 // A class to make set of things happen atomically
801 // e.g. to send a bunch of notifications all at once,
802 // without anything else happening in between
803 public class DCOMSendControl
809 while(sendingOut) guiApp.Unlock(), ecere::sys::Sleep(0.01), guiApp.Lock();