ecere/net; compiler/ecs: Distributed Objects Improvements
[sdk] / ecere / src / net / Socket.ec
index 9ee128d..96b25cf 100644 (file)
@@ -1,3 +1,5 @@
+#define _Noreturn
+
 namespace net;
 
 #include <stdarg.h>
@@ -5,12 +7,15 @@ namespace net;
 #if defined(__WIN32__)
 
 #define WIN32_LEAN_AND_MEAN
+#define String _String
 #include <winsock.h>
-static WSADATA wsaData;
+#undef String
+#define SOCKLEN_TYPE int
 
 #elif defined(__unix__) || defined(__APPLE__)
 
 default:
+#define SOCKLEN_TYPE socklen_t
 #define set _set
 #define uint _uint
 #include <sys/time.h>
@@ -56,9 +61,9 @@ public:
 };
 
 static class SocketConnectThread : Thread
-{  
+{
    Socket socket;
-   
+
    uint Main()
    {
       bool result = false;
@@ -76,10 +81,10 @@ static class SocketConnectThread : Thread
             {
                network.mutex.Wait();
                strcpy(socket.inetAddress, inet_ntoa(socket.a.sin_addr));
-               socket.inetPort = ntohs(socket.a.sin_port); 
+               socket.inetPort = ntohs(socket.a.sin_port);
                network.mutex.Release();
 
-               if(socket.OnEstablishConnection(socket.s))
+               if(socket.OnEstablishConnection((int)socket.s))
                {
                   network.mutex.Wait();
                   result = true;
@@ -105,7 +110,7 @@ static class SocketConnectThread : Thread
    #endif
       if(result && !socket.destroyed)
          socket._connected = 1;
-      else
+      else if(socket._connected == -2)
          socket._connected = -1;
 
    #ifdef DEBUG_SOCKETS
@@ -131,8 +136,8 @@ public:
          {
             SOCKET s;
             SOCKADDR_IN a;
-            int addrLen = sizeof(a);
-            
+            SOCKLEN_TYPE addrLen = sizeof(a);
+
             value.accepted = true;
             s = accept(value.s,(SOCKADDR *)&a, &addrLen);
             if(s != -1)
@@ -152,7 +157,7 @@ public:
                address = null;
                this.a = a;
                strcpy(inetAddress, inet_ntoa(this.a.sin_addr));
-               inetPort = ntohs(a.sin_port); 
+               inetPort = ntohs(a.sin_port);
                this.s = s;
                service = value;
                connectThread = null;
@@ -162,9 +167,9 @@ public:
                network.mutex.Wait();
                FD_SET(s, &network.exceptSet);
                FD_SET(s, &network.readSet);
-               if(s >= network.ns) 
+               if(s >= network.ns)
                {
-                  network.ns = s+1;
+                  network.ns = (int)(s+1);
                   network.socketsSemaphore.Release();
                }
                network.mutex.Release();
@@ -178,7 +183,7 @@ public:
       get { return this ? service : null; }
    };
 
-   property char * inetAddress { get { return (char *)inetAddress; } };
+   property const char * inetAddress { get { return (char *)inetAddress; } };
    property int inetPort { get { return inetPort; } }
    property Socket next { get { return next; } };
    property bool connected { get { return _connected == 1 || _connected == -2; } };
@@ -208,7 +213,7 @@ public:
             OnReceivePacket(packet);
             delete tempBuffer;
             return 0;
-         }                   
+         }
       }
       return 0;
    }
@@ -216,7 +221,7 @@ public:
    virtual void OnDisconnect(int code);
    virtual void OnReceivePacket(Packet packet);
 
-   bool Connect(char * address, int port)
+   bool Connect(const char * address, int port)
    {
       bool result = false;
    #if defined(__WIN32__) || defined(__unix__) || defined(__APPLE__)
@@ -249,11 +254,20 @@ public:
 
          if(!disconnected)
          {
+            if(_connected == -2 && connectThread)
+            {
+               incref this;
+               network.mutex.Release();
+               connectThread.Wait();
+               delete connectThread;
+               network.mutex.Wait();
+               _refCount--;
+            }
             disconnected = true;
             if(!service)
             {
                if(_connected)
-                  ((_connected == -1) ? network.connectSockets : network.sockets).Remove(this);
+                  ((_connected == -1 || _connected == -2) ? network.connectSockets : network.sockets).Remove(this);
             }
             else
             {
@@ -268,7 +282,7 @@ public:
 
          if(s == network.ns - 1)
             Network_DetermineMaxSocket();
-      
+
          if(s != -1)
          {
             FD_CLR(s, &network.readSet);
@@ -293,17 +307,19 @@ public:
    }
 
    // --- Transfer ---
-   bool Send(void * buffer, int size)
+   bool Send(const void * buffer, int size)
    {
    #if defined(__WIN32__) || defined(__unix__) || defined(__APPLE__)
       if(this)
       {
+         safeIncRef();
+         {
          SOCKET s = this.s;
          int count;
          fd_set ws, es;
 
          if(s != -1 && ((type == tcp && (count = SendData(buffer, size, 0))) ||
-            (type == udp && (count = sendto(s, buffer, size,0, (SOCKADDR *)&a, sizeof(a))))))
+            (type == udp && (count = (int)sendto(s, buffer, size,0, (SOCKADDR *)&a, sizeof(a))))))
          {
    #if defined(__WIN32__)
             int error = WSAGetLastError();
@@ -317,12 +333,16 @@ public:
    #endif
             {
                //Print("~");
-            }               
+            }
 
             // This is what was making eCom jam...
             // select(s+1, null, &ws, &es, null);
+
+            safeDecRef();
             return true;
          }
+         }
+         safeDecRef();
       }
    #endif
       return false;
@@ -342,12 +362,12 @@ public:
       return false;
    }
 
-   bool SendString(char * string)
+   bool SendString(const char * string)
    {
-      return Send(string, strlen(string));
+      return Send(string, (int)strlen(string));
    }
 
-   bool Sendf(char * format, ...)
+   bool Sendf(const char * format, ...)
    {
       bool result;
       va_list args;
@@ -355,12 +375,12 @@ public:
       va_start(args, format);
       vsnprintf(string, sizeof(string), format, args);
       string[sizeof(string)-1] = 0;
-      result = Send(string, strlen(string));
+      result = Send(string, (int)strlen(string));
       va_end(args);
       return result;
    }
 
-   bool DatagramConnect(char * sendAddress, int port)
+   bool DatagramConnect(const char * sendAddress, int port)
    {
       SOCKET s = socket(AF_INET,SOCK_DGRAM,0);
       if(s != -1)
@@ -375,7 +395,7 @@ public:
    bool DatagramHost(int port)
    {
       SOCKET s = socket(AF_INET,SOCK_DGRAM,0);
-      if(s != -1)
+      if(s != -1 && !_connected)
       {
          SOCKADDR_IN a;
          bool val = true;
@@ -397,9 +417,9 @@ public:
             FD_CLR(s, &network.writeSet);
             FD_SET(s, &network.readSet);
             FD_SET(s, &network.exceptSet);
-            if(s >= network.ns) 
+            if(s >= network.ns)
             {
-               network.ns = s+1;
+               network.ns = (int)(s+1);
                network.socketsSemaphore.Release();
             }
             network.mutex.Release();
@@ -412,14 +432,29 @@ public:
 
    virtual int ReceiveData(byte * buffer, int count, uint flags)
    {
-      return (int)recv(s, buffer, count, flags);
+      return (int)recv(s, (char *)buffer, count, flags);
    }
-   virtual int SendData(byte * buffer, int count, uint flags)
+   virtual int SendData(const byte * buffer, int count, uint flags)
    {
-      return (int)send(s, buffer, count, flags);
+      return (int)send(s, (const char *)buffer, count, flags);
    }
    virtual bool OnEstablishConnection(int s);
 
+   dllexport void safeIncRef()
+   {
+      mutex.Wait();
+      incref this;
+      //mutex.Release();
+   }
+
+   dllexport void safeDecRef()
+   {
+      Mutex mutex = this.mutex;
+      //mutex.Wait();
+      delete this;
+      mutex.Release();
+   }
+
 private:
    Socket()
    {
@@ -440,9 +475,10 @@ private:
       SOCKET s = this.s;
 
       if(mustLock) network.mutex.Wait();
+
       if(!service && _connected)
       {
-         (_connected == -1 ? network.connectSockets : network.sockets).Remove(this);
+         ((_connected == -1 || _connected == -2) ? network.connectSockets : network.sockets).Remove(this);
          _connected = 0;
       }
 
@@ -463,16 +499,16 @@ private:
          service = null;
          _connected = 0;
       }
-      
+
       if(s != -1) { closesocket(s); this.s = -1; }
 
       delete address;
-      delete recvBuffer; 
+      delete recvBuffer;
 
       recvBufferSize = 0;
       recvBytes = 0;
 
-      if(s != -1) 
+      if(s != -1)
       {
          FD_CLR(s, &network.readSet);
          FD_CLR(s, &network.writeSet);
@@ -502,7 +538,7 @@ private:
       network.mutex.Release();
    }
 
-   bool _Connect(SOCKET s, char * address, int port)
+   bool _Connect(SOCKET s, const char * address, int port)
    {
       bool result = false;
       if(this)
@@ -528,9 +564,9 @@ private:
          _connected = -2;
 
          FD_SET(s, &network.writeSet);
-         if(s >= network.ns && !processAlone) 
+         if(s >= network.ns && !processAlone)
          {
-            network.ns = s+1;
+            network.ns = (int)(s+1);
             network.socketsSemaphore.Release();
          }
          connectThread = SocketConnectThread { socket = this };
@@ -546,7 +582,7 @@ private:
             if(_connected == -1 || destroyed)
             {
                _connected = 0;
-               
+
                if(s == network.ns - 1)
                   Network_DetermineMaxSocket();
 #if 0
@@ -569,7 +605,7 @@ private:
             }
             else
                this.s = -1;
-            
+
             delete connectThread;
          }
          else
@@ -593,9 +629,10 @@ private:
    {
       bool result = false;
       SOCKET s;
+      Mutex mutex = this.mutex;
 
-      incref this;
       mutex.Wait();
+      incref this;
       // network.mutex.Wait();
       s = this.s;
       if(FD_ISSET(s, rs) || leftOver)
@@ -603,20 +640,20 @@ private:
          int count = 0;
 
          result = true;
-         if(recvBufferSize - recvBytes < MAX_RECEIVE)
+         if((int)recvBufferSize - recvBytes < MAX_RECEIVE)
          {
             recvBuffer = renew recvBuffer byte[recvBufferSize + MAX_RECEIVE];
             recvBufferSize += MAX_RECEIVE;
          }
-           
+
          if(FD_ISSET(s, rs) && disconnectCode == (DisconnectCode)-1)
          {
             if(type == tcp /*|| _connected*/)
                count = ReceiveData(recvBuffer + recvBytes, recvBufferSize - recvBytes, 0);
             else
             {
-               int len = sizeof(a);
-               count = recvfrom(s, recvBuffer + recvBytes, 
+               SOCKLEN_TYPE len = sizeof(a);
+               count = (int)recvfrom(s, (char *)recvBuffer + recvBytes,
                   recvBufferSize - recvBytes, 0, (SOCKADDR *)&a, &len);
                strcpy(inetAddress, inet_ntoa(this.a.sin_addr));
                inetPort = ntohs((uint16)a.sin_port);
@@ -646,7 +683,8 @@ private:
                uint recvCount = OnReceive(recvBuffer + flushCount, recvBytes - flushCount);
                if(!recvCount)
                {
-                  leftOver = true;
+                  if(recvBytes)
+                     leftOver = true;
                   if(!processAlone)
                      network.leftOverBytes = true;
                   break;
@@ -694,16 +732,16 @@ private:
             _Disconnect(disconnectCode);
       }
       // network.mutex.Release();
+      delete this;
       mutex.Release();
 
-      delete this;
       return result;
    }
 #endif
 
    public bool Process()
    {
-      ProcessTimeOut(0);
+      return ProcessTimeOut(0);
    }
 
    public bool ProcessTimeOut(Seconds timeOut)
@@ -713,8 +751,9 @@ private:
       struct timeval tvTO = {(uint)timeOut, (uint)((timeOut -(uint)timeOut)* 1000000)};
       fd_set rs, ws, es;
       int selectResult;
+      Mutex mutex;
 
-      if(disconnectCode > 0) return false;
+      if(disconnectCode > 0 && !leftOver) return false;
       FD_ZERO(&rs);
       FD_ZERO(&ws);
       FD_ZERO(&es);
@@ -722,12 +761,18 @@ private:
       //FD_SET(s, &ws);
       FD_SET(s, &es);
 
-      selectResult = select(s+1, &rs, &ws, &es, leftOver ? &tv : (timeOut ? &tvTO : null));
+      mutex = this.mutex;
       mutex.Wait();
+      incref this;
+      mutex.Release();
+      selectResult = select((int)(s+1), &rs, &ws, &es, leftOver ? &tv : (timeOut ? &tvTO : null));
+
       if(s != -1 && _refCount && (leftOver || selectResult))
       {
          gotEvent |= ProcessSocket(&rs, &ws, &es);
       }
+      mutex.Wait();
+      delete this;
       mutex.Release();
       return gotEvent;
    }
@@ -745,7 +790,7 @@ private:
    Thread connectThread;
    DisconnectCode disconnectCode;
    bool destroyed;
-   int _connected;
+   int _connected;         // -2: Initial value when calling Connect(), -1: Disconnected or otherwise destroyed while connecting, 1: succesfully connected, 0: no longer in any connect/sockets list
    bool disconnected;
 
    // Receiving Buffer