1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2013 Lucas Bajolet <lucas.bajolet@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.
17 # Network debugger for a nit program, based on the original debugger
18 # Replaces access to stdin/stdout to send data on the network to the client concerned
19 module network_debugger
22 intrude import debugger
24 redef class ToolContext
26 var opt_debug_port
: OptionInt = new OptionInt("Sets the debug port (Defaults to 22125) - Must be contained between 0 and 65535", 22125, "--port")
31 self.option_context
.add_option
(self.opt_debug_port
)
36 redef class ModelBuilder
37 fun run_debugger_network_mode
(mainmodule
: MModule, arguments
: Array[String], port
: Int)
40 self.toolcontext
.info
("*** START INTERPRETING ***", 1)
42 var interpreter
= new NetworkDebugger(self, mainmodule
, arguments
, port
)
44 init_naive_interpreter
(interpreter
, mainmodule
)
47 self.toolcontext
.info
("*** END INTERPRETING: {time1-time0} ***", 2)
49 interpreter
.disconnect_routine
52 interpreter
.socket
.close
56 # Extends the debugger by adding new network capabilities for remote debugging
60 # Represents the connexion with a particular client (Actually the only one accepted at the moment)
61 private var ns
: Socket
63 # Socket for the server, supposed to listen for incoming request from a client
64 private var socket
: Socket
66 # Initializes the debugger, waits for a client to connect
67 # Then starts debugging as usual
68 init(modelbuilder
: ModelBuilder, mainmodule
: MModule, arguments
: Array[String], port
: Int)
70 print
"Listening on port {port}"
72 socket
= new Socket.stream_with_port
(port
)
81 print
"Client connected"
85 if stdout
isa Stdout then
86 (stdout
.as(Stdout)).connection
= ns
95 # Provokes the disconnection of the client
96 # Used when debugging is over
97 fun disconnect_routine
99 print
"DBG DONE WORK ON SELF"
103 while cliOverResp
!= "CLIENT DBG DONE ACK" do
108 # Checks on every call if the client has sent a command before continuing debugging
111 if stdin
.poll_in
then
113 if command
== "stop" then
114 n
.debug
("Stopped by client")
115 while process_debug_command
(gets
) do end
117 process_debug_command
(command
)
128 # Breaks automatically when encountering an error
129 # Permits the injunction of commands before crashing
130 # Disconnects from the client before crashing
131 redef private fun fatal
(v
: NaiveInterpreter, message
: String)
133 if v
isa Debugger then
134 print
"An error was encountered, the program will stop now."
136 while v
.process_debug_command
(gets
) do end
139 if v
isa NetworkDebugger then
141 stdin
.connection
.close
148 # Replaces Stdin to read on the network
151 # Represents the connection with a client
152 var connection
: nullable Socket = null
154 # Used to store data that has been read from the connection
155 var buf
: Buffer = new FlatBuffer
158 # Checks if data is available for reading
161 return connection
.ready_to_read
(0)
164 # Reads the whole content of the buffer
165 # Blocking if the buffer is empty
168 var loc_buf
= new FlatBuffer
169 if connection
.ready_to_read
(0) then buf
.append
(connection
.read
)
170 for i
in [buf_pos
.. buf
.length-1
] do loc_buf
.add
(buf
.chars
[i
])
176 # Reads a single char on the incoming buffer
177 # If the buffer is empty, the call is blocking
180 if connection
.ready_to_read
(0) then buf
.append
(connection
.read
)
181 if buf_pos
>= buf
.length
then
185 buf
.append
(connection
.read
)
188 return buf
.chars
[buf_pos-1
].ascii
191 # Reads a line on the network if available
192 # Stops at the first encounter of a \n character
193 # If the buffer is empty, the read_line call is blocking
196 var line_buf
= new FlatBuffer
197 if connection
.ready_to_read
(0) then buf
.append
(connection
.read
)
198 var has_found_eol
: Bool = false
200 if buf_pos
>= buf
.length
then
204 buf
.append
(connection
.read
)
207 if buf
.chars
[buf_pos-1
] == '\n' then break
208 line_buf
.add
(buf
.chars
[buf_pos-1
])
214 # Replaces Stdout to write on the network
217 # Connection with the client object
218 var connection
: nullable Socket = null
220 # Writes a string on the network if available, else
221 # it is written in the standard output (Terminal)
224 if connection
!= null then