Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,17 @@ platform:
- x64
- Win32

environment:
matrix:
- FEATURE_DEBUGGER: ON
- FEATURE_DEBUGGER: OFF

# Steps of a job.
init:
- cmake -version
before_build:
- if "%PLATFORM%"=="Win32" cmake -G"Visual Studio 15 2017" -Bbuild -H.
- if "%PLATFORM%"=="x64" cmake -G"Visual Studio 15 2017 Win64" -Bbuild -H.
- if "%PLATFORM%"=="Win32" cmake -G"Visual Studio 15 2017" -Bbuild -H. -DFEATURE_DEBUGGER=%FEATURE_DEBUGGER%
- if "%PLATFORM%"=="x64" cmake -G"Visual Studio 15 2017 Win64" -Bbuild -H. -DFEATURE_DEBUGGER=%FEATURE_DEBUGGER%
build:
project: build\Jerry.sln
parallel: true
Expand Down
4 changes: 4 additions & 0 deletions jerry-ext/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,9 @@ target_include_directories(${JERRY_EXT_NAME} PRIVATE ${INCLUDE_EXT_PRIVATE})
target_compile_definitions(${JERRY_EXT_NAME} PUBLIC ${DEFINES_EXT})
target_link_libraries(${JERRY_EXT_NAME} jerry-core)

if(USING_MSVC AND FEATURE_DEBUGGER)
target_link_libraries(${JERRY_EXT_NAME} ws2_32)
endif()

install(TARGETS ${JERRY_EXT_NAME} DESTINATION lib)
install(DIRECTORY ${INCLUDE_EXT_PUBLIC}/ DESTINATION include)
191 changes: 156 additions & 35 deletions jerry-ext/debugger/debugger-tcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,28 +19,106 @@

#ifdef JERRY_DEBUGGER

#include <arpa/inet.h>
#include <errno.h>

#ifdef WIN32
#include <BaseTsd.h>
typedef SSIZE_T ssize_t;
#include <WS2tcpip.h>
#include <winsock2.h>

/* On Windows the WSAEWOULDBLOCK value can be returned for non-blocking operations */
#define JERRYX_EWOULDBLOCK WSAEWOULDBLOCK

/* On Windows the invalid socket's value of INVALID_SOCKET */
#define JERRYX_SOCKET_INVALID INVALID_SOCKET

/* On Windows sockets have a SOCKET typedef */
typedef SOCKET jerryx_socket;

#else /* !WIN32 */

#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/socket.h>
#include <unistd.h>

/* On *nix the EWOULDBLOCK errno value can be returned for non-blocking operations */
#define JERRYX_EWOULDBLOCK EWOULDBLOCK

/* On *nix the invalid socket has a value of -1 */
#define JERRYX_SOCKET_INVALID (-1)

/* On *nix the sockets are integer identifiers */
typedef int jerryx_socket;
#endif /* WIN32 */

/**
* Implementation of transport over tcp/ip.
*/
typedef struct
{
jerry_debugger_transport_header_t header; /**< transport header */
int tcp_socket; /**< tcp socket */
jerryx_socket tcp_socket; /**< tcp socket */
} jerryx_debugger_transport_tcp_t;

/**
* Get the network error value.
*
* On Windows this returns the result of the `WSAGetLastError ()` call and
* on any other system the `errno` value.
*
*
* @return last error value.
*/
static inline int
jerryx_debugger_tcp_get_errno (void)
{
#ifdef WIN32
return WSAGetLastError ();
#else /* !WIN32 */
return errno;
#endif /* WIN32 */
} /* jerryx_debugger_tcp_get_errno */

/**
* Correctly close a single socket.
*/
static inline void
jerryx_debugger_tcp_close_socket (jerryx_socket socket_id) /**< socket to close */
{
#ifdef WIN32
closesocket (socket_id);
#else /* !WIN32 */
close (socket_id);
#endif /* WIN32 */
} /* jerryx_debugger_tcp_close_socket */

