lib/socket: Socket now subclass of BufferedIStream and OStream
authorLucas Bajolet <r4pass@hotmail.com>
Fri, 2 May 2014 19:04:58 +0000 (15:04 -0400)
committerLucas Bajolet <r4pass@hotmail.com>
Fri, 2 May 2014 19:04:58 +0000 (15:04 -0400)
Signed-off-by: Lucas Bajolet <r4pass@hotmail.com>

examples/socket_client.nit
examples/socket_server.nit
lib/mpd.nit
lib/socket/socket.nit

index d7659e7..d9ac5ff 100644 (file)
@@ -26,10 +26,13 @@ end
 
 var s = new Socket.stream_with_host(args[0], args[1].to_i)
 print "[HOST ADDRESS] : {s.address}"
-print "[HOST] : {s.host.as(not null)}"
-print "[PORT] : {s.port.to_s}"
-print "Connecting ... {s.connect.to_s}"
-print "Writing ... {s.write("Hello server !").to_s}"
-print "[Response from server] : {s.read.to_s}"
-print "Closing ... {s.close.to_s}"
-
+print "[HOST] : {s.host}"
+print "[PORT] : {s.port}"
+print "Connecting ... {s.connected}"
+if s.connected then
+       print "Writing ... Hello server !"
+       s.write("Hello server !")
+       print "[Response from server] : {s.read(100)}"
+       print "Closing ..."
+       s.close
+end
index 9df9d79..8754ce2 100644 (file)
@@ -26,8 +26,6 @@ end
 
 var socket = new Socket.stream_with_port(args[0].to_i)
 print "[PORT] : {socket.port.to_s}"
-print "Binding ... {socket.bind.to_s}"
-print "Listening ... {socket.listen(3).to_s}"
 
 var clients = new Array[Socket]
 var max = socket
@@ -45,9 +43,10 @@ loop
        if fs.readset.is_set(socket) then
                var ns = socket.accept
                print "Accepting {ns.address} ... "
-               print "[Message from {ns.address}] : {ns.read}"
+               print "[Message from {ns.address}] : {ns.read(100)}"
                ns.write("Goodbye client.")
-               print "Closing {ns.address} ... {ns.close.to_s}"
+               print "Closing {ns.address} ..."
+               ns.close
        end
 end
 
index fd8fa5d..cf9b677 100644 (file)
@@ -39,7 +39,7 @@ class MPDConnection
 
                sys.nanosleep(0,5000)
 
-               var rep = p.read
+               var rep = p.read(1024)
                assert not rep.is_empty
                if not rep.has_prefix("OK") then
                        print "MPD responded {rep}"
@@ -61,7 +61,7 @@ class MPDConnection
 
                socket.write(msg)
                sys.nanosleep(0,5000)
-               var rep = socket.read
+               var rep = socket.read(1024)
                if not rep.has_prefix("OK") then
                        print "Error: MPD responded {rep}"
                        socket.close
@@ -82,7 +82,7 @@ class MPDConnection
 
                # get current status
                socket.write("status\n")
-               var rep = socket.read
+               var rep = socket.read(1024)
                for l in rep.split_with("\n") do
                        var words = l.split_with(" ")
                        if words.length > 1 then
@@ -153,7 +153,7 @@ class MPDConnection
                var time: nullable Int = null
 
                socket.write("currentsong\n")
-               var rep = socket.read
+               var rep = socket.read(1024)
                for l in rep.split_with("\n") do
                        var words = l.split_with(" ")
                        if words.length > 1 then
index 8919dbc..4a5129e 100644 (file)
@@ -21,6 +21,9 @@ import socket_c
 
 # Portal for communication between two machines
 class Socket
+       super BufferedIStream
+       super OStream
+
        # IPv4 address the socket is connected to
        # Formatted as xxx.xxx.xxx.xxx
        var address: String
@@ -38,18 +41,16 @@ class Socket
        # Underlying C socket
        private var addrin: FFSocketAddrIn
 
-       # Guard for errors
-       # If the socket could not be created or if the socket was destroyed
-       # before a call needing the socket was made
-       # this flag will be set to false.
-       var still_alive = true # Note : HUGE SUCCESS
+       redef var end_reached = false
 
        # Creates a socket connection to host `thost` on port `port`
        init stream_with_host(thost: String, tport: Int)
        do
+               _buffer = new FlatBuffer
+               _buffer_pos = 0
                socket = new FFSocket.socket( new FFSocketAddressFamilies.af_inet, new FFSocketTypes.sock_stream, new FFSocketProtocolFamilies.pf_null )
                if socket.address_is_null then
-                       still_alive = false
+                       end_reached = true
                        return
                end
                socket.setsockopt(new FFSocketOptLevels.socket, new FFSocketOptNames.reuseaddr, 1)
