ecere: Initial Emscripten support
[sdk] / ecere / src / net / Socket.ec
index 7dbb520..141ce11 100644 (file)
@@ -1,3 +1,5 @@
+#define _Noreturn
+
 namespace net;
 
 #include <stdarg.h>
@@ -5,12 +7,16 @@ 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>
 #include <unistd.h>
@@ -22,6 +28,7 @@ default:
 #include <sys/types.h>
 #include <sys/time.h>
 #include <arpa/inet.h>
+#undef set
 #undef uint
 private:
 
@@ -36,6 +43,14 @@ typedef struct in_addr IN_ADDR;
 
 import "network"
 
+#ifdef __ANDROID__
+// TOFIX:
+#undef ntohs
+#undef htons
+#define ntohs(x) (x)
+#define htons(x) (x)
+#endif
+
 #define GETLEDWORD(b) (uint32)(((b)[3] << 24) | ((b)[2] << 16) | ((b)[1] << 8) | (b)[0])
 
 #define PUTLEDWORD(b, d) \
@@ -54,9 +69,9 @@ public:
 };
 
 static class SocketConnectThread : Thread
-{  
+{
    Socket socket;
-   
+
    uint Main()
    {
       bool result = false;
@@ -74,10 +89,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;
@@ -103,7 +118,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
@@ -129,8 +144,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)
@@ -150,7 +165,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;
@@ -160,9 +175,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();
@@ -176,7 +191,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; } };
@@ -191,14 +206,22 @@ public:
          uint size = GETLEDWORD((byte *)&packet.size);
          if(count >= size)
          {
+            byte * tempBuffer = null;
             if(size)
             {
-               CopyBytes(recvBuffer, recvBuffer + size, recvBytes - size);
+               if(recvBytes - size)
+               {
+                  tempBuffer = new byte[size];
+                  packet = (Packet)tempBuffer;
+                  memcpy(tempBuffer, buffer, size);
+                  memmove(recvBuffer, recvBuffer + size, recvBytes - size);
+               }
                recvBytes -= size;
             }
             OnReceivePacket(packet);
+            delete tempBuffer;
             return 0;
-         }                   
+         }
       }
       return 0;
    }
@@ -206,7 +229,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__)
@@ -239,19 +262,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 == -1/* != 1*/)
-               {
-                  network.connectSockets.Remove(this);
-                  _connected = 0;
-               }
-               else if(_connected)
-               {
-                  network.sockets.Remove(this);
-                  _connected = 0;
-               }
+               if(_connected)
+                  ((_connected == -1 || _connected == -2) ? network.connectSockets : network.sockets).Remove(this);
             }
             else
             {
@@ -266,7 +290,7 @@ public:
 
          if(s == network.ns - 1)
             Network_DetermineMaxSocket();
-      
+
          if(s != -1)
          {
             FD_CLR(s, &network.readSet);
@@ -279,18 +303,19 @@ public:
          //if(_refCount > 1)
          /*if(_refCount >= 1)
             _refCount--;*/
-         network.mutex.Release();
 
          shutdown(s, 2);
 
          if(!wasDisconnected)
             delete this;
+
+         network.mutex.Release();
    #endif
       }
    }
 
    // --- Transfer ---
-   bool Send(void * buffer, int size)
+   bool Send(const void * buffer, int size)
    {
    #if defined(__WIN32__) || defined(__unix__) || defined(__APPLE__)
       if(this)
@@ -300,7 +325,7 @@ public:
          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();
@@ -314,7 +339,7 @@ public:
    #endif
             {
                //Print("~");
-            }               
+            }
 
             // This is what was making eCom jam...
             // select(s+1, null, &ws, &es, null);
@@ -339,24 +364,25 @@ 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;
       char string[MAX_F_STRING];
       va_start(args, format);
-      vsprintf(string,format,args);
-      result = Send(string, strlen(string));
+      vsnprintf(string, sizeof(string), format, args);
+      string[sizeof(string)-1] = 0;
+      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)
@@ -371,7 +397,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;
@@ -393,9 +419,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();
@@ -408,11 +434,11 @@ 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);
 
