1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2013 Matthieu Lucas <lucasmatthieu@gmail.com>
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
22 # Portal for communication between two machines
24 # IPv4 address the socket is connected to
25 # Formatted as xxx.xxx.xxx.xxx
28 # Hostname of the socket connected to self
29 # In C : The real canonical host name (e.g. example.org)
30 var host
: nullable String
32 # Port open for the socket
36 private var socket
: FFSocket
39 private var addrin
: FFSocketAddrIn
42 # If the socket could not be created or if the socket was destroyed
43 # before a call needing the socket was made
44 # this flag will be set to false.
45 var still_alive
= true # Note : HUGE SUCCESS
47 # Creates a socket connection to host `thost` on port `port`
48 init stream_with_host
(thost
: String, tport
: Int)
50 socket
= new FFSocket.socket
( new FFSocketAddressFamilies.af_inet
, new FFSocketTypes.sock_stream
, new FFSocketProtocolFamilies.pf_null
)
51 if socket
.address_is_null
then
55 socket
.setsockopt
(new FFSocketOptLevels.socket
, new FFSocketOptNames.reuseaddr
, 1)
56 var hostname
= socket
.gethostbyname
(thost
)
57 addrin
= new FFSocketAddrIn.with_hostent
(hostname
, tport
)
58 address
= addrin
.address
59 host
= hostname
.h_name
63 # Creates a server socket on port `tport`
64 init stream_with_port
(tport
: Int)
66 socket
= new FFSocket.socket
( new FFSocketAddressFamilies.af_inet
, new FFSocketTypes.sock_stream
, new FFSocketProtocolFamilies.pf_null
)
67 if socket
.address_is_null
then
71 socket
.setsockopt
(new FFSocketOptLevels.socket
, new FFSocketOptNames.reuseaddr
, 1)
72 addrin
= new FFSocketAddrIn.with
(tport
, new FFSocketAddressFamilies.af_inet
)
73 address
= addrin
.address
78 # Creates a client socket, this is meant to be used by accept only
79 private init primitive_init
(h
: FFSocketAcceptResult)
83 address
= addrin
.address
88 # Returns an array containing an enum of the events ready to be read
90 # event_types : Combination of several event types to watch
92 # timeout : Time in milliseconds before stopping listening for events on this socket
94 private fun poll_in
(event_types
: Array[FFSocketPollValues], timeout
: Int): Array[FFSocketPollValues] do
95 if not still_alive
then return new Array[FFSocketPollValues]
96 return socket
.socket_poll
(new PollFD(socket
.descriptor
, event_types
), timeout
)
99 # Easier use of poll_in to check for something to read on all channels of any priority
101 # timeout : Time in milliseconds before stopping to wait for events
103 fun ready_to_read
(timeout
: Int): Bool
105 if not still_alive
then return false
106 var events
= new Array[FFSocketPollValues]
107 events
.push
(new FFSocketPollValues.pollin
)
108 events
.push
(new FFSocketPollValues.pollrdnorm
)
109 events
.push
(new FFSocketPollValues.pollpri
)
110 events
.push
(new FFSocketPollValues.pollrdband
)
111 return poll_in
(events
, timeout
).length
!= 0
114 # Checks if the socket still is connected
118 if not still_alive
then return false
119 var events
= new Array[FFSocketPollValues]
120 events
.push
(new FFSocketPollValues.pollhup
)
121 events
.push
(new FFSocketPollValues.pollerr
)
122 return poll_in
(events
, 0).length
== 0
125 # Establishes a connection to socket addrin
127 # REQUIRES : self.still_alive
130 return socket
.connect
(addrin
) >= 0
133 # Write a message to connected socket
135 # Returns `true` if the `msg` was sent, `false` otherwise
137 # If not socket.sill_alive, false will be returned
138 fun write
(msg
: String): Bool do
139 if not still_alive
then return false
140 return socket
.write
(msg
) >= 0
143 # Read from connected socket
145 # If the socket is disconnected, an empty string will be returned
147 if not still_alive
then return ""
153 # Returns : `true` if the close was successful, `false` otherwise
155 if not still_alive
then return true
156 if socket
.close
>= 0 then
163 # Associates the socket to a local address and port
165 # Returns : `true` if the socket could be bound, `false` otherwise
167 if not still_alive
then return false
168 return socket
.bind
(addrin
) >= 0
171 # Sets the socket as ready to accept incoming connections, `size` is the maximum number of queued clients
173 # Returns : `true` if the socket could be set, `false` otherwise
174 fun listen
(size
: Int): Bool do
175 if not still_alive
then return false
176 return socket
.listen
(size
) >= 0
179 # Accepts an incoming connection from a client
180 # This creates a new socket that represents the connection to a client
182 # Returns : the socket for communication with the client
184 # REQUIRES : self.still_alive
185 fun accept
: Socket do
187 return new Socket.primitive_init
(socket
.accept
)
193 var sset
: FFSocketSet
194 init do sset
= new FFSocketSet end
195 fun set
(s
: Socket) do sset
.set
(s
.socket
) end
196 fun is_set
(s
: Socket): Bool do return sset
.is_set
(s
.socket
) end
197 fun zero
do sset
.zero
end
198 fun clear
(s
: Socket) do sset
.clear
(s
.socket
) end
202 private var observer
: FFSocketObserver
203 var readset
: nullable SocketSet = null
204 var writeset
: nullable SocketSet = null
205 var exceptset
: nullable SocketSet = null
206 init(read
:Bool, write
:Bool, except
: Bool)
208 if read
then readset
= new SocketSet
209 if write
then writeset
= new SocketSet
210 if except
then exceptset
= new SocketSet
211 observer
= new FFSocketObserver
213 fun select
(max
: Socket,seconds
: Int, microseconds
: Int): Bool
215 var timeval
= new FFTimeval(seconds
, microseconds
)
216 return observer
.select
(max
.socket
, readset
.sset
, writeset
.sset
, readset
.sset
, timeval
) > 0