]> git.proxmox.com Git - ceph.git/blame - ceph/src/civetweb/src/third_party/duktape-1.5.2/examples/debug-trans-socket/duk_trans_socket_unix.c
buildsys: switch source download to quincy
[ceph.git] / ceph / src / civetweb / src / third_party / duktape-1.5.2 / examples / debug-trans-socket / duk_trans_socket_unix.c
CommitLineData
7c673cae 1/*
11fdf7f2 2 * Example debug transport using a Linux/Unix TCP socket
7c673cae 3 *
11fdf7f2 4 * Provides a TCP server socket which a debug client can connect to.
7c673cae 5 * After that data is just passed through.
7c673cae
FG
6 */
7
8#include <stdio.h>
9#include <string.h>
10#include <sys/socket.h>
11fdf7f2 11#include <netinet/in.h>
7c673cae
FG
12#include <unistd.h>
13#include <poll.h>
14#include <errno.h>
15#include "duktape.h"
16
11fdf7f2 17#if !defined(DUK_DEBUG_PORT)
7c673cae
FG
18#define DUK_DEBUG_PORT 9091
19#endif
20
21#if 0
22#define DEBUG_PRINTS
23#endif
24
25static int server_sock = -1;
26static int client_sock = -1;
27
28/*
11fdf7f2 29 * Transport init and finish
7c673cae
FG
30 */
31
32void duk_trans_socket_init(void) {
33 struct sockaddr_in addr;
34 int on;
35
36 server_sock = socket(AF_INET, SOCK_STREAM, 0);
37 if (server_sock < 0) {
11fdf7f2
TL
38 fprintf(stderr, "%s: failed to create server socket: %s\n",
39 __FILE__, strerror(errno));
7c673cae
FG
40 fflush(stderr);
41 goto fail;
42 }
43
44 on = 1;
45 if (setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, (const char *) &on, sizeof(on)) < 0) {
11fdf7f2
TL
46 fprintf(stderr, "%s: failed to set SO_REUSEADDR for server socket: %s\n",
47 __FILE__, strerror(errno));
7c673cae
FG
48 fflush(stderr);
49 goto fail;
50 }
51
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);
56
57 if (bind(server_sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
11fdf7f2
TL
58 fprintf(stderr, "%s: failed to bind server socket: %s\n",
59 __FILE__, strerror(errno));
7c673cae
FG
60 fflush(stderr);
61 goto fail;
62 }
63
64 listen(server_sock, 1 /*backlog*/);
65 return;
66
67 fail:
68 if (server_sock >= 0) {
69 (void) close(server_sock);
70 server_sock = -1;
71 }
72}
73
11fdf7f2
TL
74void duk_trans_socket_finish(void) {
75 if (client_sock >= 0) {
76 (void) close(client_sock);
77 client_sock = -1;
78 }
79 if (server_sock >= 0) {
80 (void) close(server_sock);
81 server_sock = -1;
82 }
83}
84
7c673cae
FG
85void duk_trans_socket_waitconn(void) {
86 struct sockaddr_in addr;
87 socklen_t sz;
88
89 if (server_sock < 0) {
11fdf7f2
TL
90 fprintf(stderr, "%s: no server socket, skip waiting for connection\n",
91 __FILE__);
7c673cae
FG
92 fflush(stderr);
93 return;
94 }
95 if (client_sock >= 0) {
96 (void) close(client_sock);
97 client_sock = -1;
98 }
99
100 fprintf(stderr, "Waiting for debug connection on port %d\n", (int) DUK_DEBUG_PORT);
101 fflush(stderr);
102
103 sz = (socklen_t) sizeof(addr);
104 client_sock = accept(server_sock, (struct sockaddr *) &addr, &sz);
105 if (client_sock < 0) {
11fdf7f2
TL
106 fprintf(stderr, "%s: accept() failed, skip waiting for connection: %s\n",
107 __FILE__, strerror(errno));
7c673cae
FG
108 fflush(stderr);
109 goto fail;
110 }
111
112 fprintf(stderr, "Debug connection established\n");
113 fflush(stderr);
114
115 /* XXX: For now, close the listen socket because we won't accept new
116 * connections anyway. A better implementation would allow multiple
117 * debug attaches.
118 */
119
120 if (server_sock >= 0) {
121 (void) close(server_sock);
122 server_sock = -1;
123 }
124 return;
125
126 fail:
127 if (client_sock >= 0) {
128 (void) close(client_sock);
129 client_sock = -1;
130 }
131}
132
133/*
134 * Duktape callbacks
135 */
136
11fdf7f2 137/* Duktape debug transport callback: (possibly partial) read. */
7c673cae
FG
138duk_size_t duk_trans_socket_read_cb(void *udata, char *buffer, duk_size_t length) {
139 ssize_t ret;
140
141 (void) udata; /* not needed by the example */
142
143#if defined(DEBUG_PRINTS)
144 fprintf(stderr, "%s: udata=%p, buffer=%p, length=%ld\n",
145 __func__, (void *) udata, (void *) buffer, (long) length);
146 fflush(stderr);
147#endif
148
149 if (client_sock < 0) {
150 return 0;
151 }
152
153 if (length == 0) {
154 /* This shouldn't happen. */
11fdf7f2
TL
155 fprintf(stderr, "%s: read request length == 0, closing connection\n",
156 __FILE__);
7c673cae
FG
157 fflush(stderr);
158 goto fail;
159 }
160
161 if (buffer == NULL) {
162 /* This shouldn't happen. */
11fdf7f2
TL
163 fprintf(stderr, "%s: read request buffer == NULL, closing connection\n",
164 __FILE__);
7c673cae
FG
165 fflush(stderr);
166 goto fail;
167 }
168
169 /* In a production quality implementation there would be a sanity
170 * timeout here to recover from "black hole" disconnects.
171 */
172
173 ret = read(client_sock, (void *) buffer, (size_t) length);
174 if (ret < 0) {
11fdf7f2
TL
175 fprintf(stderr, "%s: debug read failed, closing connection: %s\n",
176 __FILE__, strerror(errno));
7c673cae
FG
177 fflush(stderr);
178 goto fail;
179 } else if (ret == 0) {
11fdf7f2
TL
180 fprintf(stderr, "%s: debug read failed, ret == 0 (EOF), closing connection\n",
181 __FILE__);
7c673cae
FG
182 fflush(stderr);
183 goto fail;
184 } else if (ret > (ssize_t) length) {
11fdf7f2
TL
185 fprintf(stderr, "%s: debug read failed, ret too large (%ld > %ld), closing connection\n",
186 __FILE__, (long) ret, (long) length);
7c673cae
FG
187 fflush(stderr);
188 goto fail;
189 }
190
191 return (duk_size_t) ret;
192
193 fail:
194 if (client_sock >= 0) {
195 (void) close(client_sock);
196 client_sock = -1;
197 }
198 return 0;
199}
200
11fdf7f2 201/* Duktape debug transport callback: (possibly partial) write. */
7c673cae
FG
202duk_size_t duk_trans_socket_write_cb(void *udata, const char *buffer, duk_size_t length) {
203 ssize_t ret;
204
205 (void) udata; /* not needed by the example */
206
207#if defined(DEBUG_PRINTS)
208 fprintf(stderr, "%s: udata=%p, buffer=%p, length=%ld\n",
11fdf7f2 209 __func__, (void *) udata, (const void *) buffer, (long) length);
7c673cae
FG
210 fflush(stderr);
211#endif
212
213 if (client_sock < 0) {
214 return 0;
215 }
216
217 if (length == 0) {
218 /* This shouldn't happen. */
11fdf7f2
TL
219 fprintf(stderr, "%s: write request length == 0, closing connection\n",
220 __FILE__);
7c673cae
FG
221 fflush(stderr);
222 goto fail;
223 }
224
225 if (buffer == NULL) {
226 /* This shouldn't happen. */
11fdf7f2
TL
227 fprintf(stderr, "%s: write request buffer == NULL, closing connection\n",
228 __FILE__);
7c673cae
FG
229 fflush(stderr);
230 goto fail;
231 }
232
233 /* In a production quality implementation there would be a sanity
234 * timeout here to recover from "black hole" disconnects.
235 */
236
237 ret = write(client_sock, (const void *) buffer, (size_t) length);
238 if (ret <= 0 || ret > (ssize_t) length) {
11fdf7f2
TL
239 fprintf(stderr, "%s: debug write failed, closing connection: %s\n",
240 __FILE__, strerror(errno));
7c673cae
FG
241 fflush(stderr);
242 goto fail;
243 }
244
245 return (duk_size_t) ret;
246
247 fail:
248 if (client_sock >= 0) {
249 (void) close(client_sock);
250 client_sock = -1;
251 }
252 return 0;
253}
254
255duk_size_t duk_trans_socket_peek_cb(void *udata) {
256 struct pollfd fds[1];
257 int poll_rc;
258
259 (void) udata; /* not needed by the example */
260
261#if defined(DEBUG_PRINTS)
262 fprintf(stderr, "%s: udata=%p\n", __func__, (void *) udata);
263 fflush(stderr);
264#endif
265
11fdf7f2
TL
266 if (client_sock < 0) {
267 return 0;
268 }
269
7c673cae
FG
270 fds[0].fd = client_sock;
271 fds[0].events = POLLIN;
272 fds[0].revents = 0;
273
274 poll_rc = poll(fds, 1, 0);
275 if (poll_rc < 0) {
11fdf7f2
TL
276 fprintf(stderr, "%s: poll returned < 0, closing connection: %s\n",
277 __FILE__, strerror(errno));
7c673cae
FG
278 fflush(stderr);
279 goto fail; /* also returns 0, which is correct */
280 } else if (poll_rc > 1) {
11fdf7f2
TL
281 fprintf(stderr, "%s: poll returned > 1, treating like 1\n",
282 __FILE__);
7c673cae
FG
283 fflush(stderr);
284 return 1; /* should never happen */
285 } else if (poll_rc == 0) {
286 return 0; /* nothing to read */
287 } else {
288 return 1; /* something to read */
289 }
290
291 fail:
292 if (client_sock >= 0) {
293 (void) close(client_sock);
294 client_sock = -1;
295 }
296 return 0;
297}
298
299void duk_trans_socket_read_flush_cb(void *udata) {
11fdf7f2
TL
300 (void) udata; /* not needed by the example */
301
7c673cae
FG
302#if defined(DEBUG_PRINTS)
303 fprintf(stderr, "%s: udata=%p\n", __func__, (void *) udata);
304 fflush(stderr);
305#endif
306
7c673cae
FG
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.
313 */
314
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.
318 */
319}
320
321void duk_trans_socket_write_flush_cb(void *udata) {
11fdf7f2
TL
322 (void) udata; /* not needed by the example */
323
7c673cae
FG
324#if defined(DEBUG_PRINTS)
325 fprintf(stderr, "%s: udata=%p\n", __func__, (void *) udata);
326 fflush(stderr);
327#endif
328
7c673cae
FG
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.
333 */
334
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.
338 */
339 return;
340}