/* -*- mode: c; c-basic-offset: 2 -*- */ #define NOGDI #define NOUSER #define _INC_MMSYSTEM typedef struct tagMSG *LPMSG; #include #include #undef VOID static void setdown() { } #define vmfail(s) { \ fprintf(stderr, "vm primop/value %s is not available on your platform, aborting.", s); \ abort(); } #define _ADDSOCK(sock) { sockets[sock] = 1; } enum { O_DIRECTORY, O_NOCTTY, O_NONBLOCK, O_SYNC, FD_CLOEXEC, F_DUPFD, F_GETFD, F_SETFD, F_GETFL, F_SETFL, F_GETOWN, F_SETOWN, F_GETLK, F_SETLK, F_SETLKW, F_RDLCK, F_UNLCK, F_WRLCK, S_IFLNK, S_IFSOCK, EDQUOT, ESTALE }; int fcntl(int fd, int cmd, intptr_t arg) { switch (cmd) { case F_DUPFD: vmfail("F_DUPFD"); break; case F_GETFD: vmfail("F_GETFD"); break; case F_SETFD: vmfail("F_SETFD"); break; case F_GETFL: return 0; // FIXME: this is a blatant lie case F_SETFL: { unsigned long mode = arg & O_NONBLOCK ? 1 : 0; return ioctlsocket(fd, FIONBIO, &mode); } case F_GETOWN: vmfail("F_GETOWN"); break; case F_SETOWN: vmfail("F_SETOWN"); break; case F_GETLK: vmfail("F_GETLK"); break; case F_SETLK: vmfail("F_SETLK"); break; case F_SETLKW: vmfail("F_SETLKW"); break; case F_RDLCK: vmfail("F_RDLCK"); break; case F_UNLCK: vmfail("F_UNLCK"); break; case F_WRLCK: vmfail("F_WRLCK"); break; } return -1; } static WSADATA wsa; static int wsaerrno = -1; /* win32 sockets are not ports, so you cannot write() to them */ #define MAX_SOCKETS (2<<14) static int sockets[MAX_SOCKETS] = {0}; #define issocket(fd) ((fd) < MAX_SOCKETS && sockets[(fd)]) int w32write(int fd, char* buf, size_t n) { if (issocket(fd)) return send(fd, buf, n, 0); return write(fd, buf, n); } int w32read(int fd, char* buf, size_t n) { if (issocket(fd)) return recv(fd, buf, n, 0); return read(fd, buf, n); } int w32close(int fd) { if (issocket(fd)) { sockets[fd] = 0; return closesocket(fd); } return close(fd); } /* this impl lies. i have 0 clue why it works at all */ static word do_poll_fds(word a, word b, word c) { word *cur; for (cur = (word *)a; (word)cur != INULL; cur = (word *)cur[2]) { int fd = immval(G(cur[1], 1)); if (!issocket(fd)) return cons(make_immediate(0, TPORT), F(1)); } for (cur = (word *)b; (word)cur != INULL; cur = (word *)cur[2]) { int fd = immval(G(cur[1], 1)); if (!issocket(fd)) return cons(make_immediate(1, TPORT), F(2)); } return cons(make_immediate(2, TPORT), F(3)); } /* this is mostly copied from unix do_poll */ static word do_poll_sockets(word a, word b, word c) { fd_set rs, ws, es; word *cur; hval r1, r2; int nfds = -1; struct timeval tv; int res; FD_ZERO(&rs); FD_ZERO(&ws); FD_ZERO(&es); for (cur = (word *)a; (word)cur != INULL; cur = (word *)cur[2]) { int fd = immval(G(cur[1], 1)); if (issocket(fd)) { FD_SET(fd, &rs); FD_SET(fd, &es); if (fd >= nfds) nfds = fd + 1; } else { return do_poll_fds(a, b, c); } } for (cur = (word *)b; (word)cur != INULL; cur = (word *)cur[2]) { int fd = immval(G(cur[1], 1)); if (issocket(fd)) { FD_SET(fd, &ws); FD_SET(fd, &es); if (fd >= nfds) nfds = fd + 1; } else { return do_poll_fds(a, b, c); } } if (c == IFALSE) { res = select(nfds, &rs, &ws, &es, NULL); } else { hval ms = immval(c); tv.tv_sec = ms/1000; tv.tv_usec = (ms%1000)*1000; res = select(nfds, &rs, &ws, &es, &tv); } if (res < 1) { r1 = IFALSE; r2 = BOOL(res < 0); /* 0 = timeout, otherwise error or signal */ } else { int fd; /* something active, wake the first thing */ for (fd = 0; ; ++fd) { if (FD_ISSET(fd, &rs)) { r1 = make_immediate(fd, TPORT); r2 = F(1); break; } else if (FD_ISSET(fd, &ws)) { r1 = make_immediate(fd, TPORT); r2 = F(2); break; } else if (FD_ISSET(fd, &es)) { r1 = make_immediate(fd, TPORT); r2 = F(3); break; } } } return cons(r1, r2); } /* a = rs, b = ws, c = timeout */ static word do_poll(word a, word b, word c) { if (llen((word*)a) < 1 && llen((word*)b) < 1) return do_poll_sockets(a, b, c); if (llen((word*)a) > 0) { if (issocket(immval(G(((word*)a)[1], 1)))) return do_poll_sockets(a, b, c); } if (llen((word*)b) > 0) { if (issocket(immval(G(((word*)b)[1], 1)))) return do_poll_sockets(a, b, c); } return do_poll_fds(a, b, c); } static void _setup(void) { WSAStartup(MAKEWORD(2, 2), &wsa); }