]>
git.proxmox.com Git - ceph.git/blob - ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/debug-trans-socket/duk_trans_socket.c
2 * Example debug transport using a TCP socket
4 * The application has a server socket which can be connected to.
5 * After that data is just passed through.
7 * NOTE: This is Linux specific on purpose, as it's just an example how
8 * a debug transport can be concretely implemented.
13 #include <sys/socket.h>
14 #include <arpa/inet.h>
20 #ifndef DUK_DEBUG_PORT
21 #define DUK_DEBUG_PORT 9091
28 static int server_sock
= -1;
29 static int client_sock
= -1;
35 void duk_trans_socket_init(void) {
36 struct sockaddr_in addr
;
39 server_sock
= socket(AF_INET
, SOCK_STREAM
, 0);
40 if (server_sock
< 0) {
41 fprintf(stderr
, "%s: failed to create server socket: %s\n", __FILE__
, strerror(errno
));
47 if (setsockopt(server_sock
, SOL_SOCKET
, SO_REUSEADDR
, (const char *) &on
, sizeof(on
)) < 0) {
48 fprintf(stderr
, "%s: failed to set SO_REUSEADDR for server socket: %s\n", __FILE__
, strerror(errno
));
53 memset((void *) &addr
, 0, sizeof(addr
));
54 addr
.sin_family
= AF_INET
;
55 addr
.sin_addr
.s_addr
= INADDR_ANY
;
56 addr
.sin_port
= htons(DUK_DEBUG_PORT
);
58 if (bind(server_sock
, (struct sockaddr
*) &addr
, sizeof(addr
)) < 0) {
59 fprintf(stderr
, "%s: failed to bind server socket: %s\n", __FILE__
, strerror(errno
));
64 listen(server_sock
, 1 /*backlog*/);
68 if (server_sock
>= 0) {
69 (void) close(server_sock
);
74 void duk_trans_socket_waitconn(void) {
75 struct sockaddr_in addr
;
78 if (server_sock
< 0) {
79 fprintf(stderr
, "%s: no server socket, skip waiting for connection\n", __FILE__
);
83 if (client_sock
>= 0) {
84 (void) close(client_sock
);
88 fprintf(stderr
, "Waiting for debug connection on port %d\n", (int) DUK_DEBUG_PORT
);
91 sz
= (socklen_t
) sizeof(addr
);
92 client_sock
= accept(server_sock
, (struct sockaddr
*) &addr
, &sz
);
93 if (client_sock
< 0) {
94 fprintf(stderr
, "%s: accept() failed, skip waiting for connection: %s\n", __FILE__
, strerror(errno
));
99 fprintf(stderr
, "Debug connection established\n");
102 /* XXX: For now, close the listen socket because we won't accept new
103 * connections anyway. A better implementation would allow multiple
107 if (server_sock
>= 0) {
108 (void) close(server_sock
);
114 if (client_sock
>= 0) {
115 (void) close(client_sock
);
124 /* Duktape debug transport callback: partial read */
125 duk_size_t
duk_trans_socket_read_cb(void *udata
, char *buffer
, duk_size_t length
) {
128 (void) udata
; /* not needed by the example */
130 #if defined(DEBUG_PRINTS)
131 fprintf(stderr
, "%s: udata=%p, buffer=%p, length=%ld\n",
132 __func__
, (void *) udata
, (void *) buffer
, (long) length
);
136 if (client_sock
< 0) {
141 /* This shouldn't happen. */
142 fprintf(stderr
, "%s: read request length == 0, closing connection\n", __FILE__
);
147 if (buffer
== NULL
) {
148 /* This shouldn't happen. */
149 fprintf(stderr
, "%s: read request buffer == NULL, closing connection\n", __FILE__
);
154 /* In a production quality implementation there would be a sanity
155 * timeout here to recover from "black hole" disconnects.
158 ret
= read(client_sock
, (void *) buffer
, (size_t) length
);
160 fprintf(stderr
, "%s: debug read failed, errno %d, closing connection: %s\n", __FILE__
, errno
, strerror(errno
));
163 } else if (ret
== 0) {
164 fprintf(stderr
, "%s: debug read failed, ret == 0 (EOF), closing connection\n", __FILE__
);
167 } else if (ret
> (ssize_t
) length
) {
168 fprintf(stderr
, "%s: debug read failed, ret too large (%ld > %ld), closing connection\n", __FILE__
, (long) ret
, (long) length
);
173 return (duk_size_t
) ret
;
176 if (client_sock
>= 0) {
177 (void) close(client_sock
);
183 /* Duktape debug transport callback: partial write */
184 duk_size_t
duk_trans_socket_write_cb(void *udata
, const char *buffer
, duk_size_t length
) {
187 (void) udata
; /* not needed by the example */
189 #if defined(DEBUG_PRINTS)
190 fprintf(stderr
, "%s: udata=%p, buffer=%p, length=%ld\n",
191 __func__
, (void *) udata
, (void *) buffer
, (long) length
);
195 if (client_sock
< 0) {
200 /* This shouldn't happen. */
201 fprintf(stderr
, "%s: write request length == 0, closing connection\n", __FILE__
);
206 if (buffer
== NULL
) {
207 /* This shouldn't happen. */
208 fprintf(stderr
, "%s: write request buffer == NULL, closing connection\n", __FILE__
);
213 /* In a production quality implementation there would be a sanity
214 * timeout here to recover from "black hole" disconnects.
217 ret
= write(client_sock
, (const void *) buffer
, (size_t) length
);
218 if (ret
<= 0 || ret
> (ssize_t
) length
) {
219 fprintf(stderr
, "%s: debug write failed, closing connection: %s\n", __FILE__
, strerror(errno
));
224 return (duk_size_t
) ret
;
227 if (client_sock
>= 0) {
228 (void) close(client_sock
);
234 duk_size_t
duk_trans_socket_peek_cb(void *udata
) {
235 struct pollfd fds
[1];
238 (void) udata
; /* not needed by the example */
240 #if defined(DEBUG_PRINTS)
241 fprintf(stderr
, "%s: udata=%p\n", __func__
, (void *) udata
);
245 fds
[0].fd
= client_sock
;
246 fds
[0].events
= POLLIN
;
249 poll_rc
= poll(fds
, 1, 0);
251 fprintf(stderr
, "%s: poll returned < 0, closing connection: %s\n", __FILE__
, strerror(errno
));
253 goto fail
; /* also returns 0, which is correct */
254 } else if (poll_rc
> 1) {
255 fprintf(stderr
, "%s: poll returned > 1, treating like 1\n", __FILE__
);
257 return 1; /* should never happen */
258 } else if (poll_rc
== 0) {
259 return 0; /* nothing to read */
261 return 1; /* something to read */
265 if (client_sock
>= 0) {
266 (void) close(client_sock
);
272 void duk_trans_socket_read_flush_cb(void *udata
) {
273 #if defined(DEBUG_PRINTS)
274 fprintf(stderr
, "%s: udata=%p\n", __func__
, (void *) udata
);
278 (void) udata
; /* not needed by the example */
280 /* Read flush: Duktape may not be making any more read calls at this
281 * time. If the transport maintains a receive window, it can use a
282 * read flush as a signal to update the window status to the remote
283 * peer. A read flush is guaranteed to occur before Duktape stops
284 * reading for a while; it may occur in other situations as well so
285 * it's not a 100% reliable indication.
288 /* This TCP transport requires no read flush handling so ignore.
289 * You can also pass a NULL to duk_debugger_attach() and not
290 * implement this callback at all.
294 void duk_trans_socket_write_flush_cb(void *udata
) {
295 #if defined(DEBUG_PRINTS)
296 fprintf(stderr
, "%s: udata=%p\n", __func__
, (void *) udata
);
300 (void) udata
; /* not needed by the example */
302 /* Write flush. If the transport combines multiple writes
303 * before actually sending, a write flush is an indication
304 * to write out any pending bytes: Duktape may not be doing
305 * any more writes on this occasion.
308 /* This TCP transport requires no write flush handling so ignore.
309 * You can also pass a NULL to duk_debugger_attach() and not
310 * implement this callback at all.