chibi-scheme/lib/chibi/accept.c
Alex Shinn 8b5eb68238 File descriptors maintain a reference count of ports open on them
They can be close()d explicitly with close-file-descriptor, and
will close() on gc, but only explicitly closing the last port on
them will close the fileno.  Notably needed for network sockets
where we open separate input and output ports on the same socket.
2014-02-20 22:32:50 +09:00

56 lines
1.9 KiB
C

/* chibi-ffi should probably be able to detect these patterns automatically, */
/* but for now we manually check two special cases - accept should check for */
/* EWOULDBLOCK and block on the socket, and listen should automatically make */
/* sockets non-blocking. */
sexp sexp_accept (sexp ctx, sexp self, int sock, struct sockaddr* addr, socklen_t len) {
#if SEXP_USE_GREEN_THREADS
sexp f;
#endif
int res;
res = accept(sock, addr, &len);
#if SEXP_USE_GREEN_THREADS
if (res < 0 && errno == EWOULDBLOCK) {
f = sexp_global(ctx, SEXP_G_THREADS_BLOCKER);
if (sexp_opcodep(f)) {
((sexp_proc2)sexp_opcode_func(f))(ctx, f, 1, sexp_make_fixnum(sock));
return sexp_global(ctx, SEXP_G_IO_BLOCK_ERROR);
}
}
if (res >= 0)
fcntl(res, F_SETFL, fcntl(res, F_GETFL) | O_NONBLOCK);
#endif
return sexp_make_fileno(ctx, sexp_make_fixnum(res), SEXP_FALSE);
}
/* If we're listening on a socket from Scheme, we most likely want it */
/* to be non-blocking. */
sexp sexp_listen (sexp ctx, sexp self, sexp fileno, sexp backlog) {
int fd, res;
sexp_assert_type(ctx, sexp_filenop, SEXP_FILENO, fileno);
sexp_assert_type(ctx, sexp_fixnump, SEXP_FIXNUM, backlog);
fd = sexp_fileno_fd(fileno);
res = listen(fd, sexp_unbox_fixnum(backlog));
#if SEXP_USE_GREEN_THREADS
if (res >= 0)
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
#endif
return (res == 0) ? SEXP_TRUE : SEXP_FALSE;
}
/* Additional utilities. */
sexp sexp_sockaddr_name (sexp ctx, sexp self, struct sockaddr* addr) {
char buf[20];
struct sockaddr_in *sa = (struct sockaddr_in *)addr;
unsigned char *ptr = (unsigned char *)&(sa->sin_addr);
sprintf(buf, "%d.%d.%d.%d", ptr[0], ptr[1], ptr[2], ptr[3]);
return sexp_c_string(ctx, buf, -1);
}
int sexp_sockaddr_port (sexp ctx, sexp self, struct sockaddr* addr) {
struct sockaddr_in *sa = (struct sockaddr_in *)addr;
return sa->sin_port;
}