From 1a0ac066eca2873dfef1d370598ba4fa39646d14 Mon Sep 17 00:00:00 2001 From: Peter Gal Date: Tue, 8 Jan 2019 18:10:37 +0100 Subject: [PATCH] Update the debugger to work on Windows Changed the debugger-tcp.c file to include Windows specific socket handling code and mode user all components are compilable for Windows. Added appveyor configuration to build with and without debugger. JerryScript-DCO-1.0-Signed-off-by: Peter Gal pgal.u-szeged@partner.samsung.com --- appveyor.yml | 9 +- jerry-ext/CMakeLists.txt | 4 + jerry-ext/debugger/debugger-tcp.c | 191 +++++++++++++++++++++----- jerry-port/default/default-debugger.c | 10 +- jerry-port/default/default-io.c | 2 +- 5 files changed, 175 insertions(+), 41 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 29c981b023..e1537a4e03 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -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 diff --git a/jerry-ext/CMakeLists.txt b/jerry-ext/CMakeLists.txt index 4a3f0504f7..425d5db08a 100644 --- a/jerry-ext/CMakeLists.txt +++ b/jerry-ext/CMakeLists.txt @@ -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) diff --git a/jerry-ext/debugger/debugger-tcp.c b/jerry-ext/debugger/debugger-tcp.c index 12082f66e6..85e978948d 100644 --- a/jerry-ext/debugger/debugger-tcp.c +++ b/jerry-ext/debugger/debugger-tcp.c @@ -19,11 +19,39 @@ #ifdef JERRY_DEBUGGER -#include #include + +#ifdef WIN32 +#include +typedef SSIZE_T ssize_t; +#include +#include + +/* 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 #include -#include #include +#include + +/* 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. @@ -31,16 +59,66 @@ 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 */ /** @@ -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 */ @@ -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 (); @@ -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; @@ -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; @@ -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) @@ -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)); @@ -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; } diff --git a/jerry-port/default/default-debugger.c b/jerry-port/default/default-debugger.c index e32d661144..1550d2f83b 100644 --- a/jerry-port/default/default-debugger.c +++ b/jerry-port/default/default-debugger.c @@ -19,11 +19,13 @@ #define _XOPEN_SOURCE 500 #endif -#ifdef HAVE_TIME_H +#ifdef WIN32 +#include +#elif defined (HAVE_TIME_H) #include #elif defined (HAVE_UNISTD_H) #include -#endif /* HAVE_TIME_H */ +#endif /* WIN32 */ #include "jerryscript-port.h" #include "jerryscript-port-default.h" @@ -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; diff --git a/jerry-port/default/default-io.c b/jerry-port/default/default-io.c index 72dea34e76..affab21b2b 100644 --- a/jerry-port/default/default-io.c +++ b/jerry-port/default/default-io.c @@ -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);