]>
git.proxmox.com Git - ceph.git/blob - ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/debug-trans-socket/duk_trans_socket_windows.c
e92ac2660943939544604a6ae61a3c3fabe1176c
2 * Example debug transport using a Windows TCP socket
4 * Provides a TCP server socket which a debug client can connect to.
5 * After that data is just passed through.
7 * https://msdn.microsoft.com/en-us/library/windows/desktop/ms737593(v=vs.85).aspx
9 * Compiling 'duk' with debugger support using MSVC (Visual Studio):
11 * > cl /W3 /O2 /Feduk.exe
12 * /DDUK_OPT_DEBUGGER_SUPPORT /DDUK_OPT_INTERRUPT_COUNTER
13 * /DDUK_CMDLINE_DEBUGGER_SUPPORT
14 * /Iexamples\debug-trans-socket /Isrc
15 * examples\cmdline\duk_cmdline.c
16 * examples\debug-trans-socket\duk_trans_socket_windows.c
21 * $ gcc -oduk.exe -Wall -O2 \
22 * -DDUK_OPT_DEBUGGER_SUPPORT -DDUK_OPT_INTERRUPT_COUNTER \
23 * -DDUK_CMDLINE_DEBUGGER_SUPPORT \
24 * -Iexamples/debug-trans-socket -Isrc \
25 * examples/cmdline/duk_cmdline.c \
26 * examples/debug-trans-socket/duk_trans_socket_windows.c \
27 * src/duktape.c -lm -lws2_32
31 #if !defined(WIN32_LEAN_AND_MEAN)
32 #define WIN32_LEAN_AND_MEAN
35 /* MinGW workaround for missing getaddrinfo() etc:
36 * http://programmingrants.blogspot.fi/2009/09/tips-on-undefined-reference-to.html
38 #if defined(__MINGW32__) || defined(__MINGW64__)
39 #if !defined(_WIN32_WINNT)
40 #define _WIN32_WINNT 0x0501
52 #pragma comment (lib, "Ws2_32.lib")
55 #if !defined(DUK_DEBUG_PORT)
56 #define DUK_DEBUG_PORT 9091
58 #if !defined(DUK_DEBUG_ADDRESS)
59 #define DUK_DEBUG_ADDRESS "0.0.0.0"
61 #define DUK__STRINGIFY_HELPER(x) #x
62 #define DUK__STRINGIFY(x) DUK__STRINGIFY_HELPER(x)
68 static SOCKET server_sock
= INVALID_SOCKET
;
69 static SOCKET client_sock
= INVALID_SOCKET
;
70 static int wsa_inited
= 0;
73 * Transport init and finish
76 void duk_trans_socket_init(void) {
78 struct addrinfo hints
;
79 struct addrinfo
*result
= NULL
;
82 memset((void *) &wsa_data
, 0, sizeof(wsa_data
));
83 memset((void *) &hints
, 0, sizeof(hints
));
85 rc
= WSAStartup(MAKEWORD(2, 2), &wsa_data
);
87 fprintf(stderr
, "%s: WSAStartup() failed: %d\n", __FILE__
, rc
);
93 hints
.ai_family
= AF_UNSPEC
;
94 hints
.ai_socktype
= SOCK_STREAM
;
95 hints
.ai_protocol
= IPPROTO_TCP
;
96 hints
.ai_flags
= AI_PASSIVE
;
98 rc
= getaddrinfo(DUK_DEBUG_ADDRESS
, DUK__STRINGIFY(DUK_DEBUG_PORT
), &hints
, &result
);
100 fprintf(stderr
, "%s: getaddrinfo() failed: %d\n", __FILE__
, rc
);
105 server_sock
= socket(result
->ai_family
, result
->ai_socktype
, result
->ai_protocol
);
106 if (server_sock
== INVALID_SOCKET
) {
107 fprintf(stderr
, "%s: socket() failed with error: %ld\n",
108 __FILE__
, (long) WSAGetLastError());
113 rc
= bind(server_sock
, result
->ai_addr
, (int) result
->ai_addrlen
);
114 if (rc
== SOCKET_ERROR
) {
115 fprintf(stderr
, "%s: bind() failed with error: %ld\n",
116 __FILE__
, (long) WSAGetLastError());
121 rc
= listen(server_sock
, SOMAXCONN
);
122 if (rc
== SOCKET_ERROR
) {
123 fprintf(stderr
, "%s: listen() failed with error: %ld\n",
124 __FILE__
, (long) WSAGetLastError());
129 if (result
!= NULL
) {
130 freeaddrinfo(result
);
136 if (result
!= NULL
) {
137 freeaddrinfo(result
);
140 if (server_sock
!= INVALID_SOCKET
) {
141 (void) closesocket(server_sock
);
142 server_sock
= INVALID_SOCKET
;
150 void duk_trans_socket_finish(void) {
151 if (client_sock
!= INVALID_SOCKET
) {
152 (void) closesocket(client_sock
);
153 client_sock
= INVALID_SOCKET
;
155 if (server_sock
!= INVALID_SOCKET
) {
156 (void) closesocket(server_sock
);
157 server_sock
= INVALID_SOCKET
;
165 void duk_trans_socket_waitconn(void) {
166 if (server_sock
== INVALID_SOCKET
) {
167 fprintf(stderr
, "%s: no server socket, skip waiting for connection\n",
172 if (client_sock
!= INVALID_SOCKET
) {
173 (void) closesocket(client_sock
);
174 client_sock
= INVALID_SOCKET
;
177 fprintf(stderr
, "Waiting for debug connection on port %d\n", (int) DUK_DEBUG_PORT
);
180 client_sock
= accept(server_sock
, NULL
, NULL
);
181 if (client_sock
== INVALID_SOCKET
) {
182 fprintf(stderr
, "%s: accept() failed with error %ld, skip waiting for connection\n",
183 __FILE__
, (long) WSAGetLastError());
188 fprintf(stderr
, "Debug connection established\n");
191 /* XXX: For now, close the listen socket because we won't accept new
192 * connections anyway. A better implementation would allow multiple
196 if (server_sock
!= INVALID_SOCKET
) {
197 (void) closesocket(server_sock
);
198 server_sock
= INVALID_SOCKET
;
203 if (client_sock
!= INVALID_SOCKET
) {
204 (void) closesocket(client_sock
);
205 client_sock
= INVALID_SOCKET
;
213 /* Duktape debug transport callback: (possibly partial) read. */
214 duk_size_t
duk_trans_socket_read_cb(void *udata
, char *buffer
, duk_size_t length
) {
217 (void) udata
; /* not needed by the example */
219 #if defined(DEBUG_PRINTS)
220 fprintf(stderr
, "%s: udata=%p, buffer=%p, length=%ld\n",
221 __FUNCTION__
, (void *) udata
, (void *) buffer
, (long) length
);
225 if (client_sock
== INVALID_SOCKET
) {
230 /* This shouldn't happen. */
231 fprintf(stderr
, "%s: read request length == 0, closing connection\n",
237 if (buffer
== NULL
) {
238 /* This shouldn't happen. */
239 fprintf(stderr
, "%s: read request buffer == NULL, closing connection\n",
245 /* In a production quality implementation there would be a sanity
246 * timeout here to recover from "black hole" disconnects.
249 ret
= recv(client_sock
, (void *) buffer
, (int) length
, 0);
251 fprintf(stderr
, "%s: debug read failed, error %d, closing connection\n",
255 } else if (ret
== 0) {
256 fprintf(stderr
, "%s: debug read failed, ret == 0 (EOF), closing connection\n",
260 } else if (ret
> (int) length
) {
261 fprintf(stderr
, "%s: debug read failed, ret too large (%ld > %ld), closing connection\n",
262 __FILE__
, (long) ret
, (long) length
);
267 return (duk_size_t
) ret
;
270 if (client_sock
!= INVALID_SOCKET
) {
271 (void) closesocket(client_sock
);
272 client_sock
= INVALID_SOCKET
;
277 /* Duktape debug transport callback: (possibly partial) write. */
278 duk_size_t
duk_trans_socket_write_cb(void *udata
, const char *buffer
, duk_size_t length
) {
281 (void) udata
; /* not needed by the example */
283 #if defined(DEBUG_PRINTS)
284 fprintf(stderr
, "%s: udata=%p, buffer=%p, length=%ld\n",
285 __FUNCTION__
, (void *) udata
, (const void *) buffer
, (long) length
);
289 if (client_sock
== INVALID_SOCKET
) {
294 /* This shouldn't happen. */
295 fprintf(stderr
, "%s: write request length == 0, closing connection\n",
301 if (buffer
== NULL
) {
302 /* This shouldn't happen. */
303 fprintf(stderr
, "%s: write request buffer == NULL, closing connection\n",
309 /* In a production quality implementation there would be a sanity
310 * timeout here to recover from "black hole" disconnects.
313 ret
= send(client_sock
, (const void *) buffer
, (int) length
, 0);
314 if (ret
<= 0 || ret
> (int) length
) {
315 fprintf(stderr
, "%s: debug write failed, ret %d, closing connection\n",
321 return (duk_size_t
) ret
;
324 if (client_sock
!= INVALID_SOCKET
) {
325 (void) closesocket(INVALID_SOCKET
);
326 client_sock
= INVALID_SOCKET
;
331 duk_size_t
duk_trans_socket_peek_cb(void *udata
) {
335 (void) udata
; /* not needed by the example */
337 #if defined(DEBUG_PRINTS)
338 fprintf(stderr
, "%s: udata=%p\n", __FUNCTION__
, (void *) udata
);
342 if (client_sock
== INVALID_SOCKET
) {
347 rc
= ioctlsocket(client_sock
, FIONREAD
, &avail
);
349 fprintf(stderr
, "%s: ioctlsocket() returned %d, closing connection\n",
352 goto fail
; /* also returns 0, which is correct */
355 return 0; /* nothing to read */
357 return 1; /* something to read */
363 if (client_sock
!= INVALID_SOCKET
) {
364 (void) closesocket(client_sock
);
365 client_sock
= INVALID_SOCKET
;
370 void duk_trans_socket_read_flush_cb(void *udata
) {
371 (void) udata
; /* not needed by the example */
373 #if defined(DEBUG_PRINTS)
374 fprintf(stderr
, "%s: udata=%p\n", __FUNCTION__
, (void *) udata
);
378 /* Read flush: Duktape may not be making any more read calls at this
379 * time. If the transport maintains a receive window, it can use a
380 * read flush as a signal to update the window status to the remote
381 * peer. A read flush is guaranteed to occur before Duktape stops
382 * reading for a while; it may occur in other situations as well so
383 * it's not a 100% reliable indication.
386 /* This TCP transport requires no read flush handling so ignore.
387 * You can also pass a NULL to duk_debugger_attach() and not
388 * implement this callback at all.
392 void duk_trans_socket_write_flush_cb(void *udata
) {
393 (void) udata
; /* not needed by the example */
395 #if defined(DEBUG_PRINTS)
396 fprintf(stderr
, "%s: udata=%p\n", __FUNCTION__
, (void *) udata
);
400 /* Write flush. If the transport combines multiple writes
401 * before actually sending, a write flush is an indication
402 * to write out any pending bytes: Duktape may not be doing
403 * any more writes on this occasion.
406 /* This TCP transport requires no write flush handling so ignore.
407 * You can also pass a NULL to duk_debugger_attach() and not
408 * implement this callback at all.
413 #undef DUK__STRINGIFY_HELPER
414 #undef DUK__STRINGIFY