/**
* Log tcp error message.
*/
static void
jerryx_debugger_tcp_log_error (int err_val)
jerryx_debugger_tcp_log_error (int errno_value) /**< error value to log */
{
JERRYX_ERROR_MSG ("TCP Error: %s\n", strerror (err_val));
if (errno_value == 0)
{
return;
}

#ifdef WIN32
char *error_message = NULL;
FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
errno_value,
MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &error_message,
0,
NULL);
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "TCP Error: %s\n", error_message);
LocalFree (error_message);
#else /* !WIN32 */
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "TCP Error: %s\n", strerror (errno_value));
#endif /* WIN32 */
} /* jerryx_debugger_tcp_log_error */

/**
Expand All @@ -55,7 +133,7 @@ jerryx_debugger_tcp_close (jerry_debugger_transport_header_t *header_p) /**< tcp

JERRYX_DEBUG_MSG ("TCP connection closed.\n");

close (tcp_p->tcp_socket);
jerryx_debugger_tcp_close_socket (tcp_p->tcp_socket);

jerry_heap_free ((void *) header_p, sizeof (jerryx_debugger_transport_tcp_t));
} /* jerryx_debugger_tcp_close */
Expand All @@ -80,7 +158,7 @@ jerryx_debugger_tcp_send (jerry_debugger_transport_header_t *header_p, /**< tcp
#ifdef __linux__
ssize_t is_err = recv (tcp_p->tcp_socket, NULL, 0, MSG_PEEK);

if (is_err == 0 && errno != EWOULDBLOCK)
if (is_err == 0 && errno != JERRYX_EWOULDBLOCK)
{
int err_val = errno;
jerry_debugger_transport_close ();
Expand All @@ -93,12 +171,13 @@ jerryx_debugger_tcp_send (jerry_debugger_transport_header_t *header_p, /**< tcp

if (sent_bytes < 0)
{
if (errno == EWOULDBLOCK)
int err_val = jerryx_debugger_tcp_get_errno ();

if (err_val == JERRYX_EWOULDBLOCK)
{
continue;
}

int err_val = errno;
jerry_debugger_transport_close ();
jerryx_debugger_tcp_log_error (err_val);
return false;
Expand Down Expand Up @@ -128,9 +207,10 @@ jerryx_debugger_tcp_receive (jerry_debugger_transport_header_t *header_p, /**< t

if (length <= 0)
{
if (errno != EWOULDBLOCK || length == 0)
int err_val = jerryx_debugger_tcp_get_errno ();

if (err_val != JERRYX_EWOULDBLOCK || length == 0)
{
int err_val = errno;
jerry_debugger_transport_close ();
jerryx_debugger_tcp_log_error (err_val);
return false;
Expand All @@ -150,64 +230,104 @@ jerryx_debugger_tcp_receive (jerry_debugger_transport_header_t *header_p, /**< t
} /* jerryx_debugger_tcp_receive */

/**
* Create a tcp connection.
* Utility method to prepare the server socket to accept connections.
*
* @return true if successful,
* false otherwise
* The following steps are performed:
* * Configure address re-use.
* * Bind the socket to the given port
* * Start listening on the socket.
*
* @return true if everything is ok
* false if there was an error
*/
bool
jerryx_debugger_tcp_create (uint16_t port) /**< listening port */
static bool
jerryx_debugger_tcp_configure_socket (jerryx_socket server_socket, /** < socket to configure */
uint16_t port) /** < port number to be used for the socket */
{
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)
int opt_value = 1;

if (setsockopt (server_socket, SOL_SOCKET, SO_REUSEADDR, &opt_value, sizeof (int)) != 0)
{
JERRYX_ERROR_MSG ("Error: %s\n", strerror (errno));
return false;
}

int opt_value = 1;
if (bind (server_socket, (struct sockaddr *)&addr, sizeof (struct sockaddr_in)) != 0)
{
return false;
}

if (setsockopt (server_socket, SOL_SOCKET, SO_REUSEADDR, &opt_value, sizeof (int)) == -1)
if (listen (server_socket, 1) != 0)
{
close (server_socket);
JERRYX_ERROR_MSG ("Error: %s\n", strerror (errno));
return false;
}

if (bind (server_socket, (struct sockaddr *)&addr, sizeof (struct sockaddr)) == -1)
return true;
} /* jerryx_debugger_tcp_configure_socket */

