abstract class Socket
# Underlying C socket
- private var socket: NativeSocket is noinit
+ private var native: NativeSocket is noinit
# Port used by the socket
var port: Int
do
_buffer = new NativeString(1024)
_buffer_pos = 0
- socket = new NativeSocket.socket(new NativeSocketAddressFamilies.af_inet,
+ native = new NativeSocket.socket(new NativeSocketAddressFamilies.af_inet,
new NativeSocketTypes.sock_stream, new NativeSocketProtocolFamilies.pf_null)
- if socket.address_is_null then
+ if native.address_is_null then
end_reached = true
closed = true
return
end
- if not socket.setsockopt(new NativeSocketOptLevels.socket, new NativeSocketOptNames.reuseaddr, 1) then
+ if not native.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)
- address = addrin.address
- init(addrin.port, hostname.h_name)
+ var hostent = sys.gethostbyname(host.to_cstring)
+ if hostent.address_is_null then
+ # Error in name lookup
+ var err = sys.h_errno
+ last_error = new IOError(err.to_s)
+
+ closed = true
+ end_reached = 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
end_reached = closed
+ if closed then
+ # Connection failed
+ last_error = new IOError(errno.strerror)
+ end
+
+ prepare_buffer(1024)
end
# Creates a client socket, this is meant to be used by accept only
private init server_side(h: SocketAcceptResult)
do
- _buffer = new NativeString(1024)
- _buffer_pos = 0
- socket = h.socket
+ native = h.socket
addrin = h.addr_in
- address = addrin.address
+ 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 socket.socket_poll(new PollFD(socket.descriptor, event_types), timeout)
+ return native.socket_poll(new PollFD(native.descriptor, event_types), timeout)
end
# Easier use of pollin to check for something to read on all channels of any priority
private fun internal_connect: Bool
do
assert not closed
- return socket.connect(addrin) >= 0
+ return native.connect(addrin) >= 0
end
# If socket.end_reached, nothing will happen
redef fun write(msg)
do
if closed then return
- socket.write(msg.to_s)
+ native.write(msg.to_cstring, msg.length)
end
redef fun write_byte(value)
do
if closed then return
- socket.write_byte value
+ native.write_byte value
end
- redef fun write_bytes(s) do
+ redef fun write_bytes(bytes) do
if closed then return
- socket.write(s.to_s)
+ var s = bytes.to_s
+ native.write(s.to_cstring, s.length)
end
fun write_ln(msg: Text)
do
- if end_reached then return
- write(msg.to_s)
- write("\n")
+ if closed then return
+ write msg.to_s
+ write "\n"
end
redef fun fill_buffer
do
- _buffer_length = 0
- _buffer_pos = 0
if not connected then return
- var read = socket.read
- if read.length == 0 then
+
+ var read = native.read(_buffer, _buffer_capacity)
+ if read == -1 then
close
end_reached = true
end
- enlarge(_buffer_capacity + read.length)
- read.copy_to_native(_buffer, read.length, 0, 0)
- _buffer_length = read.length
+
+ _buffer_length = read
+ _buffer_pos = 0
end
fun enlarge(len: Int) do
if _buffer_capacity >= len then return
- while _buffer_capacity < len do _buffer_capacity *= 2
+ _buffer_capacity = len
+
var ns = new NativeString(_buffer_capacity)
_buffer.copy_to(ns, _buffer_length - _buffer_pos, _buffer_pos, 0)
_buffer = ns
redef fun close
do
if closed then return
- if socket.close >= 0 then
+ if native.close >= 0 then
closed = true
end_reached = true
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
+ 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
# Create and bind a listening server socket on port `port`
init
do
- socket = new NativeSocket.socket(new NativeSocketAddressFamilies.af_inet,
+ native = new NativeSocket.socket(new NativeSocketAddressFamilies.af_inet,
new NativeSocketTypes.sock_stream, new NativeSocketProtocolFamilies.pf_null)
- assert not socket.address_is_null
- if not socket.setsockopt(new NativeSocketOptLevels.socket, new NativeSocketOptNames.reuseaddr, 1) then
+ assert not native.address_is_null
+ if not native.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
+
+ addrin = new NativeSocketAddrIn
+ addrin.family = new NativeSocketAddressFamilies.af_inet
+ addrin.port = port
+ addrin.address_any
+
+ address = addrin.address.to_s
# Bind it
closed = not bind
#
# Returns whether the socket has been be bound.
private fun bind: Bool do
- return socket.bind(addrin) >= 0
+ return native.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
- return socket.listen(size) >= 0
+ return native.listen(size) >= 0
end
# Accepts an incoming connection from a client
fun accept: nullable TCPStream
do
assert not closed
- var native = socket.accept
+ var native = native.accept
if native == null then return null
return new TCPStream.server_side(native)
end
# 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
+ native.non_blocking = not value
end
# Close this socket
# FIXME unify with `SocketStream::close` when we can use qualified names
if closed then return
- if socket.close >= 0 then
+ if native.close >= 0 then
closed = true
end
end
init do clear
# Add `socket` to this set
- fun add(socket: Socket) do native.set(socket.socket)
+ fun add(socket: Socket) do native.set(socket.native)
# Remove `socket` from this set
- fun remove(socket: Socket) do native.clear(socket.socket)
+ fun remove(socket: Socket) do native.clear(socket.native)
# Does this set has `socket`?
- fun has(socket: Socket): Bool do return native.is_set(socket.socket)
+ fun has(socket: Socket): Bool do return native.is_set(socket.native)
# Clear all sockets from this set
fun clear do native.zero
# `NativeSockectObserver::select` is not stable.
var timeval = new NativeTimeval(seconds, microseconds)
- return native.select(max.socket, read_set.native, write_set.native, except_set.native, timeval) > 0
+ return native.select(max.native, read_set.native, write_set.native, except_set.native, timeval) > 0
end
end