socket :: TCPStream :: defaultinit
# Simple communication stream with a remote socket
class TCPStream
super TCPSocket
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 closed = false
# TODO make init private
# Creates a socket connection to host `host` on port `port`
init connect(host: String, port: Int)
do
native = new NativeSocket.socket(new NativeSocketAddressFamilies.af_inet,
new NativeSocketTypes.sock_stream, new NativeSocketProtocolFamilies.pf_unspec)
if native.address_is_null then
closed = true
return
end
if not native.setsockopt(new NativeSocketOptLevels.socket, new NativeSocketOptNames.reuseaddr, 1) then
closed = true
return
end
var hostent = sys.gethostbyname(host.to_cstring)
if hostent.address_is_null then
# Error in name lookup
last_error = new IOError.from_h_errno
closed = true
return
end
addrin = new NativeSocketAddrIn
addrin.fill_from_hostent hostent
addrin.port = port
address = addrin.address.to_s
init(addrin.port, hostent.h_name.to_s)
closed = not internal_connect
if closed then
# Connection failed
last_error = new IOError.from_errno
end
end
# Creates a client socket, this is meant to be used by accept only
private init server_side(h: SocketAcceptResult)
do
native = h.socket
addrin = h.addr_in
address = addrin.address.to_s
init(addrin.port, address)
end
redef fun poll_in do return ready_to_read(0)
# Returns an array containing an enum of the events ready to be read
#
# event_types : Combination of several event types to watch
#
# 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 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
var events = [new NativeSocketPollValues.pollin]
return pollin(events, timeout).length != 0
end
# Is this socket still connected?
fun connected: Bool
do
if closed then return false
if native.poll_hup_err == 0 then
return true
else
closed = true
return false
end
end
redef fun is_writable do return not closed
# Establishes a connection to socket addrin
#
# REQUIRES : not self.end_reached
private fun internal_connect: Bool
do
assert not closed
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
if closed then return
native.write(msg.to_cstring, msg.length)
end
redef fun write_byte(value)
do
if closed then return
native.write_byte value
end
redef fun write_bytes_from_cstring(ns, len) do
if closed then return
native.write(ns, len)
end
# Write `msg`, with a trailing `\n`
fun write_ln(msg: Text)
do
if closed then return
write msg.to_s
write "\n"
end
redef fun close
do
if closed then return
if native.close >= 0 then
closed = true
end
end
# Send the data present in the socket buffer
fun flush
do
if not native.setsockopt(new NativeSocketOptLevels.tcp, new NativeSocketOptNames.tcp_nodelay, 1) or
not native.setsockopt(new NativeSocketOptLevels.tcp, new NativeSocketOptNames.tcp_nodelay, 0) then
closed = true
end
end
end
lib/socket/socket.nit:55,1--217,3