@@ -426,28 +452,21 @@ private:
    ~Socket()
    {
       _refCount = MAXINT;
-      Free();
+      Free(true);
       _refCount = 0;
    }
 
 #ifndef ECERE_NONET
-   void Free()
+   void Free(bool mustLock)
    {
       SOCKET s = this.s;
 
-      network.mutex.Wait();
-      if(!service)
+      if(mustLock) network.mutex.Wait();
+
+      if(!service && _connected)
       {
-         if(_connected == -1/* != 1*/)
-         {
-            network.connectSockets.Remove(this);
-            _connected = 0;
-         }
-         else if(_connected)
-         {
-            network.sockets.Remove(this);
-            _connected = 0;
-         }
+         ((_connected == -1 || _connected == -2) ? network.connectSockets : network.sockets).Remove(this);
+         _connected = 0;
       }
 
       if(!disconnected)
@@ -467,16 +486,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);
@@ -488,7 +507,7 @@ private:
       // COMMENTED THIS OUT SINCE IT WAS INVALIDATING PROTECTION FOR HTTP FILE CONNECTION REUSE...
       // WATCH FOR LEAKS IN OTHER PROJECTS?
       //if(_refCount > 1) _refCount--;
-      network.mutex.Release();
+      if(mustLock) network.mutex.Release();
    }
 
    void _Disconnect(DisconnectCode code)
@@ -497,7 +516,8 @@ private:
       network.mutex.Wait();
 
       disconnectCode = code;
-      Free();
+
+      Free(false);
       delete this;
 
       if(s == network.ns - 1)
@@ -505,7 +525,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)
@@ -531,9 +551,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 };
@@ -549,7 +569,7 @@ private:
             if(_connected == -1 || destroyed)
             {
                _connected = 0;
-               
+
                if(s == network.ns - 1)
                   Network_DetermineMaxSocket();
 #if 0
@@ -572,7 +592,7 @@ private:
             }
             else
                this.s = -1;
-            
+
             delete connectThread;
          }
          else
@@ -606,20 +626,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);
@@ -639,7 +659,7 @@ private:
             }
          }
 
-         if(count > 0 || leftOver)
+         if(count > 0 || (leftOver && !count))
          {
             uint flushCount;
             leftOver = false;
@@ -661,7 +681,7 @@ private:
             {
                if(flushCount)
                {
-                  CopyBytes(recvBuffer, recvBuffer + flushCount, recvBytes - flushCount);
+                  memmove(recvBuffer, recvBuffer + flushCount, recvBytes - flushCount);
                   recvBytes -= flushCount;
                }
                else
@@ -706,12 +726,18 @@ private:
 
    public bool Process()
    {
+      return ProcessTimeOut(0);
+   }
+
+   public bool ProcessTimeOut(Seconds timeOut)
+   {
       bool gotEvent = false;
       struct timeval tv = {0, 0};
+      struct timeval tvTO = {(uint)timeOut, (uint)((timeOut -(uint)timeOut)* 1000000)};
       fd_set rs, ws, es;
       int selectResult;
 
-      if(disconnectCode > 0) return false;
+      if(disconnectCode > 0 && !leftOver) return false;
       FD_ZERO(&rs);
       FD_ZERO(&ws);
       FD_ZERO(&es);
@@ -719,13 +745,15 @@ private:
       //FD_SET(s, &ws);
       FD_SET(s, &es);
 
-      selectResult = select(s+1, &rs, &ws, &es, leftOver ? &tv : null);
+      incref this;
+      selectResult = select((int)(s+1), &rs, &ws, &es, leftOver ? &tv : (timeOut ? &tvTO : null));
       mutex.Wait();
       if(s != -1 && _refCount && (leftOver || selectResult))
       {
          gotEvent |= ProcessSocket(&rs, &ws, &es);
       }
       mutex.Release();
+      delete this;
       return gotEvent;
    }
 
@@ -742,7 +770,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