Property definitions

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