summaryrefslogtreecommitdiffstats
path: root/src/civetweb/src/third_party/duktape-1.8.0/examples/debug-trans-socket/duk_trans_socket_windows.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/civetweb/src/third_party/duktape-1.8.0/examples/debug-trans-socket/duk_trans_socket_windows.c414
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