/**
* Create a tcp connection.
*
* @return true if successful,
* false otherwise
*/
bool
jerryx_debugger_tcp_create (uint16_t port) /**< listening port */
{
#ifdef WIN32
WSADATA wsaData;
int wsa_init_status = WSAStartup (MAKEWORD (2, 2), &wsaData);
if (wsa_init_status != NO_ERROR)
{
JERRYX_ERROR_MSG ("WSA Error: %d\n", wsa_init_status);
return false;
}
#endif /* WIN32*/

jerryx_socket server_socket = socket (AF_INET, SOCK_STREAM, 0);
if (server_socket == JERRYX_SOCKET_INVALID)
{
close (server_socket);
JERRYX_ERROR_MSG ("Error: %s\n", strerror (errno));
jerryx_debugger_tcp_log_error (jerryx_debugger_tcp_get_errno ());
return false;
}

if (listen (server_socket, 1) == -1)
if (!jerryx_debugger_tcp_configure_socket (server_socket, port))
{
close (server_socket);
JERRYX_ERROR_MSG ("Error: %s\n", strerror (errno));
int error = jerryx_debugger_tcp_get_errno ();
jerryx_debugger_tcp_close_socket (server_socket);
jerryx_debugger_tcp_log_error (error);
return false;
}

JERRYX_DEBUG_MSG ("Waiting for client connection\n");

int tcp_socket = accept (server_socket, (struct sockaddr *)&addr, &sin_size);
struct sockaddr_in addr;
socklen_t sin_size = sizeof (struct sockaddr_in);

jerryx_socket tcp_socket = accept (server_socket, (struct sockaddr *)&addr, &sin_size);

close (server_socket);
jerryx_debugger_tcp_close_socket (server_socket);

if (tcp_socket == -1)
if (tcp_socket == JERRYX_SOCKET_INVALID)
{
JERRYX_ERROR_MSG ("Error: %s\n", strerror (errno));
jerryx_debugger_tcp_log_error (jerryx_debugger_tcp_get_errno ());
return false;
}

/* Set non-blocking mode. */
#ifdef WIN32
u_long nonblocking_enabled = 1;
if (ioctlsocket (tcp_socket, FIONBIO, &nonblocking_enabled) != NO_ERROR)
{
jerryx_debugger_tcp_close_socket (tcp_socket);
return false;
}
#else /* !WIN32 */
int socket_flags = fcntl (tcp_socket, F_GETFL, 0);

if (socket_flags < 0)
Expand All @@ -221,6 +341,7 @@ jerryx_debugger_tcp_create (uint16_t port) /**< listening port */
close (tcp_socket);
return false;
}
#endif /* WIN32 */

JERRYX_DEBUG_MSG ("Connected from: %s\n", inet_ntoa (addr.sin_addr));

Expand All @@ -231,7 +352,7 @@ jerryx_debugger_tcp_create (uint16_t port) /**< listening port */

if (!header_p)
{
close (tcp_socket);
jerryx_debugger_tcp_close_socket (tcp_socket);
return false;
}

Expand Down
10 changes: 7 additions & 3 deletions jerry-port/default/default-debugger.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@
#define _XOPEN_SOURCE 500
#endif

#ifdef HAVE_TIME_H
#ifdef WIN32
#include <windows.h>
#elif defined (HAVE_TIME_H)
#include <time.h>
#elif defined (HAVE_UNISTD_H)
#include <unistd.h>
#endif /* HAVE_TIME_H */
#endif /* WIN32 */

#include "jerryscript-port.h"
#include "jerryscript-port-default.h"
Expand All @@ -34,7 +36,9 @@
*/
void jerry_port_sleep (uint32_t sleep_time) /**< milliseconds to sleep */
{
#ifdef HAVE_TIME_H
#ifdef WIN32
Sleep (sleep_time);
#elif defined (HAVE_TIME_H)
struct timespec sleep_timespec;
sleep_timespec.tv_sec = (time_t) sleep_time / 1000;
sleep_timespec.tv_nsec = ((long int) sleep_time % 1000) * 1000000L;
Expand Down
2 changes: 1 addition & 1 deletion jerry-port/default/default-io.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ jerry_port_log (jerry_log_level_t level, /**< message log level */
va_end (args);
va_start (args, format);

char buffer[length + 1];
JERRY_VLA (char, buffer, length + 1);
vsnprintf (buffer, (size_t) length + 1, format, args);

fprintf (stderr, "%s", buffer);
Expand Down