@@ -58,14 +59,17 @@ class Socket
                address = addrin.address
                host = hostname.h_name
                port = addrin.port
+               if not end_reached then end_reached = not connect
        end
 
        # Creates a server socket on port `tport`
        init stream_with_port(tport: Int)
        do
+               _buffer = new FlatBuffer
+               _buffer_pos = 0
                socket = new FFSocket.socket( new FFSocketAddressFamilies.af_inet, new FFSocketTypes.sock_stream, new FFSocketProtocolFamilies.pf_null )
                if socket.address_is_null then
-                       still_alive = false
+                       end_reached = true
                        return
                end
                socket.setsockopt(new FFSocketOptLevels.socket, new FFSocketOptNames.reuseaddr, 1)
@@ -73,11 +77,15 @@ class Socket
                address = addrin.address
                port = addrin.port
                host = null
+               bind
+               listen(max)
        end
 
        # Creates a client socket, this is meant to be used by accept only
        private init primitive_init(h: FFSocketAcceptResult)
        do
+               _buffer = new FlatBuffer
+               _buffer_pos = 0
                socket = h.socket
                addrin = h.addrIn
                address = addrin.address
@@ -102,12 +110,10 @@ class Socket
        #
        fun ready_to_read(timeout: Int): Bool
        do
-               if not still_alive then return false
+               if _buffer_pos < _buffer.length then return true
+               if eof then return false
                var events = new Array[FFSocketPollValues]
                events.push(new FFSocketPollValues.pollin)
-               events.push(new FFSocketPollValues.pollrdnorm)
-               events.push(new FFSocketPollValues.pollpri)
-               events.push(new FFSocketPollValues.pollrdband)
                return poll_in(events, timeout).length != 0
        end
 
@@ -115,64 +121,71 @@ class Socket
        #
        fun connected: Bool
        do
-               if not still_alive then return false
+               if eof then return false
                var events = new Array[FFSocketPollValues]
                events.push(new FFSocketPollValues.pollhup)
                events.push(new FFSocketPollValues.pollerr)
                return poll_in(events, 0).length == 0
        end
 
+       redef fun is_writable do return not end_reached
+
        # Establishes a connection to socket addrin
        #
-       # REQUIRES : self.still_alive
-       fun connect: Bool do
-               assert still_alive
+       # REQUIRES : not self.end_reached
+       private fun connect: Bool
+       do
+               assert not end_reached
                return socket.connect(addrin) >= 0
        end
 
-       # Write a message to connected socket
-       #
-       # Returns `true` if the `msg` was sent, `false` otherwise
-       #
-       # If not socket.sill_alive, false will be returned
-       fun write(msg: String): Bool do
-               if not still_alive then return false
-               return socket.write(msg) >= 0
+       # If socket.end_reached, nothing will happen
+       redef fun write(msg: Text)
+       do
+               if end_reached then return
+               socket.write(msg.to_s)
        end
 
-       # Read from connected socket
-       #
-       # If the socket is disconnected, an empty string will be returned
-       fun read: String do
-               if not still_alive then return ""
-               return socket.read
+       fun write_ln(msg: Text)
+       do
+               if end_reached then return
+               write(msg.to_s)
+               write("\n")
        end
 
-       # Close connection
-       #
-       # Returns : `true` if the close was successful, `false` otherwise
-       fun close: Bool do
-               if not still_alive then return true
+       redef fun fill_buffer
+       do
+               _buffer.clear
+               _buffer_pos = 0
+               if not connected then return
+               var read = socket.read
+               if read.length == 0 then
+                       close
+                       end_reached = true
+               end
+               _buffer.append(read)
+       end
+
+       redef fun close do
+               if end_reached then return
                if socket.close >= 0 then
-                       still_alive = false
-                       return true
+                       end_reached = true
                end
-               return false
        end
 
        # Associates the socket to a local address and port
        #
        # Returns : `true` if the socket could be bound, `false` otherwise
-       fun bind: Bool do
-               if not still_alive then return false
+       private fun bind: Bool do
+               if end_reached then return false
                return socket.bind(addrin) >= 0
        end
 
        # Sets the socket as ready to accept incoming connections, `size` is the maximum number of queued clients
        #
        # Returns : `true` if the socket could be set, `false` otherwise
-       fun listen(size: Int): Bool do
-               if not still_alive then return false
+       private fun listen(size: Int): Bool do
+               if end_reached then return false
                return socket.listen(size) >= 0
        end
 
@@ -181,9 +194,9 @@ class Socket
        #
        # Returns : the socket for communication with the client
        #
-       # REQUIRES : self.still_alive
+       # REQUIRES : not self.end_reached
        fun accept: Socket do
-               assert still_alive
+               assert not end_reached
                return new Socket.primitive_init(socket.accept)
        end