code: rename identifiers `with` since it is a keyword now
[nit.git] / lib / socket / socket.nit
index f0aaa85..681e239 100644 (file)
@@ -17,7 +17,7 @@
 # Socket services
 module socket
 
-import socket_c
+private import socket_c
 intrude import standard::stream
 
 # A general TCP socket, either a `TCPStream` or a `TCPServer`
@@ -41,9 +41,9 @@ end
 # Simple communication stream with a remote socket
 class TCPStream
        super Socket
-       super BufferedIStream
-       super OStream
-       super PollableIStream
+       super BufferedReader
+       super Writer
+       super PollableReader
 
        # Real canonical name of the host to which `self` is connected
        var host: String
@@ -66,7 +66,11 @@ class TCPStream
                        closed = true
                        return
                end
-               socket.setsockopt(new NativeSocketOptLevels.socket, new NativeSocketOptNames.reuseaddr, 1)
+               if not socket.setsockopt(new NativeSocketOptLevels.socket, new NativeSocketOptNames.reuseaddr, 1) then
+                       end_reached = true
+                       closed = true
+                       return
+               end
                var hostname = socket.gethostbyname(host)
                addrin = new NativeSocketAddrIn.with_hostent(hostname, port)
 
@@ -107,7 +111,7 @@ class TCPStream
        fun ready_to_read(timeout: Int): Bool
        do
                if _buffer_pos < _buffer.length then return true
-               if eof then return false
+               if end_reached then return false
                var events = [new NativeSocketPollValues.pollin]
                return pollin(events, timeout).length != 0
        end
@@ -168,9 +172,20 @@ class TCPStream
                if closed then return
                if socket.close >= 0 then
                        closed = true
+                       end_reached = true
                end
        end
 
+       # Send the data present in the socket buffer
+       fun flush
+       do
+               if not socket.setsockopt(new NativeSocketOptLevels.tcp, new NativeSocketOptNames.tcp_nodelay, 1) or
+                  not socket.setsockopt(new NativeSocketOptLevels.tcp, new NativeSocketOptNames.tcp_nodelay, 0) then
+                       closed = true
+               end
+       end
+end
+
 # A socket listening on a given `port` for incomming connections
 #
 # Create streams to communicate with clients using `accept`.
@@ -185,8 +200,11 @@ class TCPServer
                socket = new NativeSocket.socket(new NativeSocketAddressFamilies.af_inet,
                        new NativeSocketTypes.sock_stream, new NativeSocketProtocolFamilies.pf_null)
                assert not socket.address_is_null
-               socket.setsockopt(new NativeSocketOptLevels.socket, new NativeSocketOptNames.reuseaddr, 1)
-               addrin = new NativeSocketAddrIn.with(port, new NativeSocketAddressFamilies.af_inet)
+               if not socket.setsockopt(new NativeSocketOptLevels.socket, new NativeSocketOptNames.reuseaddr, 1) then
+                       closed = true
+                       return
+               end
+               addrin = new NativeSocketAddrIn.with_port(port, new NativeSocketAddressFamilies.af_inet)
                address = addrin.address
 
                # Bind it
@@ -222,6 +240,14 @@ class TCPServer
                return new TCPStream.server_side(native)
        end
 
+       # Set whether calls to `accept` are blocking
+       fun blocking=(value: Bool)
+       do
+               # We use the opposite from the native version as the native API
+               # is closer to the C API. In the Nity API, we use a positive version
+               # of the name.
+               socket.non_blocking = not value
+       end
 
        # Close this socket
        fun close
@@ -235,30 +261,48 @@ class TCPServer
        end
 end
 
+# A simple set of sockets used by `SocketObserver`
 class SocketSet
-       var sset = new NativeSocketSet
-       fun set(s: TCPSocket) do sset.set(s.socket) end
-       fun is_set(s: TCPSocket): Bool do return sset.is_set(s.socket) end
-       fun zero do sset.zero end
-       fun clear(s: TCPSocket) do sset.clear(s.socket) end
+       private var native = new NativeSocketSet
+
+       init do clear
+
+       # Add `socket` to this set
+       fun add(socket: Socket) do native.set(socket.socket)
+
+       # Remove `socket` from this set
+       fun remove(socket: Socket) do native.clear(socket.socket)
+
+       # Does this set has `socket`?
+       fun has(socket: Socket): Bool do return native.is_set(socket.socket)
+
+       # Clear all sockets from this set
+       fun clear do native.zero
 end
 
+# Service class to manage calls to `select`
 class SocketObserver
-       private var observer: NativeSocketObserver
-       var readset: nullable SocketSet = null
-       var writeset: nullable SocketSet = null
-       var exceptset: nullable SocketSet = null
-       init(read :Bool, write :Bool, except: Bool)
-       do
-               if read then readset = new SocketSet
-               if write then writeset = new SocketSet
-               if except then exceptset = new SocketSet
-               observer = new NativeSocketObserver
+       private var native = new NativeSocketObserver
+
+       var read_set: nullable SocketSet = null
+
+       var write_set: nullable SocketSet = null
+
+       var except_set: nullable SocketSet = null
+
+       init(read: Bool, write: Bool, except: Bool)
+       is old_style_init do
+               if read then read_set = new SocketSet
+               if write then write_set = new SocketSet
+               if except then except_set = new SocketSet
        end
-       fun select(max: TCPSocket, seconds: Int, microseconds: Int): Bool
+
+       fun select(max: Socket, seconds: Int, microseconds: Int): Bool
        do
+               # FIXME this implementation (see the call to nullable attributes below) and
+               # `NativeSockectObserver::select` is not stable.
+
                var timeval = new NativeTimeval(seconds, microseconds)
-               return observer.select(max.socket, readset.sset, writeset.sset, readset.sset, timeval) > 0
+               return native.select(max.socket, read_set.native, write_set.native, except_set.native, timeval) > 0
        end
 end
-