]> git.proxmox.com Git - ceph.git/blob - ceph/src/civetweb/src/third_party/duktape-1.3.0/examples/eventloop/socket.c
bump version to 12.2.12-pve1
[ceph.git] / ceph / src / civetweb / src / third_party / duktape-1.3.0 / examples / eventloop / socket.c
1 /*
2 * TCP sockets binding example.
3 */
4
5 #define _GNU_SOURCE
6 #include <errno.h>
7 #include <string.h>
8 #include <stdio.h>
9 #include <unistd.h>
10 #include <fcntl.h>
11 #include <netdb.h>
12 #include <sys/types.h>
13 #include <sys/socket.h>
14 #include <netinet/in.h>
15 #include <time.h>
16
17 #include "duktape.h"
18
19 #define ERROR_FROM_ERRNO(ctx) do { \
20 duk_error(ctx, DUK_ERR_ERROR, "%s (errno=%d)", strerror(errno), errno); \
21 } while (0)
22
23 static void set_nonblocking(duk_context *ctx, int fd) {
24 int rc;
25 int flags;
26
27 rc = fcntl(fd, F_GETFL);
28 if (rc < 0) {
29 ERROR_FROM_ERRNO(ctx);
30 }
31 flags = rc;
32
33 flags |= O_NONBLOCK;
34
35 rc = fcntl(fd, F_SETFL, flags);
36 if (rc < 0) {
37 ERROR_FROM_ERRNO(ctx);
38 }
39 }
40
41 static void set_reuseaddr(duk_context *ctx, int fd) {
42 int val;
43 int rc;
44
45 val = 1;
46 rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void *) &val, sizeof(val));
47 if (rc != 0) {
48 ERROR_FROM_ERRNO(ctx);
49 }
50 }
51
52 #ifdef __APPLE__
53 static void set_nosigpipe(duk_context *ctx, int fd) {
54 int val;
55 int rc;
56
57 val = 1;
58 rc = setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, (const void *) &val, sizeof(val));
59 if (rc != 0) {
60 ERROR_FROM_ERRNO(ctx);
61 }
62 }
63 #endif
64
65 static int socket_create_server_socket(duk_context *ctx) {
66 const char *addr = duk_to_string(ctx, 0);
67 int port = duk_to_int(ctx, 1);
68 int sock;
69 struct sockaddr_in sockaddr;
70 struct hostent *ent;
71 struct in_addr **addr_list;
72 struct in_addr *addr_inet;
73 int i;
74 int rc;
75
76 sock = socket(AF_INET, SOCK_STREAM, 0);
77 if (sock < 0) {
78 ERROR_FROM_ERRNO(ctx);
79 }
80
81 set_nonblocking(ctx, sock);
82 set_reuseaddr(ctx, sock);
83 #ifdef __APPLE__
84 set_nosigpipe(ctx, sock);
85 #endif
86
87 ent = gethostbyname(addr);
88 if (!ent) {
89 ERROR_FROM_ERRNO(ctx);
90 }
91
92 addr_list = (struct in_addr **) ent->h_addr_list;
93 addr_inet = NULL;
94 for (i = 0; addr_list[i]; i++) {
95 addr_inet = addr_list[i];
96 break;
97 }
98 if (!addr_inet) {
99 duk_error(ctx, DUK_ERR_ERROR, "cannot resolve %s", addr);
100 }
101
102 memset(&sockaddr, 0, sizeof(sockaddr));
103 sockaddr.sin_family = AF_INET;
104 sockaddr.sin_port = htons(port);
105 sockaddr.sin_addr = *addr_inet;
106
107 rc = bind(sock, (const struct sockaddr *) &sockaddr, sizeof(sockaddr));
108 if (rc < 0) {
109 ERROR_FROM_ERRNO(ctx);
110 }
111
112 rc = listen(sock, 10 /*backlog*/);
113 if (rc < 0) {
114 (void) close(sock);
115 ERROR_FROM_ERRNO(ctx);
116 }
117
118 duk_push_int(ctx, sock);
119 return 1;
120 }
121
122 static int socket_close(duk_context *ctx) {
123 int sock = duk_to_int(ctx, 0);
124 int rc;
125
126 rc = close(sock);
127 if (rc < 0) {
128 ERROR_FROM_ERRNO(ctx);
129 }
130 return 0;
131 }
132
133 static int socket_accept(duk_context *ctx) {
134 int sock = duk_to_int(ctx, 0);
135 int rc;
136 struct sockaddr_in addr;
137 socklen_t addrlen;
138
139 memset(&addr, 0, sizeof(addr));
140 addr.sin_family = AF_INET;
141 addrlen = sizeof(addr);
142
143 rc = accept(sock, (struct sockaddr *) &addr, &addrlen);
144 if (rc < 0) {
145 ERROR_FROM_ERRNO(ctx);
146 }
147
148 set_nonblocking(ctx, sock);
149 #ifdef __APPLE__
150 set_nosigpipe(ctx, sock);
151 #endif
152
153 if (addrlen == sizeof(addr)) {
154 uint32_t tmp = ntohl(addr.sin_addr.s_addr);
155
156 duk_push_object(ctx);
157
158 duk_push_string(ctx, "fd");
159 duk_push_int(ctx, rc);
160 duk_put_prop(ctx, -3);
161 duk_push_string(ctx, "addr");
162 duk_push_sprintf(ctx, "%d.%d.%d.%d", ((tmp >> 24) & 0xff), ((tmp >> 16) & 0xff), ((tmp >> 8) & 0xff), (tmp & 0xff));
163 duk_put_prop(ctx, -3);
164 duk_push_string(ctx, "port");
165 duk_push_int(ctx, ntohs(addr.sin_port));
166 duk_put_prop(ctx, -3);
167
168 return 1;
169 }
170
171 return 0;
172 }
173
174 static int socket_connect(duk_context *ctx) {
175 const char *addr = duk_to_string(ctx, 0);
176 int port = duk_to_int(ctx, 1);
177 int sock;
178 struct sockaddr_in sockaddr;
179 struct hostent *ent;
180 struct in_addr **addr_list;
181 struct in_addr *addr_inet;
182 int i;
183 int rc;
184
185 sock = socket(AF_INET, SOCK_STREAM, 0);
186 if (sock < 0) {
187 ERROR_FROM_ERRNO(ctx);
188 }
189
190 set_nonblocking(ctx, sock);
191 #ifdef __APPLE__
192 set_nosigpipe(ctx, sock);
193 #endif
194
195 ent = gethostbyname(addr);
196 if (!ent) {
197 ERROR_FROM_ERRNO(ctx);
198 }
199
200 addr_list = (struct in_addr **) ent->h_addr_list;
201 addr_inet = NULL;
202 for (i = 0; addr_list[i]; i++) {
203 addr_inet = addr_list[i];
204 break;
205 }
206 if (!addr_inet) {
207 duk_error(ctx, DUK_ERR_ERROR, "cannot resolve %s", addr);
208 }
209
210 memset(&sockaddr, 0, sizeof(sockaddr));
211 sockaddr.sin_family = AF_INET;
212 sockaddr.sin_port = htons(port);
213 sockaddr.sin_addr = *addr_inet;
214
215 rc = connect(sock, (const struct sockaddr *) &sockaddr, (socklen_t) sizeof(sockaddr));
216 if (rc < 0) {
217 if (errno == EINPROGRESS) {
218 #if 0
219 fprintf(stderr, "connect() returned EINPROGRESS as expected, need to poll writability\n");
220 fflush(stderr);
221 #endif
222 } else {
223 ERROR_FROM_ERRNO(ctx);
224 }
225 }
226
227 duk_push_int(ctx, sock);
228 return 1;
229 }
230
231 static int socket_read(duk_context *ctx) {
232 int sock = duk_to_int(ctx, 0);
233 char readbuf[1024];
234 int rc;
235 void *data;
236
237 rc = recvfrom(sock, (void *) readbuf, sizeof(readbuf), 0, NULL, NULL);
238 if (rc < 0) {
239 ERROR_FROM_ERRNO(ctx);
240 }
241
242 data = duk_push_fixed_buffer(ctx, rc);
243 memcpy(data, readbuf, rc);
244 return 1;
245 }
246
247 static int socket_write(duk_context *ctx) {
248 int sock = duk_to_int(ctx, 0);
249 const char *data;
250 size_t len;
251 ssize_t rc;
252
253 data = duk_to_buffer(ctx, 1, &len);
254
255 /* MSG_NOSIGNAL: avoid SIGPIPE */
256 #ifdef __APPLE__
257 rc = sendto(sock, (void *) data, len, 0, NULL, 0);
258 #else
259 rc = sendto(sock, (void *) data, len, MSG_NOSIGNAL, NULL, 0);
260 #endif
261 if (rc < 0) {
262 ERROR_FROM_ERRNO(ctx);
263 }
264
265 duk_push_int(ctx, rc);
266 return 1;
267 }
268
269 static duk_function_list_entry socket_funcs[] = {
270 { "createServerSocket", socket_create_server_socket, 2 },
271 { "close", socket_close, 1 },
272 { "accept", socket_accept, 1 },
273 { "connect", socket_connect, 2 },
274 { "read", socket_read, 1 },
275 { "write", socket_write, 2 },
276 { NULL, NULL, 0 }
277 };
278
279 void socket_register(duk_context *ctx) {
280 /* Set global 'Socket'. */
281 duk_push_global_object(ctx);
282 duk_push_object(ctx);
283 duk_put_function_list(ctx, -1, socket_funcs);
284 duk_put_prop_string(ctx, -2, "Socket");
285 duk_pop(ctx);
286 }