diff options
Diffstat (limited to '')
-rw-r--r-- | src/civetweb/src/third_party/duktape-1.8.0/examples/debug-trans-socket/duk_trans_socket_windows.c | 414 |
1 files changed, 414 insertions, 0 deletions
diff --git a/src/civetweb/src/third_party/duktape-1.8.0/examples/debug-trans-socket/duk_trans_socket_windows.c b/src/civetweb/src/third_party/duktape-1.8.0/examples/debug-trans-socket/duk_trans_socket_windows.c new file mode 100644 index 000000000..e92ac2660 --- /dev/null +++ b/src/civetweb/src/third_party/duktape-1.8.0/examples/debug-trans-socket/duk_trans_socket_windows.c @@ -0,0 +1,414 @@ +/* + * Example debug transport using a Windows TCP socket + * + * Provides a TCP server socket which a debug client can connect to. + * After that data is just passed through. + * + * https://msdn.microsoft.com/en-us/library/windows/desktop/ms737593(v=vs.85).aspx + * + * Compiling 'duk' with debugger support using MSVC (Visual Studio): + * + * > cl /W3 /O2 /Feduk.exe + * /DDUK_OPT_DEBUGGER_SUPPORT /DDUK_OPT_INTERRUPT_COUNTER + * /DDUK_CMDLINE_DEBUGGER_SUPPORT + * /Iexamples\debug-trans-socket /Isrc + * examples\cmdline\duk_cmdline.c + * examples\debug-trans-socket\duk_trans_socket_windows.c + * src\duktape.c + * + * With MinGW: + * + * $ gcc -oduk.exe -Wall -O2 \ + * -DDUK_OPT_DEBUGGER_SUPPORT -DDUK_OPT_INTERRUPT_COUNTER \ + * -DDUK_CMDLINE_DEBUGGER_SUPPORT \ + * -Iexamples/debug-trans-socket -Isrc \ + * examples/cmdline/duk_cmdline.c \ + * examples/debug-trans-socket/duk_trans_socket_windows.c \ + * src/duktape.c -lm -lws2_32 + */ + +#undef UNICODE +#if !defined(WIN32_LEAN_AND_MEAN) +#define WIN32_LEAN_AND_MEAN +#endif + +/* MinGW workaround for missing getaddrinfo() etc: + * http://programmingrants.blogspot.fi/2009/09/tips-on-undefined-reference-to.html + */ +#if defined(__MINGW32__) || defined(__MINGW64__) +#if !defined(_WIN32_WINNT) +#define _WIN32_WINNT 0x0501 +#endif +#endif + +#include <windows.h> +#include <winsock2.h> +#include <ws2tcpip.h> +#include <stdio.h> +#include <string.h> +#include "duktape.h" + +#if defined(_MSC_VER) +#pragma comment (lib, "Ws2_32.lib") +#endif + +#if !defined(DUK_DEBUG_PORT) +#define DUK_DEBUG_PORT 9091 +#endif +#if !defined(DUK_DEBUG_ADDRESS) +#define DUK_DEBUG_ADDRESS "0.0.0.0" +#endif +#define DUK__STRINGIFY_HELPER(x) #x +#define DUK__STRINGIFY(x) DUK__STRINGIFY_HELPER(x) + +#if 0 +#define DEBUG_PRINTS +#endif + +static SOCKET server_sock = INVALID_SOCKET; +static SOCKET client_sock = INVALID_SOCKET; +static int wsa_inited = 0; + +/* + * Transport init and finish + */ + +void duk_trans_socket_init(void) { + WSADATA wsa_data; + struct addrinfo hints; + struct addrinfo *result = NULL; + int rc; + + memset((void *) &wsa_data, 0, sizeof(wsa_data)); + memset((void *) &hints, 0, sizeof(hints)); + + rc = WSAStartup(MAKEWORD(2, 2), &wsa_data); + if (rc != 0) { + fprintf(stderr, "%s: WSAStartup() failed: %d\n", __FILE__, rc); + fflush(stderr); + goto fail; + } + wsa_inited = 1; + + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + hints.ai_flags = AI_PASSIVE; + + rc = getaddrinfo(DUK_DEBUG_ADDRESS, DUK__STRINGIFY(DUK_DEBUG_PORT), &hints, &result); + if (rc != 0) { + fprintf(stderr, "%s: getaddrinfo() failed: %d\n", __FILE__, rc); + fflush(stderr); + goto fail; + } + + server_sock = socket(result->ai_family, result->ai_socktype, result->ai_protocol); + if (server_sock == INVALID_SOCKET) { + fprintf(stderr, "%s: socket() failed with error: %ld\n", + __FILE__, (long) WSAGetLastError()); + fflush(stderr); + goto fail; + } + + rc = bind(server_sock, result->ai_addr, (int) result->ai_addrlen); + if (rc == SOCKET_ERROR) { + fprintf(stderr, "%s: bind() failed with error: %ld\n", + __FILE__, (long) WSAGetLastError()); + fflush(stderr); + goto fail; + } + + rc = listen(server_sock, SOMAXCONN); + if (rc == SOCKET_ERROR) { + fprintf(stderr, "%s: listen() failed with error: %ld\n", + __FILE__, (long) WSAGetLastError()); + fflush(stderr); + goto fail; + } + + if (result != NULL) { + freeaddrinfo(result); + result = NULL; + } + return; + + fail: + if (result != NULL) { + freeaddrinfo(result); + result = NULL; + } + if (server_sock != INVALID_SOCKET) { + (void) closesocket(server_sock); + server_sock = INVALID_SOCKET; + } + if (wsa_inited) { + WSACleanup(); + wsa_inited = 0; + } +} + +void duk_trans_socket_finish(void) { + if (client_sock != INVALID_SOCKET) { + (void) closesocket(client_sock); + client_sock = INVALID_SOCKET; + } + if (server_sock != INVALID_SOCKET) { + (void) closesocket(server_sock); + server_sock = INVALID_SOCKET; + } + if (wsa_inited) { + WSACleanup(); + wsa_inited = 0; + } +} + +void duk_trans_socket_waitconn(void) { + if (server_sock == INVALID_SOCKET) { + fprintf(stderr, "%s: no server socket, skip waiting for connection\n", + __FILE__); + fflush(stderr); + return; + } + if (client_sock != INVALID_SOCKET) { + (void) closesocket(client_sock); + client_sock = INVALID_SOCKET; + } + + fprintf(stderr, "Waiting for debug connection on port %d\n", (int) DUK_DEBUG_PORT); + fflush(stderr); + + client_sock = accept(server_sock, NULL, NULL); + if (client_sock == INVALID_SOCKET) { + fprintf(stderr, "%s: accept() failed with error %ld, skip waiting for connection\n", + __FILE__, (long) WSAGetLastError()); + fflush(stderr); + goto fail; + } + + fprintf(stderr, "Debug connection established\n"); + fflush(stderr); + + /* XXX: For now, close the listen socket because we won't accept new + * connections anyway. A better implementation would allow multiple + * debug attaches. + */ + + if (server_sock != INVALID_SOCKET) { + (void) closesocket(server_sock); + server_sock = INVALID_SOCKET; + } + return; + + fail: + if (client_sock != INVALID_SOCKET) { + (void) closesocket(client_sock); + client_sock = INVALID_SOCKET; + } +} + +/* + * Duktape callbacks + */ + +/* Duktape debug transport callback: (possibly partial) read. */ +duk_size_t duk_trans_socket_read_cb(void *udata, char *buffer, duk_size_t length) { + int ret; + + (void) udata; /* not needed by the example */ + +#if defined(DEBUG_PRINTS) + fprintf(stderr, "%s: udata=%p, buffer=%p, length=%ld\n", + __FUNCTION__, (void *) udata, (void *) buffer, (long) length); + fflush(stderr); +#endif + + if (client_sock == INVALID_SOCKET) { + return 0; + } + + if (length == 0) { + /* This shouldn't happen. */ + fprintf(stderr, "%s: read request length == 0, closing connection\n", + __FILE__); + fflush(stderr); + goto fail; + } + + if (buffer == NULL) { + /* This shouldn't happen. */ + fprintf(stderr, "%s: read request buffer == NULL, closing connection\n", + __FILE__); + fflush(stderr); + goto fail; + } + + /* In a production quality implementation there would be a sanity + * timeout here to recover from "black hole" disconnects. + */ + + ret = recv(client_sock, (void *) buffer, (int) length, 0); + if (ret < 0) { + fprintf(stderr, "%s: debug read failed, error %d, closing connection\n", + __FILE__, ret); + fflush(stderr); + goto fail; + } else if (ret == 0) { + fprintf(stderr, "%s: debug read failed, ret == 0 (EOF), closing connection\n", + __FILE__); + fflush(stderr); + goto fail; + } else if (ret > (int) length) { + fprintf(stderr, "%s: debug read failed, ret too large (%ld > %ld), closing connection\n", + __FILE__, (long) ret, (long) length); + fflush(stderr); + goto fail; + } + + return (duk_size_t) ret; + + fail: + if (client_sock != INVALID_SOCKET) { + (void) closesocket(client_sock); + client_sock = INVALID_SOCKET; + } + return 0; +} + +/* Duktape debug transport callback: (possibly partial) write. */ +duk_size_t duk_trans_socket_write_cb(void *udata, const char *buffer, duk_size_t length) { + int ret; + + (void) udata; /* not needed by the example */ + +#if defined(DEBUG_PRINTS) + fprintf(stderr, "%s: udata=%p, buffer=%p, length=%ld\n", + __FUNCTION__, (void *) udata, (const void *) buffer, (long) length); + fflush(stderr); +#endif + + if (client_sock == INVALID_SOCKET) { + return 0; + } + + if (length == 0) { + /* This shouldn't happen. */ + fprintf(stderr, "%s: write request length == 0, closing connection\n", + __FILE__); + fflush(stderr); + goto fail; + } + + if (buffer == NULL) { + /* This shouldn't happen. */ + fprintf(stderr, "%s: write request buffer == NULL, closing connection\n", + __FILE__); + fflush(stderr); + goto fail; + } + + /* In a production quality implementation there would be a sanity + * timeout here to recover from "black hole" disconnects. + */ + + ret = send(client_sock, (const void *) buffer, (int) length, 0); + if (ret <= 0 || ret > (int) length) { + fprintf(stderr, "%s: debug write failed, ret %d, closing connection\n", + __FILE__, ret); + fflush(stderr); + goto fail; + } + + return (duk_size_t) ret; + + fail: + if (client_sock != INVALID_SOCKET) { + (void) closesocket(INVALID_SOCKET); + client_sock = INVALID_SOCKET; + } + return 0; +} + +duk_size_t duk_trans_socket_peek_cb(void *udata) { + u_long avail; + int rc; + + (void) udata; /* not needed by the example */ + +#if defined(DEBUG_PRINTS) + fprintf(stderr, "%s: udata=%p\n", __FUNCTION__, (void *) udata); + fflush(stderr); +#endif + + if (client_sock == INVALID_SOCKET) { + return 0; + } + + avail = 0; + rc = ioctlsocket(client_sock, FIONREAD, &avail); + if (rc != 0) { + fprintf(stderr, "%s: ioctlsocket() returned %d, closing connection\n", + __FILE__, rc); + fflush(stderr); + goto fail; /* also returns 0, which is correct */ + } else { + if (avail == 0) { + return 0; /* nothing to read */ + } else { + return 1; /* something to read */ + } + } + /* never here */ + + fail: + if (client_sock != INVALID_SOCKET) { + (void) closesocket(client_sock); + client_sock = INVALID_SOCKET; + } + return 0; +} + +void duk_trans_socket_read_flush_cb(void *udata) { + (void) udata; /* not needed by the example */ + +#if defined(DEBUG_PRINTS) + fprintf(stderr, "%s: udata=%p\n", __FUNCTION__, (void *) udata); + fflush(stderr); +#endif + + /* Read flush: Duktape may not be making any more read calls at this + * time. If the transport maintains a receive window, it can use a + * read flush as a signal to update the window status to the remote + * peer. A read flush is guaranteed to occur before Duktape stops + * reading for a while; it may occur in other situations as well so + * it's not a 100% reliable indication. + */ + + /* This TCP transport requires no read flush handling so ignore. + * You can also pass a NULL to duk_debugger_attach() and not + * implement this callback at all. + */ +} + +void duk_trans_socket_write_flush_cb(void *udata) { + (void) udata; /* not needed by the example */ + +#if defined(DEBUG_PRINTS) + fprintf(stderr, "%s: udata=%p\n", __FUNCTION__, (void *) udata); + fflush(stderr); +#endif + + /* Write flush. If the transport combines multiple writes + * before actually sending, a write flush is an indication + * to write out any pending bytes: Duktape may not be doing + * any more writes on this occasion. + */ + + /* This TCP transport requires no write flush handling so ignore. + * You can also pass a NULL to duk_debugger_attach() and not + * implement this callback at all. + */ + return; +} + +#undef DUK__STRINGIFY_HELPER +#undef DUK__STRINGIFY |