Github User Fetcher 1.0.0
C Application with Server and GUI
Loading...
Searching...
No Matches
duktape-1.5.2/examples/debug-trans-socket/duk_trans_socket_unix.c
Go to the documentation of this file.
1/*
2 * Example debug transport using a Linux/Unix TCP socket
3 *
4 * Provides a TCP server socket which a debug client can connect to.
5 * After that data is just passed through.
6 */
7
8#include <stdio.h>
9#include <string.h>
10#include <sys/socket.h>
11#include <netinet/in.h>
12#include <unistd.h>
13#include <poll.h>
14#include <errno.h>
15#include "duktape.h"
16
17#if !defined(DUK_DEBUG_PORT)
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/*
29 * Transport init and finish
30 */
31
33 struct sockaddr_in addr;
34 int on;
35
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));
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) {
46 fprintf(stderr, "%s: failed to set SO_REUSEADDR for server socket: %s\n",
47 __FILE__, strerror(errno));
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) {
58 fprintf(stderr, "%s: failed to bind server socket: %s\n",
59 __FILE__, strerror(errno));
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
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
86 struct sockaddr_in addr;
87 socklen_t sz;
88
89 if (server_sock < 0) {
90 fprintf(stderr, "%s: no server socket, skip waiting for connection\n",
91 __FILE__);
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) {
106 fprintf(stderr, "%s: accept() failed, skip waiting for connection: %s\n",
107 __FILE__, strerror(errno));
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
137/* Duktape debug transport callback: (possibly partial) read. */
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. */
155 fprintf(stderr, "%s: read request length == 0, closing connection\n",
156 __FILE__);
157 fflush(stderr);
158 goto fail;
159 }
160
161 if (buffer == NULL) {
162 /* This shouldn't happen. */
163 fprintf(stderr, "%s: read request buffer == NULL, closing connection\n",
164 __FILE__);
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) {
175 fprintf(stderr, "%s: debug read failed, closing connection: %s\n",
176 __FILE__, strerror(errno));
177 fflush(stderr);
178 goto fail;
179 } else if (ret == 0) {
180 fprintf(stderr, "%s: debug read failed, ret == 0 (EOF), closing connection\n",
181 __FILE__);
182 fflush(stderr);
183 goto fail;
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);
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
201/* Duktape debug transport callback: (possibly partial) write. */
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",
209 __func__, (void *) udata, (const void *) buffer, (long) length);
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. */
219 fprintf(stderr, "%s: write request length == 0, closing connection\n",
220 __FILE__);
221 fflush(stderr);
222 goto fail;
223 }
224
225 if (buffer == NULL) {
226 /* This shouldn't happen. */
227 fprintf(stderr, "%s: write request buffer == NULL, closing connection\n",
228 __FILE__);
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) {
239 fprintf(stderr, "%s: debug write failed, closing connection: %s\n",
240 __FILE__, strerror(errno));
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
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
266 if (client_sock < 0) {
267 return 0;
268 }
269
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) {
276 fprintf(stderr, "%s: poll returned < 0, closing connection: %s\n",
277 __FILE__, strerror(errno));
278 fflush(stderr);
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",
282 __FILE__);
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
300 (void) udata; /* not needed by the example */
301
302#if defined(DEBUG_PRINTS)
303 fprintf(stderr, "%s: udata=%p\n", __func__, (void *) udata);
304 fflush(stderr);
305#endif
306
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
322 (void) udata; /* not needed by the example */
323
324#if defined(DEBUG_PRINTS)
325 fprintf(stderr, "%s: udata=%p\n", __func__, (void *) udata);
326 fflush(stderr);
327#endif
328
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}
duk_size_t duk_trans_socket_read_cb(void *udata, char *buffer, duk_size_t length)
duk_size_t duk_trans_socket_write_cb(void *udata, const char *buffer, duk_size_t length)
#define NULL
Definition gmacros.h:924