mirror of
https://github.com/janet-lang/janet
synced 2024-11-25 09:47:17 +00:00
Port net code to windows.
Use winsock2 and WSAPoll. Not the most high performance solution but should work well.
This commit is contained in:
parent
0745c15d7b
commit
4a693222b4
@ -29,6 +29,10 @@
|
|||||||
#define _POSIX_C_SOURCE 200112L
|
#define _POSIX_C_SOURCE 200112L
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(WIN32) || defined(_WIN32)
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Needed for realpath on linux */
|
/* Needed for realpath on linux */
|
||||||
#if !defined(_XOPEN_SOURCE) && (defined(__linux__) || defined(__EMSCRIPTEN__))
|
#if !defined(_XOPEN_SOURCE) && (defined(__linux__) || defined(__EMSCRIPTEN__))
|
||||||
#define _XOPEN_SOURCE 500
|
#define _XOPEN_SOURCE 500
|
||||||
|
144
src/core/net.c
144
src/core/net.c
@ -26,6 +26,14 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef JANET_WINDOWS
|
||||||
|
#include <windows.h>
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
#pragma comment (lib, "Ws2_32.lib")
|
||||||
|
#pragma comment (lib, "Mswsock.lib")
|
||||||
|
#pragma comment (lib, "Advapi32.lib")
|
||||||
|
#else
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
@ -34,6 +42,7 @@
|
|||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Streams
|
* Streams
|
||||||
@ -44,7 +53,11 @@
|
|||||||
#define JANET_STREAM_WRITABLE 4
|
#define JANET_STREAM_WRITABLE 4
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
#ifdef JANET_WINDOWS
|
||||||
|
SOCKET socket;
|
||||||
|
#else
|
||||||
int fd;
|
int fd;
|
||||||
|
#endif
|
||||||
int flags;
|
int flags;
|
||||||
} JanetStream;
|
} JanetStream;
|
||||||
|
|
||||||
@ -65,11 +78,25 @@ static int janet_stream_close(void *p, size_t s) {
|
|||||||
JanetStream *stream = p;
|
JanetStream *stream = p;
|
||||||
if (!(stream->flags & JANET_STREAM_CLOSED)) {
|
if (!(stream->flags & JANET_STREAM_CLOSED)) {
|
||||||
stream->flags |= JANET_STREAM_CLOSED;
|
stream->flags |= JANET_STREAM_CLOSED;
|
||||||
|
#ifdef JANET_WINDOWS
|
||||||
|
closesocket(stream->socket);
|
||||||
|
#else
|
||||||
close(stream->fd);
|
close(stream->fd);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef JANET_WINDOWS
|
||||||
|
static JanetStream *make_stream(SOCKET socket, int flags) {
|
||||||
|
u_long iMode = 0;
|
||||||
|
JanetStream *stream = janet_abstract(&StreamAT, sizeof(JanetStream));
|
||||||
|
ioctlsocket(socket, FIONBIO, &iMode);
|
||||||
|
stream->socket = socket;
|
||||||
|
stream->flags = flags;
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
#else
|
||||||
static JanetStream *make_stream(int fd, int flags) {
|
static JanetStream *make_stream(int fd, int flags) {
|
||||||
JanetStream *stream = janet_abstract(&StreamAT, sizeof(JanetStream));
|
JanetStream *stream = janet_abstract(&StreamAT, sizeof(JanetStream));
|
||||||
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
|
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
|
||||||
@ -77,6 +104,7 @@ static JanetStream *make_stream(int fd, int flags) {
|
|||||||
stream->flags = flags;
|
stream->flags = flags;
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Event loop
|
* Event loop
|
||||||
@ -139,7 +167,11 @@ typedef struct {
|
|||||||
#define JANET_LOOPFD_MAX 1024
|
#define JANET_LOOPFD_MAX 1024
|
||||||
|
|
||||||
/* Global loop data */
|
/* Global loop data */
|
||||||
|
#ifdef JANET_WINDOWS
|
||||||
|
JANET_THREAD_LOCAL WSAPOLLFD janet_vm_pollfds[JANET_LOOPFD_MAX];
|
||||||
|
#else
|
||||||
JANET_THREAD_LOCAL struct pollfd janet_vm_pollfds[JANET_LOOPFD_MAX];
|
JANET_THREAD_LOCAL struct pollfd janet_vm_pollfds[JANET_LOOPFD_MAX];
|
||||||
|
#endif
|
||||||
JANET_THREAD_LOCAL JanetLoopFD janet_vm_loopfds[JANET_LOOPFD_MAX];
|
JANET_THREAD_LOCAL JanetLoopFD janet_vm_loopfds[JANET_LOOPFD_MAX];
|
||||||
JANET_THREAD_LOCAL int janet_vm_loop_count;
|
JANET_THREAD_LOCAL int janet_vm_loop_count;
|
||||||
|
|
||||||
@ -179,7 +211,11 @@ static int janet_loop_schedule(JanetLoopFD lfd, short events) {
|
|||||||
}
|
}
|
||||||
int index = janet_vm_loop_count++;
|
int index = janet_vm_loop_count++;
|
||||||
janet_vm_loopfds[index] = lfd;
|
janet_vm_loopfds[index] = lfd;
|
||||||
|
#ifdef JANET_WINDOWS
|
||||||
|
janet_vm_pollfds[index].fd = lfd.stream->socket;
|
||||||
|
#else
|
||||||
janet_vm_pollfds[index].fd = lfd.stream->fd;
|
janet_vm_pollfds[index].fd = lfd.stream->fd;
|
||||||
|
#endif
|
||||||
janet_vm_pollfds[index].events = events;
|
janet_vm_pollfds[index].events = events;
|
||||||
janet_vm_pollfds[index].revents = 0;
|
janet_vm_pollfds[index].revents = 0;
|
||||||
return index;
|
return index;
|
||||||
@ -197,7 +233,11 @@ static void janet_loop_rmindex(int index) {
|
|||||||
static size_t janet_loop_event(size_t index) {
|
static size_t janet_loop_event(size_t index) {
|
||||||
JanetLoopFD *jlfd = janet_vm_loopfds + index;
|
JanetLoopFD *jlfd = janet_vm_loopfds + index;
|
||||||
JanetStream *stream = jlfd->stream;
|
JanetStream *stream = jlfd->stream;
|
||||||
|
#ifdef JANET_WINDOWS
|
||||||
|
SOCKET socket = stream->socket;
|
||||||
|
#else
|
||||||
int fd = stream->fd;
|
int fd = stream->fd;
|
||||||
|
#endif
|
||||||
int ret = 1;
|
int ret = 1;
|
||||||
int should_resume = 0;
|
int should_resume = 0;
|
||||||
Janet resumeval = janet_wrap_nil();
|
Janet resumeval = janet_wrap_nil();
|
||||||
@ -211,20 +251,30 @@ static size_t janet_loop_event(size_t index) {
|
|||||||
JanetBuffer *buffer = jlfd->data.read_chunk.buf;
|
JanetBuffer *buffer = jlfd->data.read_chunk.buf;
|
||||||
int32_t bytes_left = jlfd->data.read_chunk.bytes_left;
|
int32_t bytes_left = jlfd->data.read_chunk.bytes_left;
|
||||||
janet_buffer_extra(buffer, bytes_left);
|
janet_buffer_extra(buffer, bytes_left);
|
||||||
ssize_t nread;
|
|
||||||
errno = 0;
|
|
||||||
if (!(stream->flags & JANET_STREAM_READABLE)) {
|
if (!(stream->flags & JANET_STREAM_READABLE)) {
|
||||||
should_resume = 1;
|
should_resume = 1;
|
||||||
ret = 0;
|
ret = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#ifdef JANET_WINDOWS
|
||||||
|
long nread;
|
||||||
|
do {
|
||||||
|
nread = recv(socket, buffer->data + buffer->count, bytes_left, 0);
|
||||||
|
} while (nread == -1 && WSAGetLastError() == WSAEINTR);
|
||||||
|
if (WSAGetLastError() == WSAEWOULDBLOCK) {
|
||||||
|
ret = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
ssize_t nread;
|
||||||
do {
|
do {
|
||||||
nread = read(fd, buffer->data + buffer->count, bytes_left);
|
nread = read(fd, buffer->data + buffer->count, bytes_left);
|
||||||
} while (errno == EINTR);
|
} while (nread == -1 && errno == EINTR);
|
||||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||||
ret = 1;
|
ret = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
if (nread > 0) {
|
if (nread > 0) {
|
||||||
buffer->count += nread;
|
buffer->count += nread;
|
||||||
bytes_left -= nread;
|
bytes_left -= nread;
|
||||||
@ -244,10 +294,15 @@ static size_t janet_loop_event(size_t index) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case JLE_READ_ACCEPT: {
|
case JLE_READ_ACCEPT: {
|
||||||
|
#ifdef JANET_WINDOWS
|
||||||
|
SOCKET connfd = accept(socket, NULL, NULL);
|
||||||
|
if (connfd != INVALID_SOCKET) {
|
||||||
|
#else
|
||||||
char addr[256] = {0}; /* Just make sure it is large enough for largest address type */
|
char addr[256] = {0}; /* Just make sure it is large enough for largest address type */
|
||||||
socklen_t len = 0;
|
socklen_t len = 0;
|
||||||
int connfd = accept(fd, (void *) &addr, &len);
|
int connfd = accept(fd, (void *) &addr, &len);
|
||||||
if (connfd >= 0) {
|
if (connfd >= 0) {
|
||||||
|
#endif
|
||||||
/* Made a new connection socket */
|
/* Made a new connection socket */
|
||||||
JanetStream *stream = make_stream(connfd, JANET_STREAM_READABLE | JANET_STREAM_WRITABLE);
|
JanetStream *stream = make_stream(connfd, JANET_STREAM_READABLE | JANET_STREAM_WRITABLE);
|
||||||
Janet streamv = janet_wrap_abstract(stream);
|
Janet streamv = janet_wrap_abstract(stream);
|
||||||
@ -284,11 +339,17 @@ static size_t janet_loop_event(size_t index) {
|
|||||||
}
|
}
|
||||||
if (start < len) {
|
if (start < len) {
|
||||||
int32_t nbytes = len - start;
|
int32_t nbytes = len - start;
|
||||||
|
#ifdef JANET_WINDOWS
|
||||||
|
long nwrote;
|
||||||
|
do {
|
||||||
|
nwrote = send(socket, bytes + start, nbytes, 0);
|
||||||
|
} while (nwrote == -1 && WSAGetLastError() == WSAEINTR);
|
||||||
|
#else
|
||||||
ssize_t nwrote;
|
ssize_t nwrote;
|
||||||
errno = 0;
|
|
||||||
do {
|
do {
|
||||||
nwrote = write(fd, bytes + start, nbytes);
|
nwrote = write(fd, bytes + start, nbytes);
|
||||||
} while (errno == EINTR);
|
} while (nwrote == -1 && errno == EINTR);
|
||||||
|
#endif
|
||||||
if (nwrote > 0) {
|
if (nwrote > 0) {
|
||||||
start += nwrote;
|
start += nwrote;
|
||||||
} else {
|
} else {
|
||||||
@ -309,7 +370,6 @@ static size_t janet_loop_event(size_t index) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case JLE_CONNECT: {
|
case JLE_CONNECT: {
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -326,7 +386,7 @@ static size_t janet_loop_event(size_t index) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Remove this handler from the handler pool. */
|
/* Remove this handler from the handler pool. */
|
||||||
if (should_resume) janet_loop_rmindex(index);
|
if (should_resume) janet_loop_rmindex((int) index);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -343,15 +403,24 @@ static void janet_loop1(void) {
|
|||||||
/* Poll */
|
/* Poll */
|
||||||
if (janet_vm_loop_count == 0) return;
|
if (janet_vm_loop_count == 0) return;
|
||||||
int ready;
|
int ready;
|
||||||
|
#ifdef JANET_WINDOWS
|
||||||
|
do {
|
||||||
|
ready = WSAPoll(janet_vm_pollfds, janet_vm_loop_count, -1);
|
||||||
|
} while (ready == -1 && WSAGetLastError() == WSAEINTR);
|
||||||
|
if (ready == -1) return;
|
||||||
|
#else
|
||||||
do {
|
do {
|
||||||
ready = poll(janet_vm_pollfds, janet_vm_loop_count, -1);
|
ready = poll(janet_vm_pollfds, janet_vm_loop_count, -1);
|
||||||
} while (ready == -1 && errno == EAGAIN);
|
} while (ready == -1 && errno == EAGAIN);
|
||||||
if (ready == -1) return;
|
if (ready == -1) return;
|
||||||
|
#endif
|
||||||
/* Handle events */
|
/* Handle events */
|
||||||
for (int i = 0; i < janet_vm_loop_count;) {
|
for (int i = 0; i < janet_vm_loop_count;) {
|
||||||
if (janet_vm_pollfds[i].events & janet_vm_pollfds[i].revents) {
|
int revents = janet_vm_pollfds[i].revents;
|
||||||
|
janet_vm_pollfds[i].revents = 0;
|
||||||
|
if ((janet_vm_pollfds[i].events | POLLHUP | POLLER) & revents) {
|
||||||
size_t delta = janet_loop_event(i);
|
size_t delta = janet_loop_event(i);
|
||||||
i += delta;
|
i += (int) delta;
|
||||||
} else {
|
} else {
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
@ -431,6 +500,22 @@ static Janet cfun_net_connect(int32_t argc, Janet *argv) {
|
|||||||
|
|
||||||
struct addrinfo *ai = janet_get_addrinfo(argv, 0);
|
struct addrinfo *ai = janet_get_addrinfo(argv, 0);
|
||||||
|
|
||||||
|
#ifdef JANET_WINDOWS
|
||||||
|
/* Create socket */
|
||||||
|
SOCKET sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
|
||||||
|
if (sock == INVALID_SOCKET) {
|
||||||
|
freeaddrinfo(ai);
|
||||||
|
janet_panic("could not create socket");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Connect to socket */
|
||||||
|
int status = connect(sock, ai->ai_addr, (int) ai->ai_addrlen);
|
||||||
|
freeaddrinfo(ai);
|
||||||
|
if (status == -1) {
|
||||||
|
closesocket(sock);
|
||||||
|
janet_panic("could not connect to socket");
|
||||||
|
}
|
||||||
|
#else
|
||||||
/* Create socket */
|
/* Create socket */
|
||||||
int sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
|
int sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
|
||||||
if (sock < 0) {
|
if (sock < 0) {
|
||||||
@ -445,6 +530,7 @@ static Janet cfun_net_connect(int32_t argc, Janet *argv) {
|
|||||||
close(sock);
|
close(sock);
|
||||||
janet_panic("could not connect to socket");
|
janet_panic("could not connect to socket");
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Wrap socket in abstract type JanetStream */
|
/* Wrap socket in abstract type JanetStream */
|
||||||
JanetStream *stream = make_stream(sock, JANET_STREAM_READABLE | JANET_STREAM_WRITABLE);
|
JanetStream *stream = make_stream(sock, JANET_STREAM_READABLE | JANET_STREAM_WRITABLE);
|
||||||
@ -459,6 +545,36 @@ static Janet cfun_net_server(int32_t argc, Janet *argv) {
|
|||||||
|
|
||||||
struct addrinfo *ai = janet_get_addrinfo(argv, 0);
|
struct addrinfo *ai = janet_get_addrinfo(argv, 0);
|
||||||
|
|
||||||
|
#ifdef JANET_WINDOWS
|
||||||
|
/* Check all addrinfos in a loop for the first that we can bind to. */
|
||||||
|
SOCKET sfd = INVALID_SOCKET;
|
||||||
|
struct addrinfo *rp = NULL;
|
||||||
|
for (rp = ai; rp != NULL; rp = rp->ai_next) {
|
||||||
|
sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
|
||||||
|
if (sfd == INVALID_SOCKET) continue;
|
||||||
|
/* Set various socket options */
|
||||||
|
int enable = 1;
|
||||||
|
if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (char *) &enable, sizeof(int)) < 0) {
|
||||||
|
closesocket(sfd);
|
||||||
|
janet_panic("setsockopt(SO_REUSEADDR) failed");
|
||||||
|
}
|
||||||
|
/* Bind */
|
||||||
|
if (bind(sfd, rp->ai_addr, (int) rp->ai_addrlen) == 0) break;
|
||||||
|
closesocket(sfd);
|
||||||
|
}
|
||||||
|
if (NULL == rp) {
|
||||||
|
freeaddrinfo(ai);
|
||||||
|
janet_panic("could not bind to any sockets");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* listen */
|
||||||
|
int status = listen(sfd, 1024);
|
||||||
|
freeaddrinfo(ai);
|
||||||
|
if (status) {
|
||||||
|
closesocket(sfd);
|
||||||
|
janet_panic("could not listen on file descriptor");
|
||||||
|
}
|
||||||
|
#else
|
||||||
/* Check all addrinfos in a loop for the first that we can bind to. */
|
/* Check all addrinfos in a loop for the first that we can bind to. */
|
||||||
int sfd = 0;
|
int sfd = 0;
|
||||||
struct addrinfo *rp = NULL;
|
struct addrinfo *rp = NULL;
|
||||||
@ -498,6 +614,7 @@ static Janet cfun_net_server(int32_t argc, Janet *argv) {
|
|||||||
* Since a connection could be disconnected at any time, any read or write may fail.
|
* Since a connection could be disconnected at any time, any read or write may fail.
|
||||||
* We don't want to blow up the whole application. */
|
* We don't want to blow up the whole application. */
|
||||||
signal(SIGPIPE, SIG_IGN);
|
signal(SIGPIPE, SIG_IGN);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Put sfd on our loop */
|
/* Put sfd on our loop */
|
||||||
JanetLoopFD lfd = {0};
|
JanetLoopFD lfd = {0};
|
||||||
@ -572,6 +689,15 @@ static const JanetReg net_cfuns[] = {
|
|||||||
|
|
||||||
void janet_lib_net(JanetTable *env) {
|
void janet_lib_net(JanetTable *env) {
|
||||||
janet_vm_loop_count = 0;
|
janet_vm_loop_count = 0;
|
||||||
|
#ifdef JANET_WINDOWS
|
||||||
|
WSADATA wsaData;
|
||||||
|
janet_assert(!WSAStartup(MAKEWORD(2, 2), &wsaData), "could not start winsock");
|
||||||
|
#endif
|
||||||
janet_core_cfuns(env, NULL, net_cfuns);
|
janet_core_cfuns(env, NULL, net_cfuns);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void janet_net_deinit(void) {
|
||||||
|
#ifdef JANET_WINDOWS
|
||||||
|
WSACleanup();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
#ifndef janet_exit
|
#ifndef janet_exit
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#define janet_exit(m) do { \
|
#define janet_exit(m) do { \
|
||||||
printf("C runtime error at line %d in file %s: %s\n",\
|
fprintf(stderr, "C runtime error at line %d in file %s: %s\n",\
|
||||||
__LINE__,\
|
__LINE__,\
|
||||||
__FILE__,\
|
__FILE__,\
|
||||||
(m));\
|
(m));\
|
||||||
@ -50,7 +50,7 @@
|
|||||||
/* What to do when out of memory */
|
/* What to do when out of memory */
|
||||||
#ifndef JANET_OUT_OF_MEMORY
|
#ifndef JANET_OUT_OF_MEMORY
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#define JANET_OUT_OF_MEMORY do { printf("janet out of memory\n"); exit(1); } while (0)
|
#define JANET_OUT_OF_MEMORY do { fprintf(stderr, "janet out of memory\n"); exit(1); } while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Omit docstrings in some builds */
|
/* Omit docstrings in some builds */
|
||||||
@ -128,6 +128,7 @@ void janet_lib_thread(JanetTable *env);
|
|||||||
#endif
|
#endif
|
||||||
#ifdef JANET_NET
|
#ifdef JANET_NET
|
||||||
void janet_lib_net(JanetTable *env);
|
void janet_lib_net(JanetTable *env);
|
||||||
|
void janet_net_deinit(void);
|
||||||
void janet_net_markloop(void);
|
void janet_net_markloop(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1444,4 +1444,7 @@ void janet_deinit(void) {
|
|||||||
#ifdef JANET_THREADS
|
#ifdef JANET_THREADS
|
||||||
janet_threads_deinit();
|
janet_threads_deinit();
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef JANET_NET
|
||||||
|
janet_net_deinit();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user