]>
git.proxmox.com Git - ceph.git/blob - ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/debug-trans-socket/duk_trans_socket_unix.c
2 * Example debug transport using a Linux/Unix TCP socket
4 * Provides a TCP server socket which a debug client can connect to.
5 * After that data is just passed through.
10 #include <sys/socket.h>
11 #include <netinet/in.h>
17 #if !defined(DUK_DEBUG_PORT)
18 #define DUK_DEBUG_PORT 9091
25 static int server_sock
= -1;
26 static int client_sock
= -1;
29 * Transport init and finish
32 void duk_trans_socket_init(void) {
33 struct sockaddr_in addr
;
36 server_sock
= socket(AF_INET
, SOCK_STREAM
, 0);
37 if (server_sock
< 0) {
38 fprintf(stderr
, "%s: failed to create server socket: %s\n",
39 __FILE__
, strerror(errno
));
45 if (setsockopt(server_sock
, SOL_SOCKET
, SO_REUSEADDR
, (const char *) &on
, sizeof(on
)) < 0) {
46 fprintf(stderr
, "%s: failed to set SO_REUSEADDR for server socket: %s\n",
47 __FILE__
, strerror(errno
));
52 memset((void *) &addr
, 0, sizeof(addr
));
53 addr
.sin_family
= AF_INET
;
54 addr
.sin_addr
.s_addr
= INADDR_ANY
;
55 addr
.sin_port
= htons(DUK_DEBUG_PORT
);
57 if (bind(server_sock
, (struct sockaddr
*) &addr
, sizeof(addr
)) < 0) {
58 fprintf(stderr
, "%s: failed to bind server socket: %s\n",
59 __FILE__
, strerror(errno
));
64 listen(server_sock
, 1 /*backlog*/);
68 if (server_sock
>= 0) {
69 (void) close(server_sock
);
74 void duk_trans_socket_finish(void) {
75 if (client_sock
>= 0) {
76 (void) close(client_sock
);
79 if (server_sock
>= 0) {
80 (void) close(server_sock
);
85 void duk_trans_socket_waitconn(void) {
86 struct sockaddr_in addr
;
89 if (server_sock
< 0) {
90 fprintf(stderr
, "%s: no server socket, skip waiting for connection\n",
95 if (client_sock
>= 0) {
96 (void) close(client_sock
);
100 fprintf(stderr
, "Waiting for debug connection on port %d\n", (int) DUK_DEBUG_PORT
);
103 sz
= (socklen_t
) sizeof(addr
);
104 client_sock
= accept(server_sock
, (struct sockaddr
*) &addr
, &sz
);
105 if (client_sock
< 0) {
106 fprintf(stderr
, "%s: accept() failed, skip waiting for connection: %s\n",
107 __FILE__
, strerror(errno
));
112 fprintf(stderr
, "Debug connection established\n");
115 /* XXX: For now, close the listen socket because we won't accept new
116 * connections anyway. A better implementation would allow multiple
120 if (server_sock
>= 0) {
121 (void) close(server_sock
);
127 if (client_sock
>= 0) {
128 (void) close(client_sock
);
137 /* Duktape debug transport callback: (possibly partial) read. */
138 duk_size_t
duk_trans_socket_read_cb(void *udata
, char *buffer
, duk_size_t length
) {
141 (void) udata
; /* not needed by the example */
143 #if defined(DEBUG_PRINTS)
144 fprintf(stderr
, "%s: udata=%p, buffer=%p, length=%ld\n",
145 __func__
, (void *) udata
, (void *) buffer
, (long) length
);
149 if (client_sock
< 0) {
154 /* This shouldn't happen. */
155 fprintf(stderr
, "%s: read request length == 0, closing connection\n",
161 if (buffer
== NULL
) {
162 /* This shouldn't happen. */
163 fprintf(stderr
, "%s: read request buffer == NULL, closing connection\n",
169 /* In a production quality implementation there would be a sanity
170 * timeout here to recover from "black hole" disconnects.
173 ret
= read(client_sock
, (void *) buffer
, (size_t) length
);
175 fprintf(stderr
, "%s: debug read failed, closing connection: %s\n",
176 __FILE__
, strerror(errno
));
179 } else if (ret
== 0) {
180 fprintf(stderr
, "%s: debug read failed, ret == 0 (EOF), closing connection\n",
184 } else if (ret
> (ssize_t
) length
) {
185 fprintf(stderr
, "%s: debug read failed, ret too large (%ld > %ld), closing connection\n",
186 __FILE__
, (long) ret
, (long) length
);
191 return (duk_size_t
) ret
;
194 if (client_sock
>= 0) {
195 (void) close(client_sock
);
201 /* Duktape debug transport callback: (possibly partial) write. */
202 duk_size_t
duk_trans_socket_write_cb(void *udata
, const char *buffer
, duk_size_t length
) {
205 (void) udata
; /* not needed by the example */
207 #if defined(DEBUG_PRINTS)
208 fprintf(stderr
, "%s: udata=%p, buffer=%p, length=%ld\n",
209 __func__
, (void *) udata
, (const void *) buffer
, (long) length
);
213 if (client_sock
< 0) {
218 /* This shouldn't happen. */
219 fprintf(stderr
, "%s: write request length == 0, closing connection\n",
225 if (buffer
== NULL
) {
226 /* This shouldn't happen. */
227 fprintf(stderr
, "%s: write request buffer == NULL, closing connection\n",
233 /* In a production quality implementation there would be a sanity
234 * timeout here to recover from "black hole" disconnects.
237 ret
= write(client_sock
, (const void *) buffer
, (size_t) length
);
238 if (ret
<= 0 || ret
> (ssize_t
) length
) {
239 fprintf(stderr
, "%s: debug write failed, closing connection: %s\n",
240 __FILE__
, strerror(errno
));
245 return (duk_size_t
) ret
;
248 if (client_sock
>= 0) {
249 (void) close(client_sock
);
255 duk_size_t
duk_trans_socket_peek_cb(void *udata
) {
256 struct pollfd fds
[1];
259 (void) udata
; /* not needed by the example */
261 #if defined(DEBUG_PRINTS)
262 fprintf(stderr
, "%s: udata=%p\n", __func__
, (void *) udata
);
266 if (client_sock
< 0) {
270 fds
[0].fd
= client_sock
;
271 fds
[0].events
= POLLIN
;
274 poll_rc
= poll(fds
, 1, 0);
276 fprintf(stderr
, "%s: poll returned < 0, closing connection: %s\n",
277 __FILE__
, strerror(errno
));
279 goto fail
; /* also returns 0, which is correct */
280 } else if (poll_rc
> 1) {
281 fprintf(stderr
, "%s: poll returned > 1, treating like 1\n",
284 return 1; /* should never happen */
285 } else if (poll_rc
== 0) {
286 return 0; /* nothing to read */
288 return 1; /* something to read */
292 if (client_sock
>= 0) {
293 (void) close(client_sock
);
299 void duk_trans_socket_read_flush_cb(void *udata
) {
300 (void) udata
; /* not needed by the example */
302 #if defined(DEBUG_PRINTS)
303 fprintf(stderr
, "%s: udata=%p\n", __func__
, (void *) udata
);
307 /* Read flush: Duktape may not be making any more read calls at this
308 * time. If the transport maintains a receive window, it can use a
309 * read flush as a signal to update the window status to the remote
310 * peer. A read flush is guaranteed to occur before Duktape stops
311 * reading for a while; it may occur in other situations as well so
312 * it's not a 100% reliable indication.
315 /* This TCP transport requires no read flush handling so ignore.
316 * You can also pass a NULL to duk_debugger_attach() and not
317 * implement this callback at all.
321 void duk_trans_socket_write_flush_cb(void *udata
) {
322 (void) udata
; /* not needed by the example */
324 #if defined(DEBUG_PRINTS)
325 fprintf(stderr
, "%s: udata=%p\n", __func__
, (void *) udata
);
329 /* Write flush. If the transport combines multiple writes
330 * before actually sending, a write flush is an indication
331 * to write out any pending bytes: Duktape may not be doing
332 * any more writes on this occasion.
335 /* This TCP transport requires no write flush handling so ignore.
336 * You can also pass a NULL to duk_debugger_attach() and not
337 * implement this callback at all.