# Simple communication stream with a remote socket
class TCPStream
super TCPSocket
- super BufferedReader
- super Writer
super PollableReader
+ super Duplex
# Real canonical name of the host to which `self` is connected
var host: String
private var addrin: NativeSocketAddrIn is noinit
- redef var end_reached = false
+ redef var closed = false
# TODO make init private
# Creates a socket connection to host `host` on port `port`
init connect(host: String, port: Int)
do
- _buffer = new CString(1024)
- _buffer_pos = 0
native = new NativeSocket.socket(new NativeSocketAddressFamilies.af_inet,
- new NativeSocketTypes.sock_stream, new NativeSocketProtocolFamilies.pf_null)
+ new NativeSocketTypes.sock_stream, new NativeSocketProtocolFamilies.pf_unspec)
if native.address_is_null then
- end_reached = true
closed = true
return
end
if not native.setsockopt(new NativeSocketOptLevels.socket, new NativeSocketOptNames.reuseaddr, 1) then
- end_reached = true
closed = true
return
end
last_error = new IOError.from_h_errno
closed = true
- end_reached = true
return
end
init(addrin.port, hostent.h_name.to_s)
closed = not internal_connect
- end_reached = closed
if closed then
# Connection failed
last_error = new IOError.from_errno
end
-
- prepare_buffer(1024)
end
# Creates a client socket, this is meant to be used by accept only
address = addrin.address.to_s
init(addrin.port, address)
-
- prepare_buffer(1024)
end
redef fun poll_in do return ready_to_read(0)
#
# timeout : Time in milliseconds before stopping listening for events on this socket
private fun pollin(event_types: Array[NativeSocketPollValues], timeout: Int): Array[NativeSocketPollValues] do
- if end_reached then return new Array[NativeSocketPollValues]
- return native.socket_poll(new PollFD(native.descriptor, event_types), timeout)
+ if closed then return new Array[NativeSocketPollValues]
+ return native.socket_poll(new PollFD.from_poll_values(native.descriptor, event_types), timeout)
end
# Easier use of pollin to check for something to read on all channels of any priority
# timeout : Time in milliseconds before stopping to wait for events
fun ready_to_read(timeout: Int): Bool
do
- if _buffer_pos < _buffer_length then return true
- if end_reached then return false
var events = [new NativeSocketPollValues.pollin]
return pollin(events, timeout).length != 0
end
end
end
- redef fun is_writable do return not end_reached
+ redef fun is_writable do return not closed
# Establishes a connection to socket addrin
#
return native.connect(addrin) >= 0
end
+ redef fun raw_read_byte do
+ var rd = native.read(write_buffer, 1)
+ if rd < 1 then return -1
+ return write_buffer[0].to_i
+ end
+
+ redef fun raw_read_bytes(ns, max) do
+ var rd = native.read(ns, max)
+ print "Read {rd} bytes"
+ if rd < 0 then return -1
+ return rd
+ end
+
# If socket.end_reached, nothing will happen
redef fun write(msg)
do
native.write_byte value
end
- redef fun write_bytes(bytes) do
+ redef fun write_bytes_from_cstring(ns, len) do
if closed then return
- var s = bytes.to_s
- native.write(s.to_cstring, s.length)
+ native.write(ns, len)
end
+ # Write `msg`, with a trailing `\n`
fun write_ln(msg: Text)
do
if closed then return
write "\n"
end
- redef fun fill_buffer
- do
- if not connected then return
-
- var read = native.read(_buffer, _buffer_capacity)
- if read == -1 then
- close
- end_reached = true
- end
-
- _buffer_length = read
- _buffer_pos = 0
- end
-
- fun enlarge(len: Int) do
- if _buffer_capacity >= len then return
- _buffer_capacity = len
-
- var ns = new CString(_buffer_capacity)
- _buffer.copy_to(ns, _buffer_length - _buffer_pos, _buffer_pos, 0)
- _buffer = ns
- end
-
redef fun close
do
if closed then return
if native.close >= 0 then
closed = true
- end_reached = true
end
end
init
do
native = new NativeSocket.socket(new NativeSocketAddressFamilies.af_inet,
- new NativeSocketTypes.sock_stream, new NativeSocketProtocolFamilies.pf_null)
+ new NativeSocketTypes.sock_stream, new NativeSocketProtocolFamilies.pf_unspec)
assert not native.address_is_null
if not native.setsockopt(new NativeSocketOptLevels.socket, new NativeSocketOptNames.reuseaddr, 1) then
closed = true
class SocketObserver
private var native = new NativeSocketObserver
+ # Set of file descriptors on which to watch read events
var read_set: nullable SocketSet = null
+ # Set of file descriptors on which to watch write events
var write_set: nullable SocketSet = null
+ # Set of file descriptors on which to watch exception events
var except_set: nullable SocketSet = null
- init(read: Bool, write: Bool, except: Bool)
- is old_style_init do
+ # Initialize a socket observer
+ init with_sets(read: Bool, write: Bool, except: Bool) do
if read then read_set = new SocketSet
if write then write_set = new SocketSet
if except then except_set = new SocketSet
end
+ # Watch for changes in the states of several sockets.
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 native.select(max.native, read_set.native, write_set.native, except_set.native, timeval) > 0
+ var rd = if read_set != null then read_set.as(not null).native else null
+ var wrt = if write_set != null then write_set.as(not null).native else null
+ var expt = if except_set != null then except_set.as(not null).native else null
+ return native.select(max.native, rd, wrt, expt, timeval) > 0
end
end
init do native = new NativeSocket.socket(
new NativeSocketAddressFamilies.af_inet,
new NativeSocketTypes.sock_dgram,
- new NativeSocketProtocolFamilies.pf_null)
+ new NativeSocketProtocolFamilies.pf_unspec)
# Bind this socket to an `address`, on `port` (to all addresses if `null`)
#