    #ifndef __SNC_BI__
    #define __SNC_BI__
    ' file: snc.bi [S]imple [N]etwork [C]onnection
    ' needs uptodate include files.
    ' see at: http://www.freebasic.net/forum/viewtopic.php?f=7&t=23421


    #ifdef __FB_WIN32__
     #include "windows.bi"
     #include "win/windef.bi"
     #include "win/winsock2.bi"
     #ifndef opensocket
     #define opensocket socket
     #endif
    #else
     #include "crt/unistd.bi"     ' close_ ...
     #include "crt/netinet/in.bi" ' socket.bi ...
     #include "crt/sys/select.bi" ' FD_SET ...
     #include "crt/netdb.bi"      ' hostent ...
     #include "crt/arpa/inet.bi"  ' inet_ntoa ...
    #endif

    ' User-settable options (used with setsockopt).
    #ifndef TCP_NODELAY ' "tcp.bi" does not exists
     #define TCP_NODELAY &H01 ' don't delay send to coalesce packets
    #endif

    enum NETWORK_ERROR
      ERROR_NO_ERROR = 0
      ' connection
      ERROR_DISCONNECTED
      ERROR_PUT
      ERROR_GET
      ' socket
      ERROR_SOCKET
      ERROR_SETSOCKOPT
      ERROR_SELECT
      ' client
      ERROR_CONNECT
      ERROR_RESOLVE
      ' server
      ERROR_BIND
      ERROR_LISTEN
      ERROR_ACCEPT
    end enum

    function GetNetworkErrorText(byval errorcode as NETWORK_ERROR) as string
      select case as const errorcode
      case ERROR_NO_ERROR     : return "no error !"
      ' connection
      case ERROR_PUT          : return "error: put data !"
      case ERROR_GET          : return "error: get data !"
      case ERROR_DISCONNECTED : return "error: disconnected !"
      ' socket
      case ERROR_SOCKET       : return "error: socket !"
      case ERROR_SETSOCKOPT   : return "error: setsockopt !"
      case ERROR_SELECT       : return "error: select !"
      ' client
      case ERROR_CONNECT      : return "error: client connect !"
      case ERROR_RESOLVE      : return "error: client resolve IP"
      ' server
      case ERROR_BIND         : return "error: server bind() !"
      case ERROR_LISTEN       : return "error: server listen() !"
      case ERROR_ACCEPT       : return "error: server accept() !"
      case else               : return "roor: " & errorcode & " unknow !"
      end select
    end function


    sub NetworkInit
      #ifdef __FB_WIN32__
      static as integer IsInit=0
      if IsInit=0 then
        dim as WSAData wd
        WSAStartup(WINSOCK_VERSION, @wd)
        IsInit=1
      end if
      #endif
    end sub

    sub Network_Exit()
      #ifdef __FB_WIN32__
      WSACleanup()
      #endif
    end sub


    ' A NetworkConnection has to be constructed with a server or a client.
    ' You can send and receive any data to/from your peer with it.
    type NetworkConnection
      public:
      declare constructor (byval sock as long)
      declare destructor
      ' returns 1 you can send data
      ' returns  0 not ATM. try again
      ' returns -1 as error signal
      declare function CanPut() as integer
      ' returns 1 you can get data
      ' returns -1 as error signal
      declare function CanGet() as integer
      ' Sends a any data note: if you send a string dataSize=len(txt)+1
      ' returns number of sended data
      ' returns -1 as error signal
      declare function PutData(byval pData as any ptr,byval dataSize as integer) as integer
      ' Receives any data (pData will be reallocated)
      ' returns received number of bytes
      ' returns  0 if other connection are closed
      ' returns -1 as error signal
      declare function GetData(byref pData as any ptr) as integer
      declare function GetLastError as NETWORK_ERROR
      protected:
      as long sock
      as any ptr pInData
      as fd_set read_fds, write_fds
      as timeval timeout
      as NETWORK_ERROR lastError
    end type

    constructor NetworkConnection(byval sock as long)
      this.sock = sock
      if this.sock<>-1 then
        'dim as long tmp = 1
        'if setsockopt(this.sock, IPPROTO_TCP, TCP_NODELAY,cptr(const zstring ptr,@tmp), sizeof(long))=-1 then
        '  lasterror=ERROR_SETSOCKOPT
        'end if
      else
        lasterror=ERROR_SOCKET
      end if
    end constructor

    function NetworkConnection.GetLastError as NETWORK_ERROR
      return lasterror
    end function

    destructor NetworkConnection
      if sock<>-1 then
        closesocket(sock)
        sock=-1
      end if
    end destructor

    function NetworkConnection.CanPut as integer
      if sock<0 then lasterror=ERROR_SOCKET:return -1
      FD_ZERO(@write_fds)
      FD_SET_(sock, @write_fds)
      if select_(sock + 1, 0, @write_fds, 0, @timeout) = -1 then
        lasterror=ERROR_SELECT
        return -1
      end if
      return iif(FD_ISSET(sock, @write_fds),1,0)
    end function

    function NetworkConnection.PutData(byval pData as any ptr,byval dataSize as integer) as integer
      if sock<0     then lasterror=ERROR_SOCKET:return -1
      if pData=0    then lasterror=ERROR_PUT:return -1
      if dataSize<1 then lasterror=ERROR_PUT:return -1
      dim as integer size,dSize=dataSize
      ' as long as not all data has been sent
      while (size<dataSize)
        dim as integer nBytes = send(sock,pData,dSize, 0)
        if nBytes<0 then lasterror=ERROR_PUT:return -1
        pData+=nBytes:dSize-=nBytes
        size+=nBytes
      wend
      return size
    end function

    function NetworkConnection.CanGet as integer
      if sock<0 then lasterror=ERROR_SOCKET:return -1
      FD_ZERO(@read_fds)
      FD_SET_(sock, @read_fds)
      if select_(sock + 1, @read_fds, 0, 0, @timeout) = -1 then
        lasterror=ERROR_SELECT
        return -1
      end if
      return iif(FD_ISSET(sock, @read_fds),1,0)
    end function

    function NetworkConnection.GetData(byref pData as any ptr) as integer
      const CHUNK_SIZE=1024*8
      static as ubyte chunk(CHUNK_SIZE-1)
      if sock<0 then lasterror=ERROR_SOCKET:return -1
      dim as integer dSize
      if pData then deallocate pData:pData=0
      do
        dim as integer nBytes = recv(sock,@chunk(0),CHUNK_SIZE, 0)
        if nBytes=0 then
          if dSize=0 then
            lasterror=ERROR_DISCONNECTED
            return -1
          end if
          exit do
        end if
        if nBytes<0 then
          lasterror=ERROR_GET
          return -1
        end if
        pData=reallocate(pData,dSize+nBytes)
        dim as ubyte ptr pWrite=pData+dSize
        for i as integer=0 to nBytes-1
          pWrite[i]=chunk(i)
        next
        dSize+=nBytes
        dim as integer try=100
        sleep 20
        while CanGet()=0 andalso try>0
          sleep 10:try-=1
        wend
        if try=0 then exit do
      loop
      return dSize
    end function


    ' constructing NetworkConnection pointers
    type ConnectionFactoy extends object
      public:
      declare constructor
      declare virtual destructor
      ' return a connection If returns NULL, there is no connection available.
      declare abstract function GetConnection() as NetworkConnection ptr
      declare virtual function GetLastError as NETWORK_ERROR
      protected:
      as long sock
      as fd_set read_fd
      as sockaddr_in addr
      as NETWORK_ERROR lastError
    end type


    constructor ConnectionFactoy
      NetworkInit
      sock = opensocket(AF_INET, SOCK_STREAM, 0)
      if sock=-1 then lasterror=ERROR_SOCKET
    end constructor

    destructor ConnectionFactoy
      if sock<>-1 then
        closesocket(sock)
        sock=-1
      end if
    end destructor

    virtual function ConnectionFactoy.GetLastError as NETWORK_ERROR
      return lasterror
    end function

    ' Constructs connection to server
    type NetworkClient extends ConnectionFactoy
      public:
      ' Initialized with the server address and the destination port
      declare constructor (address as string,byval port as ushort)
      ' Returns a connection to the server
      declare virtual function GetConnection() as NetworkConnection ptr
      declare virtual function GetLastError as NETWORK_ERROR
    end type


    '  connection_maker(port)
    constructor NetworkClient(address as string,byval port as ushort)
      base()
      if port=-1 then
        LastError = ERROR_SOCKET
        return
      end if
      ' server address
      dim as hostent ptr he =gethostbyname(strptr(address))
      if (he=0) then
        LastError = ERROR_RESOLVE
        return
      end if
      addr.sin_family = AF_INET
      addr.sin_port = htons(port)
      addr.sin_addr = *cptr(in_addr ptr,he->h_addr_list[0])
      if connect(sock,cptr(sockaddr ptr,@addr), sizeof(sockaddr))< 0 then
        LastError = ERROR_CONNECT
      end if
    end constructor

    virtual function NetworkClient.GetConnection() as NetworkConnection ptr
      return new NetworkConnection(sock)
    end function

    virtual function NetworkClient.GetLastError as NETWORK_ERROR
      return lasterror
    end function

    ' Constructs connections to clients
    type NetworkServer extends ConnectionFactoy
      public:
      ' Opens connection possibility on port for maxConnections clients
      declare constructor (byval port as ushort,byval maxConnections as integer=64)
      ' Returns a connection to a connecting client
      declare virtual function GetConnection() as NetworkConnection ptr
      declare virtual function GetLastError as NETWORK_ERROR
      private:
      as timeval timeout
    end type

    constructor NetworkServer(byval port as ushort,byval maxConnections as integer)
      base()
      if port=-1 then
        LastError = ERROR_SOCKET
        return
      end if
      addr.sin_family = AF_INET
      addr.sin_port = htons(port)
      addr.sin_addr.s_addr = INADDR_ANY
      if bind(sock, cptr(sockaddr ptr,@addr), sizeof(sockaddr)) = -1 then
        lasterror=ERROR_BIND
      elseif listen(sock, maxConnections) = -1 then
        lasterror=ERROR_LISTEN
      end if
    end constructor

    virtual function NetworkServer.GetConnection() as NetworkConnection ptr
      FD_ZERO(@read_fd)
      FD_SET_(sock, @read_fd)
     
      if select_(sock + 1, @read_fd, 0, 0, @timeout) = -1 then
        lasterror=ERROR_SELECT
        return 0
      end if

      if FD_ISSET(sock, @read_fd) then
        dim as long clientsock = accept(sock, 0, 0)
        if clientsock=-1 then
          lasterror = ERROR_ACCEPT
          return 0
        end if
        return new NetworkConnection(clientsock)
      else
        return 0
      end if
    end function

    virtual function NetworkServer.GetLastError as NETWORK_ERROR
      return lasterror
    end function
    #endif '__SNC_BI__