Move low-level debugger connection handling into jerry-ext. (#2426)

JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
Zoltan Herczeg
2018-07-19 03:14:43 +02:00
committed by yichoi
parent 88589902e2
commit 76ff084dc7
15 changed files with 686 additions and 520 deletions
-370
View File
@@ -1,370 +0,0 @@
/* 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.
*/
/*
* FIPS-180-1 compliant SHA-1 implementation
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* The SHA-1 standard was published by NIST in 1993.
*
* http://www.itl.nist.gov/fipspubs/fip180-1.htm
*/
#include "debugger.h"
#ifdef JERRY_DEBUGGER
/**
* SHA-1 context structure.
*/
typedef struct
{
uint32_t total[2]; /**< number of bytes processed */
uint32_t state[5]; /**< intermediate digest state */
uint8_t buffer[64]; /**< data block being processed */
} jerry_sha1_context;
/* 32-bit integer manipulation macros (big endian). */
#define JERRY_SHA1_GET_UINT32_BE(n, b, i) \
{ \
(n) = (((uint32_t) (b)[(i) + 0]) << 24) \
| (((uint32_t) (b)[(i) + 1]) << 16) \
| (((uint32_t) (b)[(i) + 2]) << 8) \
| ((uint32_t) (b)[(i) + 3]); \
}
#define JERRY_SHA1_PUT_UINT32_BE(n, b, i) \
{ \
(b)[(i) + 0] = (uint8_t) ((n) >> 24); \
(b)[(i) + 1] = (uint8_t) ((n) >> 16); \
(b)[(i) + 2] = (uint8_t) ((n) >> 8); \
(b)[(i) + 3] = (uint8_t) ((n)); \
}
/**
* Initialize SHA-1 context.
*/
static void
jerry_sha1_init (jerry_sha1_context *sha1_context_p) /**< SHA-1 context */
{
memset (sha1_context_p, 0, sizeof (jerry_sha1_context));
sha1_context_p->total[0] = 0;
sha1_context_p->total[1] = 0;
sha1_context_p->state[0] = 0x67452301;
sha1_context_p->state[1] = 0xEFCDAB89;
sha1_context_p->state[2] = 0x98BADCFE;
sha1_context_p->state[3] = 0x10325476;
sha1_context_p->state[4] = 0xC3D2E1F0;
} /* jerry_sha1_init */
#define JERRY_SHA1_P(a, b, c, d, e, x) \
do { \
e += JERRY_SHA1_SHIFT (a, 5) + JERRY_SHA1_F (b, c, d) + K + x; \
b = JERRY_SHA1_SHIFT (b, 30); \
} while (0)
/**
* Update SHA-1 internal buffer status.
*/
static void
jerry_sha1_process (jerry_sha1_context *sha1_context_p, /**< SHA-1 context */
const uint8_t data[64]) /**< data buffer */
{
uint32_t temp, W[16], A, B, C, D, E;
JERRY_SHA1_GET_UINT32_BE (W[0], data, 0);
JERRY_SHA1_GET_UINT32_BE (W[1], data, 4);
JERRY_SHA1_GET_UINT32_BE (W[2], data, 8);
JERRY_SHA1_GET_UINT32_BE (W[3], data, 12);
JERRY_SHA1_GET_UINT32_BE (W[4], data, 16);
JERRY_SHA1_GET_UINT32_BE (W[5], data, 20);
JERRY_SHA1_GET_UINT32_BE (W[6], data, 24);
JERRY_SHA1_GET_UINT32_BE (W[7], data, 28);
JERRY_SHA1_GET_UINT32_BE (W[8], data, 32);
JERRY_SHA1_GET_UINT32_BE (W[9], data, 36);
JERRY_SHA1_GET_UINT32_BE (W[10], data, 40);
JERRY_SHA1_GET_UINT32_BE (W[11], data, 44);
JERRY_SHA1_GET_UINT32_BE (W[12], data, 48);
JERRY_SHA1_GET_UINT32_BE (W[13], data, 52);
JERRY_SHA1_GET_UINT32_BE (W[14], data, 56);
JERRY_SHA1_GET_UINT32_BE (W[15], data, 60);
#define JERRY_SHA1_SHIFT(x, n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
#define JERRY_SHA1_R(t) \
( \
temp = W[(t - 3) & 0x0F] ^ W[(t - 8) & 0x0F] ^ W[(t - 14) & 0x0F] ^ W[t & 0x0F], \
W[t & 0x0F] = JERRY_SHA1_SHIFT (temp, 1) \
)
A = sha1_context_p->state[0];
B = sha1_context_p->state[1];
C = sha1_context_p->state[2];
D = sha1_context_p->state[3];
E = sha1_context_p->state[4];
uint32_t K = 0x5A827999;
#define JERRY_SHA1_F(x, y, z) (z ^ (x & (y ^ z)))
JERRY_SHA1_P (A, B, C, D, E, W[0]);
JERRY_SHA1_P (E, A, B, C, D, W[1]);
JERRY_SHA1_P (D, E, A, B, C, W[2]);
JERRY_SHA1_P (C, D, E, A, B, W[3]);
JERRY_SHA1_P (B, C, D, E, A, W[4]);
JERRY_SHA1_P (A, B, C, D, E, W[5]);
JERRY_SHA1_P (E, A, B, C, D, W[6]);
JERRY_SHA1_P (D, E, A, B, C, W[7]);
JERRY_SHA1_P (C, D, E, A, B, W[8]);
JERRY_SHA1_P (B, C, D, E, A, W[9]);
JERRY_SHA1_P (A, B, C, D, E, W[10]);
JERRY_SHA1_P (E, A, B, C, D, W[11]);
JERRY_SHA1_P (D, E, A, B, C, W[12]);
JERRY_SHA1_P (C, D, E, A, B, W[13]);
JERRY_SHA1_P (B, C, D, E, A, W[14]);
JERRY_SHA1_P (A, B, C, D, E, W[15]);
JERRY_SHA1_P (E, A, B, C, D, JERRY_SHA1_R (16));
JERRY_SHA1_P (D, E, A, B, C, JERRY_SHA1_R (17));
JERRY_SHA1_P (C, D, E, A, B, JERRY_SHA1_R (18));
JERRY_SHA1_P (B, C, D, E, A, JERRY_SHA1_R (19));
#undef JERRY_SHA1_F
K = 0x6ED9EBA1;
#define JERRY_SHA1_F(x, y, z) (x ^ y ^ z)
JERRY_SHA1_P (A, B, C, D, E, JERRY_SHA1_R (20));
JERRY_SHA1_P (E, A, B, C, D, JERRY_SHA1_R (21));
JERRY_SHA1_P (D, E, A, B, C, JERRY_SHA1_R (22));
JERRY_SHA1_P (C, D, E, A, B, JERRY_SHA1_R (23));
JERRY_SHA1_P (B, C, D, E, A, JERRY_SHA1_R (24));
JERRY_SHA1_P (A, B, C, D, E, JERRY_SHA1_R (25));
JERRY_SHA1_P (E, A, B, C, D, JERRY_SHA1_R (26));
JERRY_SHA1_P (D, E, A, B, C, JERRY_SHA1_R (27));
JERRY_SHA1_P (C, D, E, A, B, JERRY_SHA1_R (28));
JERRY_SHA1_P (B, C, D, E, A, JERRY_SHA1_R (29));
JERRY_SHA1_P (A, B, C, D, E, JERRY_SHA1_R (30));
JERRY_SHA1_P (E, A, B, C, D, JERRY_SHA1_R (31));
JERRY_SHA1_P (D, E, A, B, C, JERRY_SHA1_R (32));
JERRY_SHA1_P (C, D, E, A, B, JERRY_SHA1_R (33));
JERRY_SHA1_P (B, C, D, E, A, JERRY_SHA1_R (34));
JERRY_SHA1_P (A, B, C, D, E, JERRY_SHA1_R (35));
JERRY_SHA1_P (E, A, B, C, D, JERRY_SHA1_R (36));
JERRY_SHA1_P (D, E, A, B, C, JERRY_SHA1_R (37));
JERRY_SHA1_P (C, D, E, A, B, JERRY_SHA1_R (38));
JERRY_SHA1_P (B, C, D, E, A, JERRY_SHA1_R (39));
#undef JERRY_SHA1_F
K = 0x8F1BBCDC;
#define JERRY_SHA1_F(x, y, z) ((x & y) | (z & (x | y)))
JERRY_SHA1_P (A, B, C, D, E, JERRY_SHA1_R (40));
JERRY_SHA1_P (E, A, B, C, D, JERRY_SHA1_R (41));
JERRY_SHA1_P (D, E, A, B, C, JERRY_SHA1_R (42));
JERRY_SHA1_P (C, D, E, A, B, JERRY_SHA1_R (43));
JERRY_SHA1_P (B, C, D, E, A, JERRY_SHA1_R (44));
JERRY_SHA1_P (A, B, C, D, E, JERRY_SHA1_R (45));
JERRY_SHA1_P (E, A, B, C, D, JERRY_SHA1_R (46));
JERRY_SHA1_P (D, E, A, B, C, JERRY_SHA1_R (47));
JERRY_SHA1_P (C, D, E, A, B, JERRY_SHA1_R (48));
JERRY_SHA1_P (B, C, D, E, A, JERRY_SHA1_R (49));
JERRY_SHA1_P (A, B, C, D, E, JERRY_SHA1_R (50));
JERRY_SHA1_P (E, A, B, C, D, JERRY_SHA1_R (51));
JERRY_SHA1_P (D, E, A, B, C, JERRY_SHA1_R (52));
JERRY_SHA1_P (C, D, E, A, B, JERRY_SHA1_R (53));
JERRY_SHA1_P (B, C, D, E, A, JERRY_SHA1_R (54));
JERRY_SHA1_P (A, B, C, D, E, JERRY_SHA1_R (55));
JERRY_SHA1_P (E, A, B, C, D, JERRY_SHA1_R (56));
JERRY_SHA1_P (D, E, A, B, C, JERRY_SHA1_R (57));
JERRY_SHA1_P (C, D, E, A, B, JERRY_SHA1_R (58));
JERRY_SHA1_P (B, C, D, E, A, JERRY_SHA1_R (59));
#undef JERRY_SHA1_F
K = 0xCA62C1D6;
#define JERRY_SHA1_F(x, y, z) (x ^ y ^ z)
JERRY_SHA1_P (A, B, C, D, E, JERRY_SHA1_R (60));
JERRY_SHA1_P (E, A, B, C, D, JERRY_SHA1_R (61));
JERRY_SHA1_P (D, E, A, B, C, JERRY_SHA1_R (62));
JERRY_SHA1_P (C, D, E, A, B, JERRY_SHA1_R (63));
JERRY_SHA1_P (B, C, D, E, A, JERRY_SHA1_R (64));
JERRY_SHA1_P (A, B, C, D, E, JERRY_SHA1_R (65));
JERRY_SHA1_P (E, A, B, C, D, JERRY_SHA1_R (66));
JERRY_SHA1_P (D, E, A, B, C, JERRY_SHA1_R (67));
JERRY_SHA1_P (C, D, E, A, B, JERRY_SHA1_R (68));
JERRY_SHA1_P (B, C, D, E, A, JERRY_SHA1_R (69));
JERRY_SHA1_P (A, B, C, D, E, JERRY_SHA1_R (70));
JERRY_SHA1_P (E, A, B, C, D, JERRY_SHA1_R (71));
JERRY_SHA1_P (D, E, A, B, C, JERRY_SHA1_R (72));
JERRY_SHA1_P (C, D, E, A, B, JERRY_SHA1_R (73));
JERRY_SHA1_P (B, C, D, E, A, JERRY_SHA1_R (74));
JERRY_SHA1_P (A, B, C, D, E, JERRY_SHA1_R (75));
JERRY_SHA1_P (E, A, B, C, D, JERRY_SHA1_R (76));
JERRY_SHA1_P (D, E, A, B, C, JERRY_SHA1_R (77));
JERRY_SHA1_P (C, D, E, A, B, JERRY_SHA1_R (78));
JERRY_SHA1_P (B, C, D, E, A, JERRY_SHA1_R (79));
#undef JERRY_SHA1_F
sha1_context_p->state[0] += A;
sha1_context_p->state[1] += B;
sha1_context_p->state[2] += C;
sha1_context_p->state[3] += D;
sha1_context_p->state[4] += E;
#undef JERRY_SHA1_SHIFT
#undef JERRY_SHA1_R
} /* jerry_sha1_process */
#undef JERRY_SHA1_P
/**
* SHA-1 update buffer.
*/
static void
jerry_sha1_update (jerry_sha1_context *sha1_context_p, /**< SHA-1 context */
const uint8_t *source_p, /**< source buffer */
size_t source_length) /**< length of source buffer */
{
size_t fill;
uint32_t left;
if (source_length == 0)
{
return;
}
left = sha1_context_p->total[0] & 0x3F;
fill = 64 - left;
sha1_context_p->total[0] += (uint32_t) source_length;
/* Check overflow. */
if (sha1_context_p->total[0] < (uint32_t) source_length)
{
sha1_context_p->total[1]++;
}
if (left && source_length >= fill)
{
memcpy ((void *) (sha1_context_p->buffer + left), source_p, fill);
jerry_sha1_process (sha1_context_p, sha1_context_p->buffer);
source_p += fill;
source_length -= fill;
left = 0;
}
while (source_length >= 64)
{
jerry_sha1_process (sha1_context_p, source_p);
source_p += 64;
source_length -= 64;
}
if (source_length > 0)
{
memcpy ((void *) (sha1_context_p->buffer + left), source_p, source_length);
}
} /* jerry_sha1_update */
/**
* SHA-1 final digest.
*/
static void
jerry_sha1_finish (jerry_sha1_context *sha1_context_p, /**< SHA-1 context */
uint8_t destination_p[20]) /**< result */
{
uint8_t buffer[16];
uint32_t high = (sha1_context_p->total[0] >> 29) | (sha1_context_p->total[1] << 3);
uint32_t low = (sha1_context_p->total[0] << 3);
uint32_t last = sha1_context_p->total[0] & 0x3F;
uint32_t padn = (last < 56) ? (56 - last) : (120 - last);
memset (buffer, 0, sizeof (buffer));
buffer[0] = 0x80;
while (padn > sizeof (buffer))
{
jerry_sha1_update (sha1_context_p, buffer, sizeof (buffer));
buffer[0] = 0;
padn -= (uint32_t) sizeof (buffer);
}
jerry_sha1_update (sha1_context_p, buffer, padn);
JERRY_SHA1_PUT_UINT32_BE (high, buffer, 0);
JERRY_SHA1_PUT_UINT32_BE (low, buffer, 4);
jerry_sha1_update (sha1_context_p, buffer, 8);
JERRY_SHA1_PUT_UINT32_BE (sha1_context_p->state[0], destination_p, 0);
JERRY_SHA1_PUT_UINT32_BE (sha1_context_p->state[1], destination_p, 4);
JERRY_SHA1_PUT_UINT32_BE (sha1_context_p->state[2], destination_p, 8);
JERRY_SHA1_PUT_UINT32_BE (sha1_context_p->state[3], destination_p, 12);
JERRY_SHA1_PUT_UINT32_BE (sha1_context_p->state[4], destination_p, 16);
} /* jerry_sha1_finish */
#undef JERRY_SHA1_GET_UINT32_BE
#undef JERRY_SHA1_PUT_UINT32_BE
/**
* Computes the SHA-1 value of the combination of the two input buffers.
*/
void
jerry_debugger_compute_sha1 (const uint8_t *source1_p, /**< first part of the input */
size_t source1_length, /**< length of the first part */
const uint8_t *source2_p, /**< second part of the input */
size_t source2_length, /**< length of the second part */
uint8_t destination_p[20]) /**< result */
{
JMEM_DEFINE_LOCAL_ARRAY (sha1_context_p, 1, jerry_sha1_context);
jerry_sha1_init (sha1_context_p);
jerry_sha1_update (sha1_context_p, source1_p, source1_length);
jerry_sha1_update (sha1_context_p, source2_p, source2_length);
jerry_sha1_finish (sha1_context_p, destination_p);
JMEM_FINALIZE_LOCAL_ARRAY (sha1_context_p);
} /* jerry_debugger_compute_sha1 */
#endif /* JERRY_DEBUGGER */
-237
View File
@@ -1,237 +0,0 @@
/* 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.
*/
#include "debugger-tcp.h"
#include "jrt.h"
#ifdef JERRY_DEBUGGER
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
/**
* Implementation of transport over tcp/ip.
*/
typedef struct
{
jerry_debugger_transport_header_t header; /**< transport header */
int tcp_socket; /**< tcp socket */
} jerry_debugger_transport_tcp_t;
/**
* Log tcp error message.
*/
static void
jerry_debugger_tcp_log_error (void)
{
JERRY_ERROR_MSG ("Error: %s\n", strerror (errno));
} /* jerry_debugger_tcp_log_error */
/**
* Close a tcp connection.
*/
static void
jerry_debugger_tcp_close (jerry_debugger_transport_header_t *header_p) /**< tcp implementation */
{
JERRY_ASSERT (jerry_debugger_transport_is_connected ());
jerry_debugger_transport_tcp_t *tcp_p = (jerry_debugger_transport_tcp_t *) header_p;
JERRY_DEBUG_MSG ("TCP connection closed.\n");
close (tcp_p->tcp_socket);
jerry_debugger_transport_free ((void *) header_p, sizeof (jerry_debugger_transport_tcp_t));
} /* jerry_debugger_tcp_close */
/**
* Send data over a tcp connection.
*
* @return true - if the data has been sent successfully
* false - otherwise
*/
static bool
jerry_debugger_tcp_send (jerry_debugger_transport_header_t *header_p, /**< tcp implementation */
uint8_t *message_p, /**< message to be sent */
size_t message_length) /**< message length in bytes */
{
JERRY_ASSERT (jerry_debugger_transport_is_connected ());
jerry_debugger_transport_tcp_t *tcp_p = (jerry_debugger_transport_tcp_t *) header_p;
do
{
ssize_t sent_bytes = send (tcp_p->tcp_socket, message_p, message_length, 0);
if (sent_bytes < 0)
{
if (errno == EWOULDBLOCK)
{
continue;
}
jerry_debugger_tcp_log_error ();
jerry_debugger_transport_close ();
return false;
}
message_p += sent_bytes;
message_length -= (size_t) sent_bytes;
}
while (message_length > 0);
return true;
} /* jerry_debugger_tcp_send */
/**
* Receive data from a tcp connection.
*/
static bool
jerry_debugger_tcp_receive (jerry_debugger_transport_header_t *header_p, /**< tcp implementation */
jerry_debugger_transport_receive_context_t *receive_context_p) /**< receive context */
{
jerry_debugger_transport_tcp_t *tcp_p = (jerry_debugger_transport_tcp_t *) header_p;
uint8_t *buffer_p = receive_context_p->buffer_p + receive_context_p->received_length;
size_t buffer_size = JERRY_DEBUGGER_TRANSPORT_MAX_BUFFER_SIZE - receive_context_p->received_length;
ssize_t length = recv (tcp_p->tcp_socket, buffer_p, buffer_size, 0);
if (length < 0)
{
if (errno != EWOULDBLOCK)
{
jerry_debugger_tcp_log_error ();
jerry_debugger_transport_close ();
return false;
}
length = 0;
}
receive_context_p->received_length += (size_t) length;
if (receive_context_p->received_length > 0)
{
receive_context_p->message_p = receive_context_p->buffer_p;
receive_context_p->message_length = receive_context_p->received_length;
}
return true;
} /* jerry_debugger_tcp_receive */
/**
* Create a tcp connection.
*
* @return true if successful,
* false otherwise
*/
bool
jerry_debugger_tcp_create (uint16_t port) /**< listening port */
{
int server_socket;
struct sockaddr_in addr;
socklen_t sin_size = sizeof (struct sockaddr_in);
addr.sin_family = AF_INET;
addr.sin_port = htons (port);
addr.sin_addr.s_addr = INADDR_ANY;
if ((server_socket = socket (AF_INET, SOCK_STREAM, 0)) == -1)
{
JERRY_ERROR_MSG ("Error: %s\n", strerror (errno));
return false;
}
int opt_value = 1;
if (setsockopt (server_socket, SOL_SOCKET, SO_REUSEADDR, &opt_value, sizeof (int)) == -1)
{
close (server_socket);
JERRY_ERROR_MSG ("Error: %s\n", strerror (errno));
return false;
}
if (bind (server_socket, (struct sockaddr *)&addr, sizeof (struct sockaddr)) == -1)
{
close (server_socket);
JERRY_ERROR_MSG ("Error: %s\n", strerror (errno));
return false;
}
if (listen (server_socket, 1) == -1)
{
close (server_socket);
JERRY_ERROR_MSG ("Error: %s\n", strerror (errno));
return false;
}
JERRY_DEBUG_MSG ("Waiting for client connection\n");
int tcp_socket = accept (server_socket, (struct sockaddr *)&addr, &sin_size);
close (server_socket);
if (tcp_socket == -1)
{
JERRY_ERROR_MSG ("Error: %s\n", strerror (errno));
return false;
}
/* Set non-blocking mode. */
int socket_flags = fcntl (tcp_socket, F_GETFL, 0);
if (socket_flags < 0)
{
close (tcp_socket);
return false;
}
if (fcntl (tcp_socket, F_SETFL, socket_flags | O_NONBLOCK) == -1)
{
close (tcp_socket);
return false;
}
JERRY_DEBUG_MSG ("Connected from: %s\n", inet_ntoa (addr.sin_addr));
size_t size = sizeof (jerry_debugger_transport_tcp_t);
jerry_debugger_transport_header_t *header_p;
header_p = (jerry_debugger_transport_header_t *) jerry_debugger_transport_malloc (size);
if (!header_p)
{
close (tcp_socket);
return false;
}
header_p->close = jerry_debugger_tcp_close;
header_p->send = jerry_debugger_tcp_send;
header_p->receive = jerry_debugger_tcp_receive;
((jerry_debugger_transport_tcp_t *) header_p)->tcp_socket = tcp_socket;
jerry_debugger_transport_add (header_p,
0,
JERRY_DEBUGGER_TRANSPORT_MAX_BUFFER_SIZE,
0,
JERRY_DEBUGGER_TRANSPORT_MAX_BUFFER_SIZE);
return true;
} /* jerry_debugger_tcp_create */
#endif /* JERRY_DEBUGGER */
-27
View File
@@ -1,27 +0,0 @@
/* 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.
*/
#ifndef DEBUGGER_TCP_H
#define DEBUGGER_TCP_H
#include "jerryscript-debugger-transport.h"
#ifdef JERRY_DEBUGGER
bool jerry_debugger_tcp_create (uint16_t port);
#endif /* JERRY_DEBUGGER */
#endif /* !DEBUGGER_TCP_H */
-451
View File
@@ -1,451 +0,0 @@
/* 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.
*/
#include "debugger-ws.h"
#include "jrt.h"
#ifdef JERRY_DEBUGGER
/* JerryScript debugger protocol is a simplified version of RFC-6455 (WebSockets). */
/**
* Last fragment of a Websocket package.
*/
#define JERRY_DEBUGGER_WEBSOCKET_FIN_BIT 0x80
/**
* Masking-key is available.
*/
#define JERRY_DEBUGGER_WEBSOCKET_MASK_BIT 0x80
/**
* Opcode type mask.
*/
#define JERRY_DEBUGGER_WEBSOCKET_OPCODE_MASK 0x0fu
/**
* Packet length mask.
*/
#define JERRY_DEBUGGER_WEBSOCKET_LENGTH_MASK 0x7fu
/**
* Size of websocket header size.
*/
#define JERRY_DEBUGGER_WEBSOCKET_HEADER_SIZE 2
/**
* Payload mask size in bytes of a websocket package.
*/
#define JERRY_DEBUGGER_WEBSOCKET_MASK_SIZE 4
/**
* Maximum message size with 1 byte size field.
*/
#define JERRY_DEBUGGER_WEBSOCKET_ONE_BYTE_LEN_MAX 125
/**
* WebSocket opcode types.
*/
typedef enum
{
JERRY_DEBUGGER_WEBSOCKET_TEXT_FRAME = 1, /**< text frame */
JERRY_DEBUGGER_WEBSOCKET_BINARY_FRAME = 2, /**< binary frame */
JERRY_DEBUGGER_WEBSOCKET_CLOSE_CONNECTION = 8, /**< close connection */
JERRY_DEBUGGER_WEBSOCKET_PING = 9, /**< ping (keep alive) frame */
JERRY_DEBUGGER_WEBSOCKET_PONG = 10, /**< reply to ping frame */
} jerry_websocket_opcode_type_t;
/**
* Header for incoming packets.
*/
typedef struct
{
uint8_t ws_opcode; /**< websocket opcode */
uint8_t size; /**< size of the message */
uint8_t mask[4]; /**< mask bytes */
} jerry_websocket_receive_header_t;
/**
* Convert a 6-bit value to a Base64 character.
*
* @return Base64 character
*/
static uint8_t
jerry_to_base64_character (uint8_t value) /**< 6-bit value */
{
if (value < 26)
{
return (uint8_t) (value + 'A');
}
if (value < 52)
{
return (uint8_t) (value - 26 + 'a');
}
if (value < 62)
{
return (uint8_t) (value - 52 + '0');
}
if (value == 62)
{
return (uint8_t) '+';
}
return (uint8_t) '/';
} /* jerry_to_base64_character */
/**
* Encode a byte sequence into Base64 string.
*/
static void
jerry_to_base64 (const uint8_t *source_p, /**< source data */
uint8_t *destination_p, /**< destination buffer */
size_t length) /**< length of source, must be divisible by 3 */
{
while (length >= 3)
{
uint8_t value = (source_p[0] >> 2);
destination_p[0] = jerry_to_base64_character (value);
value = (uint8_t) (((source_p[0] << 4) | (source_p[1] >> 4)) & 0x3f);
destination_p[1] = jerry_to_base64_character (value);
value = (uint8_t) (((source_p[1] << 2) | (source_p[2] >> 6)) & 0x3f);
destination_p[2] = jerry_to_base64_character (value);
value = (uint8_t) (source_p[2] & 0x3f);
destination_p[3] = jerry_to_base64_character (value);
source_p += 3;
destination_p += 4;
length -= 3;
}
} /* jerry_to_base64 */
/**
* Process WebSocket handshake.
*
* @return true - if the handshake was completed successfully
* false - otherwise
*/
static bool
jerry_process_handshake (uint8_t *request_buffer_p) /**< temporary buffer */
{
size_t request_buffer_size = 1024;
uint8_t *request_end_p = request_buffer_p;
/* Buffer request text until the double newlines are received. */
while (true)
{
jerry_debugger_transport_receive_context_t context;
if (!jerry_debugger_transport_receive (&context))
{
JERRY_ASSERT (!jerry_debugger_transport_is_connected ());
return false;
}
if (context.message_p == NULL)
{
jerry_debugger_transport_sleep ();
continue;
}
size_t length = request_buffer_size - 1u - (size_t) (request_end_p - request_buffer_p);
if (length < context.message_length)
{
JERRY_ERROR_MSG ("Handshake buffer too small.\n");
return false;
}
/* Both stream and datagram packets are supported. */
memcpy (request_end_p, context.message_p, context.message_length);
jerry_debugger_transport_receive_completed (&context);
request_end_p += (size_t) context.message_length;
*request_end_p = 0;
if (request_end_p > request_buffer_p + 4
&& memcmp (request_end_p - 4, "\r\n\r\n", 4) == 0)
{
break;
}
}
/* Check protocol. */
const char *text_p = "GET /jerry-debugger";
size_t text_len = strlen (text_p);
if ((size_t) (request_end_p - request_buffer_p) < text_len
|| memcmp (request_buffer_p, text_p, text_len) != 0)
{
JERRY_ERROR_MSG ("Invalid handshake format.\n");
return false;
}
uint8_t *websocket_key_p = request_buffer_p + text_len;
text_p = "Sec-WebSocket-Key:";
text_len = strlen (text_p);
while (true)
{
if ((size_t) (request_end_p - websocket_key_p) < text_len)
{
JERRY_ERROR_MSG ("Sec-WebSocket-Key not found.\n");
return false;
}
if (websocket_key_p[0] == 'S'
&& websocket_key_p[-1] == '\n'
&& websocket_key_p[-2] == '\r'
&& memcmp (websocket_key_p, text_p, text_len) == 0)
{
websocket_key_p += text_len;
break;
}
websocket_key_p++;
}
/* String terminated by double newlines. */
while (*websocket_key_p == ' ')
{
websocket_key_p++;
}
uint8_t *websocket_key_end_p = websocket_key_p;
while (*websocket_key_end_p > ' ')
{
websocket_key_end_p++;
}
/* Since the request_buffer_p is not needed anymore it can
* be reused for storing the SHA-1 key and Base64 string. */
const size_t sha1_length = 20;
jerry_debugger_compute_sha1 (websocket_key_p,
(size_t) (websocket_key_end_p - websocket_key_p),
(const uint8_t *) "258EAFA5-E914-47DA-95CA-C5AB0DC85B11",
36,
request_buffer_p);
/* The SHA-1 key is 20 bytes long but jerry_to_base64 expects
* a length divisible by 3 so an extra 0 is appended at the end. */
request_buffer_p[sha1_length] = 0;
jerry_to_base64 (request_buffer_p, request_buffer_p + sha1_length + 1, sha1_length + 1);
/* Last value must be replaced by equal sign. */
text_p = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: ";
if (!jerry_debugger_transport_send ((const uint8_t *) text_p, strlen (text_p))
|| !jerry_debugger_transport_send (request_buffer_p + sha1_length + 1, 27))
{
return false;
}
text_p = "=\r\n\r\n";
return jerry_debugger_transport_send ((const uint8_t *) text_p, strlen (text_p));
} /* jerry_process_handshake */
/**
* Close a tcp connection.
*/
static void
jerry_debugger_ws_close (jerry_debugger_transport_header_t *header_p) /**< tcp implementation */
{
JERRY_ASSERT (jerry_debugger_transport_is_connected ());
jerry_debugger_transport_free ((void *) header_p, sizeof (jerry_debugger_transport_header_t));
} /* jerry_debugger_ws_close */
/**
* Send data over a websocket connection.
*
* @return true - if the data has been sent successfully
* false - otherwise
*/
static bool
jerry_debugger_ws_send (jerry_debugger_transport_header_t *header_p, /**< tcp implementation */
uint8_t *message_p, /**< message to be sent */
size_t message_length) /**< message length in bytes */
{
JERRY_ASSERT (message_length <= JERRY_DEBUGGER_WEBSOCKET_ONE_BYTE_LEN_MAX);
message_p[-2] = JERRY_DEBUGGER_WEBSOCKET_FIN_BIT | JERRY_DEBUGGER_WEBSOCKET_BINARY_FRAME;
message_p[-1] = (uint8_t) message_length;
return header_p->next_p->send (header_p->next_p, message_p - 2, message_length + 2);
} /* jerry_debugger_ws_send */
/**
* Receive data from a websocket connection.
*/
static bool
jerry_debugger_ws_receive (jerry_debugger_transport_header_t *header_p, /**< tcp implementation */
jerry_debugger_transport_receive_context_t *receive_context_p) /**< receive context */
{
if (!header_p->next_p->receive (header_p->next_p, receive_context_p))
{
return false;
}
if (receive_context_p->message_p == NULL)
{
return true;
}
size_t message_total_length = receive_context_p->message_total_length;
if (message_total_length == 0)
{
/* Byte stream. */
if (receive_context_p->message_length < sizeof (jerry_websocket_receive_header_t))
{
receive_context_p->message_p = NULL;
return true;
}
}
else
{
/* Datagram packet. */
JERRY_ASSERT (receive_context_p->message_length >= sizeof (jerry_websocket_receive_header_t));
}
uint8_t *message_p = receive_context_p->message_p;
if ((message_p[0] & ~JERRY_DEBUGGER_WEBSOCKET_OPCODE_MASK) != JERRY_DEBUGGER_WEBSOCKET_FIN_BIT
|| (message_p[1] & JERRY_DEBUGGER_WEBSOCKET_LENGTH_MASK) > JERRY_DEBUGGER_WEBSOCKET_ONE_BYTE_LEN_MAX
|| !(message_p[1] & JERRY_DEBUGGER_WEBSOCKET_MASK_BIT))
{
JERRY_ERROR_MSG ("Unsupported Websocket message.\n");
jerry_debugger_transport_close ();
return false;
}
if ((message_p[0] & JERRY_DEBUGGER_WEBSOCKET_OPCODE_MASK) != JERRY_DEBUGGER_WEBSOCKET_BINARY_FRAME)
{
JERRY_ERROR_MSG ("Unsupported Websocket opcode.\n");
jerry_debugger_transport_close ();
return false;
}
size_t message_length = (size_t) (message_p[1] & JERRY_DEBUGGER_WEBSOCKET_LENGTH_MASK);
if (message_total_length == 0)
{
size_t new_total_length = message_length + sizeof (jerry_websocket_receive_header_t);
/* Byte stream. */
if (receive_context_p->message_length < new_total_length)
{
receive_context_p->message_p = NULL;
return true;
}
receive_context_p->message_total_length = new_total_length;
}
else
{
/* Datagram packet. */
JERRY_ASSERT (receive_context_p->message_length == (message_length + sizeof (jerry_websocket_receive_header_t)));
}
message_p += sizeof (jerry_websocket_receive_header_t);
receive_context_p->message_p = message_p;
receive_context_p->message_length = message_length;
/* Unmask data bytes. */
const uint8_t *mask_p = message_p - JERRY_DEBUGGER_WEBSOCKET_MASK_SIZE;
const uint8_t *mask_end_p = message_p;
const uint8_t *message_end_p = message_p + message_length;
while (message_p < message_end_p)
{
/* Invert certain bits with xor operation. */
*message_p = *message_p ^ *mask_p;
message_p++;
mask_p++;
if (JERRY_UNLIKELY (mask_p >= mask_end_p))
{
mask_p -= JERRY_DEBUGGER_WEBSOCKET_MASK_SIZE;
}
}
return true;
} /* jerry_debugger_ws_receive */
/**
* Initialize the websocket transportation layer.
*
* @return true - if the connection succeeded
* false - otherwise
*/
bool
jerry_debugger_ws_create (void)
{
bool is_handshake_ok = false;
const size_t buffer_size = 1024;
uint8_t *request_buffer_p = (uint8_t *) jerry_debugger_transport_malloc (buffer_size);
if (!request_buffer_p)
{
return false;
}
is_handshake_ok = jerry_process_handshake (request_buffer_p);
jerry_debugger_transport_free ((void *) request_buffer_p, buffer_size);
if (!is_handshake_ok && jerry_debugger_transport_is_connected ())
{
return false;
}
const size_t interface_size = sizeof (jerry_debugger_transport_header_t);
jerry_debugger_transport_header_t *header_p;
header_p = (jerry_debugger_transport_header_t *) jerry_debugger_transport_malloc (interface_size);
if (!header_p)
{
return false;
}
header_p->close = jerry_debugger_ws_close;
header_p->send = jerry_debugger_ws_send;
header_p->receive = jerry_debugger_ws_receive;
jerry_debugger_transport_add (header_p,
JERRY_DEBUGGER_WEBSOCKET_HEADER_SIZE,
JERRY_DEBUGGER_WEBSOCKET_ONE_BYTE_LEN_MAX,
JERRY_DEBUGGER_WEBSOCKET_HEADER_SIZE + JERRY_DEBUGGER_WEBSOCKET_MASK_SIZE,
JERRY_DEBUGGER_WEBSOCKET_ONE_BYTE_LEN_MAX);
return true;
} /* jerry_debugger_ws_create */
#endif /* JERRY_DEBUGGER */
-33
View File
@@ -1,33 +0,0 @@
/* 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.
*/
#ifndef DEBUGGER_WS_H
#define DEBUGGER_WS_H
#include "jerryscript-debugger-transport.h"
#ifdef JERRY_DEBUGGER
/* JerryScript debugger protocol is a simplified version of RFC-6455 (WebSockets). */
bool jerry_debugger_ws_create (void);
void jerry_debugger_compute_sha1 (const uint8_t *input1, size_t input1_len,
const uint8_t *input2, size_t input2_len,
uint8_t output[20]);
#endif /* JERRY_DEBUGGER */
#endif /* !DEBUGGER_WS_H */
-1
View File
@@ -16,7 +16,6 @@
#ifndef DEBUGGER_H
#define DEBUGGER_H
#include "debugger-ws.h"
#include "ecma-globals.h"
#include "jerryscript-debugger-transport.h"