X-Git-Url: http://nitlanguage.org diff --git a/lib/socket/socket.nit b/lib/socket/socket.nit index f0aaa85..681e239 100644 --- a/lib/socket/socket.nit +++ b/lib/socket/socket.nit @@ -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 -