mirror of
https://github.com/jerryscript-project/jerryscript.git
synced 2025-12-15 16:29:21 +00:00
Separate the debugger-client to support the later usage of other communication protocols (#2764)
JerryScript-DCO-1.0-Signed-off-by: Robert Sipka rsipka.uszeged@partner.samsung.com
This commit is contained in:
parent
d4e27d3003
commit
6d490c7296
@ -22,7 +22,7 @@ import socket
|
||||
import sys
|
||||
import logging
|
||||
import time
|
||||
import jerry_client_ws
|
||||
import jerry_client_main
|
||||
|
||||
def write(string):
|
||||
print(string, end='')
|
||||
@ -248,9 +248,9 @@ def src_check_args(args):
|
||||
|
||||
# pylint: disable=too-many-branches,too-many-locals,too-many-statements
|
||||
def main():
|
||||
args = jerry_client_ws.arguments_parse()
|
||||
args = jerry_client_main.arguments_parse()
|
||||
|
||||
debugger = jerry_client_ws.JerryDebugger(args.address)
|
||||
debugger = jerry_client_main.JerryDebugger(args.address)
|
||||
debugger.non_interactive = args.non_interactive
|
||||
|
||||
logging.debug("Connected to JerryScript on %d port", debugger.port)
|
||||
|
||||
@ -19,9 +19,9 @@ import argparse
|
||||
import logging
|
||||
import re
|
||||
import select
|
||||
import socket
|
||||
import struct
|
||||
import sys
|
||||
from jerry_client_websocket import WebSocket
|
||||
|
||||
# Expected debugger protocol version.
|
||||
JERRY_DEBUGGER_VERSION = 8
|
||||
@ -101,10 +101,6 @@ JERRY_DEBUGGER_EVAL_PART = 18
|
||||
JERRY_DEBUGGER_GET_SCOPE_CHAIN = 19
|
||||
JERRY_DEBUGGER_GET_SCOPE_VARIABLES = 20
|
||||
|
||||
MAX_BUFFER_SIZE = 128
|
||||
WEBSOCKET_BINARY_FRAME = 2
|
||||
WEBSOCKET_FIN_BIT = 0x80
|
||||
|
||||
JERRY_DEBUGGER_SCOPE_WITH = 1
|
||||
JERRY_DEBUGGER_SCOPE_LOCAL = 2
|
||||
JERRY_DEBUGGER_SCOPE_CLOSURE = 3
|
||||
@ -278,7 +274,6 @@ class JerryDebugger(object):
|
||||
|
||||
print("Connecting to: %s:%s" % (self.host, self.port))
|
||||
|
||||
self.message_data = b""
|
||||
self.prompt = False
|
||||
self.function_list = {}
|
||||
self.source = ''
|
||||
@ -303,62 +298,27 @@ class JerryDebugger(object):
|
||||
self.nocolor = ''
|
||||
self.src_offset = 0
|
||||
self.src_offset_diff = 0
|
||||
self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.client_socket.connect((self.host, self.port))
|
||||
self.non_interactive = False
|
||||
self.current_out = b""
|
||||
self.current_log = b""
|
||||
|
||||
self.send_message(b"GET /jerry-debugger HTTP/1.1\r\n" +
|
||||
b"Upgrade: websocket\r\n" +
|
||||
b"Connection: Upgrade\r\n" +
|
||||
b"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n")
|
||||
result = b""
|
||||
expected = (b"HTTP/1.1 101 Switching Protocols\r\n" +
|
||||
b"Upgrade: websocket\r\n" +
|
||||
b"Connection: Upgrade\r\n" +
|
||||
b"Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n")
|
||||
self.channel = WebSocket(address=(self.host, self.port))
|
||||
|
||||
len_expected = len(expected)
|
||||
|
||||
while len(result) < len_expected:
|
||||
result += self.client_socket.recv(1024)
|
||||
|
||||
len_result = len(result)
|
||||
|
||||
if result[0:len_expected] != expected:
|
||||
raise Exception("Unexpected handshake")
|
||||
|
||||
if len_result > len_expected:
|
||||
result = result[len_expected:]
|
||||
else:
|
||||
result = b""
|
||||
|
||||
len_expected = 10
|
||||
# Network configurations, which has the following struct:
|
||||
# header [2] - opcode[1], size[1]
|
||||
config_size = 8
|
||||
# The server will send the configuration message after connection established
|
||||
# type [1]
|
||||
# configuration [1]
|
||||
# version [4]
|
||||
# max_message_size [1]
|
||||
# cpointer_size [1]
|
||||
result = self.channel.connect(config_size)
|
||||
|
||||
while len(result) < len_expected:
|
||||
result += self.client_socket.recv(1024)
|
||||
|
||||
len_result = len(result)
|
||||
|
||||
expected = struct.pack("BBB",
|
||||
WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT,
|
||||
8,
|
||||
JERRY_DEBUGGER_CONFIGURATION)
|
||||
|
||||
if result[0:3] != expected:
|
||||
if len(result) != config_size or ord(result[0]) != JERRY_DEBUGGER_CONFIGURATION:
|
||||
raise Exception("Unexpected configuration")
|
||||
|
||||
self.little_endian = ord(result[3]) & JERRY_DEBUGGER_LITTLE_ENDIAN
|
||||
self.max_message_size = ord(result[8])
|
||||
self.cp_size = ord(result[9])
|
||||
self.little_endian = ord(result[1]) & JERRY_DEBUGGER_LITTLE_ENDIAN
|
||||
self.max_message_size = ord(result[6])
|
||||
self.cp_size = ord(result[7])
|
||||
|
||||
if self.little_endian:
|
||||
self.byte_order = "<"
|
||||
@ -374,18 +334,15 @@ class JerryDebugger(object):
|
||||
|
||||
self.idx_format = "I"
|
||||
|
||||
self.version = struct.unpack(self.byte_order + self.idx_format, result[4:8])[0]
|
||||
self.version = struct.unpack(self.byte_order + self.idx_format, result[2:6])[0]
|
||||
if self.version != JERRY_DEBUGGER_VERSION:
|
||||
raise Exception("Incorrect debugger version from target: %d expected: %d" %
|
||||
(self.version, JERRY_DEBUGGER_VERSION))
|
||||
|
||||
logging.debug("Compressed pointer size: %d", self.cp_size)
|
||||
|
||||
if len_result > len_expected:
|
||||
self.message_data = result[len_expected:]
|
||||
|
||||
def __del__(self):
|
||||
self.client_socket.close()
|
||||
self.channel.close()
|
||||
|
||||
def _exec_command(self, command_id):
|
||||
self.send_command(command_id)
|
||||
@ -515,15 +472,16 @@ class JerryDebugger(object):
|
||||
return "Error: Positive integer number expected, %s\n" % (val_errno)
|
||||
|
||||
self.frame_index = min_depth
|
||||
message = struct.pack(self.byte_order + "BBIB" + self.idx_format + self.idx_format + "B",
|
||||
WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT,
|
||||
WEBSOCKET_FIN_BIT + 1 + 4 + 4 + 1,
|
||||
0,
|
||||
|
||||
message = struct.pack(self.byte_order + "BB" + self.idx_format + self.idx_format + "B",
|
||||
1 + 4 + 4 + 1,
|
||||
JERRY_DEBUGGER_GET_BACKTRACE,
|
||||
min_depth,
|
||||
max_depth,
|
||||
get_total)
|
||||
self.send_message(message)
|
||||
|
||||
self.channel.send_message(self.byte_order, message)
|
||||
|
||||
self.prompt = False
|
||||
return ""
|
||||
|
||||
@ -539,13 +497,13 @@ class JerryDebugger(object):
|
||||
except ValueError as val_errno:
|
||||
return "Error: Non negative integer number expected, %s\n" % (val_errno)
|
||||
|
||||
message = struct.pack(self.byte_order + "BBIB" + self.idx_format,
|
||||
WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT,
|
||||
WEBSOCKET_FIN_BIT + 1 + 4,
|
||||
0,
|
||||
message = struct.pack(self.byte_order + "BB" + self.idx_format,
|
||||
1 + 4,
|
||||
JERRY_DEBUGGER_GET_SCOPE_VARIABLES,
|
||||
index)
|
||||
self.send_message(message)
|
||||
|
||||
self.channel.send_message(self.byte_order, message)
|
||||
|
||||
self.prompt = False
|
||||
return ""
|
||||
|
||||
@ -605,18 +563,16 @@ class JerryDebugger(object):
|
||||
|
||||
max_fragment = min(self.max_message_size - message_header, size)
|
||||
|
||||
message = struct.pack(self.byte_order + "BBIBI",
|
||||
WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT,
|
||||
WEBSOCKET_FIN_BIT + max_fragment + message_header,
|
||||
0,
|
||||
message = struct.pack(self.byte_order + "BBI",
|
||||
max_fragment + message_header,
|
||||
message_type,
|
||||
size)
|
||||
|
||||
if size == max_fragment:
|
||||
self.send_message(message + args)
|
||||
self.channel.send_message(self.byte_order, message + args)
|
||||
return
|
||||
|
||||
self.send_message(message + args[0:max_fragment])
|
||||
self.channel.send_message(self.byte_order, message + args[0:max_fragment])
|
||||
offset = max_fragment
|
||||
|
||||
if message_type == JERRY_DEBUGGER_EVAL:
|
||||
@ -631,15 +587,14 @@ class JerryDebugger(object):
|
||||
while offset < size:
|
||||
next_fragment = min(max_fragment, size - offset)
|
||||
|
||||
message = struct.pack(self.byte_order + "BBIB",
|
||||
WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT,
|
||||
WEBSOCKET_FIN_BIT + next_fragment + message_header,
|
||||
0,
|
||||
message = struct.pack(self.byte_order + "BB",
|
||||
next_fragment + message_header,
|
||||
message_type)
|
||||
|
||||
prev_offset = offset
|
||||
offset += next_fragment
|
||||
self.send_message(message + args[prev_offset:offset])
|
||||
|
||||
self.channel.send_message(self.byte_order, message + args[prev_offset:offset])
|
||||
|
||||
def delete_active(self):
|
||||
for i in self.active_breakpoint_list.values():
|
||||
@ -663,50 +618,40 @@ class JerryDebugger(object):
|
||||
return False
|
||||
|
||||
def send_breakpoint(self, breakpoint):
|
||||
message = struct.pack(self.byte_order + "BBIBB" + self.cp_format + self.idx_format,
|
||||
WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT,
|
||||
WEBSOCKET_FIN_BIT + 1 + 1 + self.cp_size + 4,
|
||||
0,
|
||||
message = struct.pack(self.byte_order + "BBB" + self.cp_format + self.idx_format,
|
||||
1 + 1 + self.cp_size + 4,
|
||||
JERRY_DEBUGGER_UPDATE_BREAKPOINT,
|
||||
int(breakpoint.active_index >= 0),
|
||||
breakpoint.function.byte_code_cp,
|
||||
breakpoint.offset)
|
||||
self.send_message(message)
|
||||
self.channel.send_message(self.byte_order, message)
|
||||
|
||||
def send_bytecode_cp(self, byte_code_cp):
|
||||
message = struct.pack(self.byte_order + "BBIB" + self.cp_format,
|
||||
WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT,
|
||||
WEBSOCKET_FIN_BIT + 1 + self.cp_size,
|
||||
0,
|
||||
message = struct.pack(self.byte_order + "BB" + self.cp_format,
|
||||
1 + self.cp_size,
|
||||
JERRY_DEBUGGER_FREE_BYTE_CODE_CP,
|
||||
byte_code_cp)
|
||||
self.send_message(message)
|
||||
self.channel.send_message(self.byte_order, message)
|
||||
|
||||
def send_command(self, command):
|
||||
message = struct.pack(self.byte_order + "BBIB",
|
||||
WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT,
|
||||
WEBSOCKET_FIN_BIT + 1,
|
||||
0,
|
||||
message = struct.pack(self.byte_order + "BB",
|
||||
1,
|
||||
command)
|
||||
self.send_message(message)
|
||||
self.channel.send_message(self.byte_order, message)
|
||||
|
||||
def send_exception_config(self, enable):
|
||||
message = struct.pack(self.byte_order + "BBIBB",
|
||||
WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT,
|
||||
WEBSOCKET_FIN_BIT + 1 + 1,
|
||||
0,
|
||||
message = struct.pack(self.byte_order + "BBB",
|
||||
1 + 1,
|
||||
JERRY_DEBUGGER_EXCEPTION_CONFIG,
|
||||
enable)
|
||||
self.send_message(message)
|
||||
self.channel.send_message(self.byte_order, message)
|
||||
|
||||
def send_parser_config(self, enable):
|
||||
message = struct.pack(self.byte_order + "BBIBB",
|
||||
WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT,
|
||||
WEBSOCKET_FIN_BIT + 1 + 1,
|
||||
0,
|
||||
message = struct.pack(self.byte_order + "BBB",
|
||||
1 + 1,
|
||||
JERRY_DEBUGGER_PARSER_CONFIG,
|
||||
enable)
|
||||
self.send_message(message)
|
||||
self.channel.send_message(self.byte_order, message)
|
||||
|
||||
def set_colors(self):
|
||||
self.nocolor = '\033[0m'
|
||||
@ -717,46 +662,6 @@ class JerryDebugger(object):
|
||||
self.yellow_bg = '\033[43m\033[30m'
|
||||
self.blue = '\033[94m'
|
||||
|
||||
def send_message(self, message):
|
||||
size = len(message)
|
||||
while size > 0:
|
||||
bytes_send = self.client_socket.send(message)
|
||||
if bytes_send < size:
|
||||
message = message[bytes_send:]
|
||||
size -= bytes_send
|
||||
|
||||
|
||||
def get_message(self, blocking):
|
||||
# Connection was closed
|
||||
if self.message_data is None:
|
||||
return None
|
||||
|
||||
while True:
|
||||
if len(self.message_data) >= 2:
|
||||
if ord(self.message_data[0]) != WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT:
|
||||
raise Exception("Unexpected data frame")
|
||||
|
||||
size = ord(self.message_data[1])
|
||||
if size == 0 or size >= 126:
|
||||
raise Exception("Unexpected data frame")
|
||||
|
||||
if len(self.message_data) >= size + 2:
|
||||
result = self.message_data[0:size + 2]
|
||||
self.message_data = self.message_data[size + 2:]
|
||||
return result
|
||||
|
||||
if not blocking:
|
||||
select_result = select.select([self.client_socket], [], [], 0)[0]
|
||||
if self.client_socket not in select_result:
|
||||
return b''
|
||||
|
||||
data = self.client_socket.recv(MAX_BUFFER_SIZE)
|
||||
|
||||
if not data:
|
||||
self.message_data = None
|
||||
return None
|
||||
self.message_data += data
|
||||
|
||||
def store_client_sources(self, args):
|
||||
self.client_sources = args
|
||||
|
||||
@ -783,7 +688,7 @@ class JerryDebugger(object):
|
||||
result = ""
|
||||
|
||||
while True:
|
||||
data = self.get_message(False)
|
||||
data = self.channel.get_message(False)
|
||||
if not self.non_interactive:
|
||||
if sys.stdin in select.select([sys.stdin], [], [], 0)[0]:
|
||||
sys.stdin.readline()
|
||||
@ -796,8 +701,8 @@ class JerryDebugger(object):
|
||||
if not data: # Break the while loop if there is no more data.
|
||||
return DebuggerAction(DebuggerAction.END, "")
|
||||
|
||||
buffer_type = ord(data[2])
|
||||
buffer_size = ord(data[1]) - 1
|
||||
buffer_type = ord(data[0])
|
||||
buffer_size = len(data) -1
|
||||
|
||||
logging.debug("Main buffer type: %d, message size: %d", buffer_type, buffer_size)
|
||||
|
||||
@ -822,7 +727,7 @@ class JerryDebugger(object):
|
||||
self._release_function(data)
|
||||
|
||||
elif buffer_type in [JERRY_DEBUGGER_BREAKPOINT_HIT, JERRY_DEBUGGER_EXCEPTION_HIT]:
|
||||
breakpoint_data = struct.unpack(self.byte_order + self.cp_format + self.idx_format, data[3:])
|
||||
breakpoint_data = struct.unpack(self.byte_order + self.cp_format + self.idx_format, data[1:])
|
||||
|
||||
breakpoint = self._get_breakpoint(breakpoint_data)
|
||||
self.last_breakpoint_hit = breakpoint[0]
|
||||
@ -850,20 +755,20 @@ class JerryDebugger(object):
|
||||
return DebuggerAction(DebuggerAction.TEXT, result)
|
||||
|
||||
elif buffer_type == JERRY_DEBUGGER_EXCEPTION_STR:
|
||||
self.exception_string += data[3:]
|
||||
self.exception_string += data[1:]
|
||||
|
||||
elif buffer_type == JERRY_DEBUGGER_EXCEPTION_STR_END:
|
||||
self.exception_string += data[3:]
|
||||
self.exception_string += data[1:]
|
||||
|
||||
elif buffer_type == JERRY_DEBUGGER_BACKTRACE_TOTAL:
|
||||
total = struct.unpack(self.byte_order + self.idx_format, data[3:])[0]
|
||||
total = struct.unpack(self.byte_order + self.idx_format, data[1:])[0]
|
||||
result += "Total number of frames: %d\n" % (total)
|
||||
return DebuggerAction(DebuggerAction.TEXT, result)
|
||||
|
||||
elif buffer_type in [JERRY_DEBUGGER_BACKTRACE, JERRY_DEBUGGER_BACKTRACE_END]:
|
||||
frame_index = self.frame_index
|
||||
|
||||
buffer_pos = 3
|
||||
buffer_pos = 1
|
||||
while buffer_size > 0:
|
||||
breakpoint_data = struct.unpack(self.byte_order + self.cp_format + self.idx_format,
|
||||
data[buffer_pos: buffer_pos + self.cp_size + 4])
|
||||
@ -894,7 +799,7 @@ class JerryDebugger(object):
|
||||
elif buffer_type == JERRY_DEBUGGER_MEMSTATS_RECEIVE:
|
||||
|
||||
memory_stats = struct.unpack(self.byte_order + self.idx_format * 5,
|
||||
data[3: 3 + 4 * 5])
|
||||
data[1: 1 + 4 * 5])
|
||||
|
||||
result += "Allocated bytes: %s\n" % memory_stats[0]
|
||||
result += "Byte code bytes: %s\n" % memory_stats[1]
|
||||
@ -909,7 +814,7 @@ class JerryDebugger(object):
|
||||
self.send_client_source()
|
||||
|
||||
elif buffer_type in [JERRY_DEBUGGER_SCOPE_CHAIN, JERRY_DEBUGGER_SCOPE_CHAIN_END]:
|
||||
self.scopes = data[3:]
|
||||
self.scopes = data[1:]
|
||||
|
||||
if buffer_type == JERRY_DEBUGGER_SCOPE_CHAIN_END:
|
||||
result = self.process_scopes()
|
||||
@ -920,7 +825,7 @@ class JerryDebugger(object):
|
||||
return DebuggerAction(DebuggerAction.TEXT, result)
|
||||
|
||||
elif buffer_type in [JERRY_DEBUGGER_SCOPE_VARIABLES, JERRY_DEBUGGER_SCOPE_VARIABLES_END]:
|
||||
self.scope_vars += "".join(data[3:])
|
||||
self.scope_vars += "".join(data[1:])
|
||||
|
||||
if buffer_type == JERRY_DEBUGGER_SCOPE_VARIABLES_END:
|
||||
result = self.process_scope_variables()
|
||||
@ -988,8 +893,8 @@ class JerryDebugger(object):
|
||||
if data is None:
|
||||
return "Error: connection lost during source code receiving"
|
||||
|
||||
buffer_type = ord(data[2])
|
||||
buffer_size = ord(data[1]) - 1
|
||||
buffer_type = ord(data[0])
|
||||
buffer_size = len(data) - 1
|
||||
|
||||
logging.debug("Parser buffer type: %d, message size: %d", buffer_type, buffer_size)
|
||||
|
||||
@ -998,19 +903,19 @@ class JerryDebugger(object):
|
||||
return ""
|
||||
|
||||
elif buffer_type in [JERRY_DEBUGGER_SOURCE_CODE, JERRY_DEBUGGER_SOURCE_CODE_END]:
|
||||
source_code += data[3:]
|
||||
source_code += data[1:]
|
||||
|
||||
elif buffer_type in [JERRY_DEBUGGER_SOURCE_CODE_NAME, JERRY_DEBUGGER_SOURCE_CODE_NAME_END]:
|
||||
source_code_name += data[3:]
|
||||
source_code_name += data[1:]
|
||||
|
||||
elif buffer_type in [JERRY_DEBUGGER_FUNCTION_NAME, JERRY_DEBUGGER_FUNCTION_NAME_END]:
|
||||
function_name += data[3:]
|
||||
function_name += data[1:]
|
||||
|
||||
elif buffer_type == JERRY_DEBUGGER_PARSE_FUNCTION:
|
||||
logging.debug("Source name: %s, function name: %s", source_code_name, function_name)
|
||||
|
||||
position = struct.unpack(self.byte_order + self.idx_format + self.idx_format,
|
||||
data[3: 3 + 4 + 4])
|
||||
data[1: 1 + 4 + 4])
|
||||
|
||||
stack.append({"source": source_code,
|
||||
"source_name": source_code_name,
|
||||
@ -1028,7 +933,7 @@ class JerryDebugger(object):
|
||||
|
||||
logging.debug("Breakpoint %s received", name)
|
||||
|
||||
buffer_pos = 3
|
||||
buffer_pos = 1
|
||||
while buffer_size > 0:
|
||||
line = struct.unpack(self.byte_order + self.idx_format,
|
||||
data[buffer_pos: buffer_pos + 4])
|
||||
@ -1038,7 +943,7 @@ class JerryDebugger(object):
|
||||
|
||||
elif buffer_type == JERRY_DEBUGGER_BYTE_CODE_CP:
|
||||
byte_code_cp = struct.unpack(self.byte_order + self.cp_format,
|
||||
data[3: 3 + self.cp_size])[0]
|
||||
data[1: 1 + self.cp_size])[0]
|
||||
|
||||
logging.debug("Byte code cptr received: {0x%x}", byte_code_cp)
|
||||
|
||||
@ -1068,7 +973,7 @@ class JerryDebugger(object):
|
||||
elif buffer_type == JERRY_DEBUGGER_RELEASE_BYTE_CODE_CP:
|
||||
# Redefined functions are dropped during parsing.
|
||||
byte_code_cp = struct.unpack(self.byte_order + self.cp_format,
|
||||
data[3: 3 + self.cp_size])[0]
|
||||
data[1: 1 + self.cp_size])[0]
|
||||
|
||||
if byte_code_cp in new_function_list:
|
||||
del new_function_list[byte_code_cp]
|
||||
@ -1084,7 +989,7 @@ class JerryDebugger(object):
|
||||
logging.error("Parser error!")
|
||||
raise Exception("Unexpected message")
|
||||
|
||||
data = self.get_message(True)
|
||||
data = self.channel.get_message(True)
|
||||
|
||||
# Copy the ready list to the global storage.
|
||||
self.function_list.update(new_function_list)
|
||||
@ -1131,7 +1036,7 @@ class JerryDebugger(object):
|
||||
|
||||
def _release_function(self, data):
|
||||
byte_code_cp = struct.unpack(self.byte_order + self.cp_format,
|
||||
data[3: 3 + self.cp_size])[0]
|
||||
data[1: 1 + self.cp_size])[0]
|
||||
|
||||
function = self.function_list[byte_code_cp]
|
||||
|
||||
@ -1234,13 +1139,13 @@ class JerryDebugger(object):
|
||||
if buffer_type in [JERRY_DEBUGGER_EVAL_RESULT_END,
|
||||
JERRY_DEBUGGER_OUTPUT_RESULT_END]:
|
||||
subtype = ord(data[-1])
|
||||
message += data[3:-1]
|
||||
message += data[1:-1]
|
||||
break
|
||||
else:
|
||||
message += data[3:]
|
||||
message += data[1:]
|
||||
|
||||
data = self.get_message(True)
|
||||
buffer_type = ord(data[2])
|
||||
data = self.channel.get_message(True)
|
||||
buffer_type = ord(data[0])
|
||||
# Checks if the next frame would be an invalid data frame.
|
||||
# If it is not the message type, or the end type of it, an exception is thrown.
|
||||
if buffer_type not in [msg_type, msg_type + 1]:
|
||||
48
jerry-debugger/jerry_client_tcp.py
Normal file
48
jerry-debugger/jerry_client_tcp.py
Normal file
@ -0,0 +1,48 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# Copyright JS Foundation and other contributors, http://js.foundation
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import socket
|
||||
import select
|
||||
|
||||
class Socket(object):
|
||||
""" Create a new socket using the given address family, socket type and protocol number. """
|
||||
def __init__(self, socket_family=socket.AF_INET, socket_type=socket.SOCK_STREAM, proto=0, fileno=None):
|
||||
self.socket = socket.socket(socket_family, socket_type, proto, fileno)
|
||||
|
||||
def connect(self, address):
|
||||
"""
|
||||
Connect to a remote socket at address (host, port).
|
||||
The format of address depends on the address family.
|
||||
"""
|
||||
self.socket.connect(address)
|
||||
|
||||
def close(self):
|
||||
"""" Mark the socket closed. """
|
||||
self.socket.close()
|
||||
|
||||
def receive_data(self, max_size=1024):
|
||||
""" The maximum amount of data to be received at once is specified by max_size. """
|
||||
return self.socket.recv(max_size)
|
||||
|
||||
def send_data(self, data):
|
||||
""" Send data to the socket. The socket must be connected to a remote socket. """
|
||||
return self.socket.send(data)
|
||||
|
||||
def ready(self):
|
||||
""" Monitor the file descriptor. """
|
||||
result = select.select([self.socket], [], [], 0)[0]
|
||||
|
||||
return self.socket in result
|
||||
135
jerry-debugger/jerry_client_websocket.py
Normal file
135
jerry-debugger/jerry_client_websocket.py
Normal file
@ -0,0 +1,135 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# Copyright JS Foundation and other contributors, http://js.foundation
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import struct
|
||||
from jerry_client_tcp import Socket
|
||||
|
||||
MAX_BUFFER_SIZE = 128
|
||||
WEBSOCKET_BINARY_FRAME = 2
|
||||
WEBSOCKET_FIN_BIT = 0x80
|
||||
|
||||
class WebSocket(object):
|
||||
def __init__(self, address, protocol=Socket()):
|
||||
|
||||
self.data_buffer = b""
|
||||
self.protocol = protocol
|
||||
self.address = address
|
||||
|
||||
def __handshake(self):
|
||||
""" Client Handshake Request. """
|
||||
self.__send_data(b"GET /jerry-debugger HTTP/1.1\r\n" +
|
||||
b"Upgrade: websocket\r\n" +
|
||||
b"Connection: Upgrade\r\n" +
|
||||
b"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n")
|
||||
|
||||
# Expected answer from the handshake.
|
||||
expected = (b"HTTP/1.1 101 Switching Protocols\r\n" +
|
||||
b"Upgrade: websocket\r\n" +
|
||||
b"Connection: Upgrade\r\n" +
|
||||
b"Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n")
|
||||
|
||||
len_expected = len(expected)
|
||||
|
||||
while len(self.data_buffer) < len_expected:
|
||||
self.data_buffer += self.protocol.receive_data()
|
||||
|
||||
if self.data_buffer[0:len_expected] != expected:
|
||||
raise Exception("Unexpected handshake")
|
||||
|
||||
if len(self.data_buffer) > len_expected:
|
||||
self.data_buffer = self.data_buffer[len_expected:]
|
||||
else:
|
||||
self.data_buffer = b""
|
||||
|
||||
def connect(self, config_size):
|
||||
""" WebSockets connection. """
|
||||
self.protocol.connect(self.address)
|
||||
self.data_buffer = b""
|
||||
self.__handshake()
|
||||
|
||||
# It will return with the Network configurations, which has the following struct:
|
||||
# header [2] - opcode[1], size[1]
|
||||
# configuration [config_size]
|
||||
len_expected = config_size + 2
|
||||
|
||||
while len(self.data_buffer) < len_expected:
|
||||
self.data_buffer += self.protocol.receive_data()
|
||||
|
||||
expected = struct.pack("BB",
|
||||
WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT,
|
||||
config_size)
|
||||
|
||||
if self.data_buffer[0:2] != expected:
|
||||
raise Exception("Unexpected configuration")
|
||||
|
||||
result = self.data_buffer[2:len_expected]
|
||||
self.data_buffer = self.data_buffer[len_expected:]
|
||||
|
||||
return result
|
||||
|
||||
def __send_data(self, data):
|
||||
""" Private function to send data using the given protocol. """
|
||||
size = len(data)
|
||||
|
||||
while size > 0:
|
||||
bytes_send = self.protocol.send_data(data)
|
||||
if bytes_send < size:
|
||||
data = data[bytes_send:]
|
||||
size -= bytes_send
|
||||
|
||||
def send_message(self, byte_order, packed_data):
|
||||
""" Send message. """
|
||||
message = struct.pack(byte_order + "BBI",
|
||||
WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT,
|
||||
WEBSOCKET_FIN_BIT + struct.unpack(byte_order + "B", packed_data[0])[0],
|
||||
0) + packed_data[1:]
|
||||
|
||||
self.__send_data(message)
|
||||
|
||||
def close(self):
|
||||
""" Close the WebSockets connection. """
|
||||
self.protocol.close()
|
||||
|
||||
def get_message(self, blocking):
|
||||
""" Receive message. """
|
||||
|
||||
# Connection was closed
|
||||
if self.data_buffer is None:
|
||||
return None
|
||||
|
||||
while True:
|
||||
if len(self.data_buffer) >= 2:
|
||||
if ord(self.data_buffer[0]) != WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT:
|
||||
raise Exception("Unexpected data frame")
|
||||
|
||||
size = ord(self.data_buffer[1])
|
||||
if size == 0 or size >= 126:
|
||||
raise Exception("Unexpected data frame")
|
||||
|
||||
if len(self.data_buffer) >= size + 2:
|
||||
result = self.data_buffer[2:size + 2]
|
||||
self.data_buffer = self.data_buffer[size + 2:]
|
||||
return result
|
||||
|
||||
if not blocking and not self.protocol.ready():
|
||||
return b''
|
||||
|
||||
data = self.protocol.receive_data(MAX_BUFFER_SIZE)
|
||||
|
||||
if not data:
|
||||
self.data_buffer = None
|
||||
return None
|
||||
self.data_buffer += data
|
||||
Loading…
x
Reference in New Issue
Block a user