2 * TCP sockets binding example.
12 #include <sys/types.h>
13 #include <sys/socket.h>
14 #include <netinet/in.h>
19 #define ERROR_FROM_ERRNO(ctx) do { \
20 duk_error(ctx, DUK_ERR_ERROR, "%s (errno=%d)", strerror(errno), errno); \
23 static void set_nonblocking(duk_context
*ctx
, int fd
) {
27 rc
= fcntl(fd
, F_GETFL
);
29 ERROR_FROM_ERRNO(ctx
);
35 rc
= fcntl(fd
, F_SETFL
, flags
);
37 ERROR_FROM_ERRNO(ctx
);
41 static void set_reuseaddr(duk_context
*ctx
, int fd
) {
46 rc
= setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, (const void *) &val
, sizeof(val
));
48 ERROR_FROM_ERRNO(ctx
);
53 static void set_nosigpipe(duk_context
*ctx
, int fd
) {
58 rc
= setsockopt(fd
, SOL_SOCKET
, SO_NOSIGPIPE
, (const void *) &val
, sizeof(val
));
60 ERROR_FROM_ERRNO(ctx
);
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);
69 struct sockaddr_in sockaddr
;
71 struct in_addr
**addr_list
;
72 struct in_addr
*addr_inet
;
76 sock
= socket(AF_INET
, SOCK_STREAM
, 0);
78 ERROR_FROM_ERRNO(ctx
);
81 set_nonblocking(ctx
, sock
);
82 set_reuseaddr(ctx
, sock
);
84 set_nosigpipe(ctx
, sock
);
87 ent
= gethostbyname(addr
);
89 ERROR_FROM_ERRNO(ctx
);
92 addr_list
= (struct in_addr
**) ent
->h_addr_list
;
94 for (i
= 0; addr_list
[i
]; i
++) {
95 addr_inet
= addr_list
[i
];
99 duk_error(ctx
, DUK_ERR_ERROR
, "cannot resolve %s", addr
);
102 memset(&sockaddr
, 0, sizeof(sockaddr
));
103 sockaddr
.sin_family
= AF_INET
;
104 sockaddr
.sin_port
= htons(port
);
105 sockaddr
.sin_addr
= *addr_inet
;
107 rc
= bind(sock
, (const struct sockaddr
*) &sockaddr
, sizeof(sockaddr
));
109 ERROR_FROM_ERRNO(ctx
);
112 rc
= listen(sock
, 10 /*backlog*/);
115 ERROR_FROM_ERRNO(ctx
);
118 duk_push_int(ctx
, sock
);
122 static int socket_close(duk_context
*ctx
) {
123 int sock
= duk_to_int(ctx
, 0);
128 ERROR_FROM_ERRNO(ctx
);
133 static int socket_accept(duk_context
*ctx
) {
134 int sock
= duk_to_int(ctx
, 0);
136 struct sockaddr_in addr
;
139 memset(&addr
, 0, sizeof(addr
));
140 addr
.sin_family
= AF_INET
;
141 addrlen
= sizeof(addr
);
143 rc
= accept(sock
, (struct sockaddr
*) &addr
, &addrlen
);
145 ERROR_FROM_ERRNO(ctx
);
148 set_nonblocking(ctx
, sock
);
150 set_nosigpipe(ctx
, sock
);
153 if (addrlen
== sizeof(addr
)) {
154 uint32_t tmp
= ntohl(addr
.sin_addr
.s_addr
);
156 duk_push_object(ctx
);
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);
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);
178 struct sockaddr_in sockaddr
;
180 struct in_addr
**addr_list
;
181 struct in_addr
*addr_inet
;
185 sock
= socket(AF_INET
, SOCK_STREAM
, 0);
187 ERROR_FROM_ERRNO(ctx
);
190 set_nonblocking(ctx
, sock
);
192 set_nosigpipe(ctx
, sock
);
195 ent
= gethostbyname(addr
);
197 ERROR_FROM_ERRNO(ctx
);
200 addr_list
= (struct in_addr
**) ent
->h_addr_list
;
202 for (i
= 0; addr_list
[i
]; i
++) {
203 addr_inet
= addr_list
[i
];
207 duk_error(ctx
, DUK_ERR_ERROR
, "cannot resolve %s", addr
);
210 memset(&sockaddr
, 0, sizeof(sockaddr
));
211 sockaddr
.sin_family
= AF_INET
;
212 sockaddr
.sin_port
= htons(port
);
213 sockaddr
.sin_addr
= *addr_inet
;
215 rc
= connect(sock
, (const struct sockaddr
*) &sockaddr
, (socklen_t
) sizeof(sockaddr
));
217 if (errno
== EINPROGRESS
) {
219 fprintf(stderr
, "connect() returned EINPROGRESS as expected, need to poll writability\n");
223 ERROR_FROM_ERRNO(ctx
);
227 duk_push_int(ctx
, sock
);
231 static int socket_read(duk_context
*ctx
) {
232 int sock
= duk_to_int(ctx
, 0);
237 rc
= recvfrom(sock
, (void *) readbuf
, sizeof(readbuf
), 0, NULL
, NULL
);
239 ERROR_FROM_ERRNO(ctx
);
242 data
= duk_push_fixed_buffer(ctx
, rc
);
243 memcpy(data
, readbuf
, rc
);
247 static int socket_write(duk_context
*ctx
) {
248 int sock
= duk_to_int(ctx
, 0);
253 data
= duk_to_buffer(ctx
, 1, &len
);
255 /* MSG_NOSIGNAL: avoid SIGPIPE */
257 rc
= sendto(sock
, (void *) data
, len
, 0, NULL
, 0);
259 rc
= sendto(sock
, (void *) data
, len
, MSG_NOSIGNAL
, NULL
, 0);
262 ERROR_FROM_ERRNO(ctx
);
265 duk_push_int(ctx
, rc
);
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 },
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");