From f85b5c7c161d831a6ed2e727ac838eff28cee845 Mon Sep 17 00:00:00 2001 From: Dima Krasner Date: Sun, 16 Aug 2015 23:56:55 +0300 Subject: [PATCH 1/4] Fixed socket support on MinGW --- auto.def | 3 +++ jim-aio.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++-- jim-eventloop.c | 10 +++++++++- 3 files changed, 63 insertions(+), 3 deletions(-) diff --git a/auto.def b/auto.def index 7404e851..58d80b0e 100644 --- a/auto.def +++ b/auto.def @@ -127,6 +127,9 @@ switch -glob -- $host_os { define TCL_PLATFORM_OS $host_os define TCL_PLATFORM_PLATFORM windows define TCL_PLATFORM_PATH_SEPARATOR {;} + if {[cc-check-function-in-lib socket ws2_32]} { + define-append LDLIBS [get-define lib_socket] + } } default { # Note that cygwin is considered a unix platform diff --git a/jim-aio.c b/jim-aio.c index ef3f139f..2044dcb5 100644 --- a/jim-aio.c +++ b/jim-aio.c @@ -50,6 +50,11 @@ #include "jim.h" +#ifdef __MINGW32__ +#include +#include +#include +#else #if defined(HAVE_SYS_SOCKET_H) && defined(HAVE_SELECT) && defined(HAVE_NETINET_IN_H) && defined(HAVE_NETDB_H) && defined(HAVE_ARPA_INET_H) #include #include @@ -61,6 +66,7 @@ #else #define JIM_ANSIC #endif +#endif #include "jim-eventloop.h" #include "jim-subcmd.h" @@ -533,11 +539,25 @@ static int aio_cmd_puts(Jim_Interp *interp, int argc, Jim_Obj *const *argv) } wdata = Jim_GetString(strObj, &wlen); +#ifdef __MINGW32__ + errno = 0; +#endif if (fwrite(wdata, 1, wlen, af->fp) == (unsigned)wlen) { if (argc == 2 || putc('\n', af->fp) != EOF) { return JIM_OK; } } +#ifdef __MINGW32__ + /* fwrite() doesn't seem to work with sockets, so we fall back to good ol' send() */ + if (errno == 0) { + SOCKET sock = _get_osfhandle(fileno(af->fp)); + if (send(sock, wdata, wlen, 0) == (unsigned)wlen) { + if (argc == 2 || send(sock, "\n", 1, 0) == 1) { + return JIM_OK; + } + } + } +#endif JimAioSetError(interp, af->filename); return JIM_ERR; } @@ -620,12 +640,21 @@ static int aio_cmd_sendto(Jim_Interp *interp, int argc, Jim_Obj *const *argv) static int aio_cmd_accept(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { AioFile *af = Jim_CmdPrivData(interp); +#ifdef __MINGW32__ + SOCKET sock; +#else int sock; +#endif union sockaddr_any sa; socklen_t addrlen = sizeof(sa); +#ifdef __MINGW32__ + sock = accept(_get_osfhandle(af->fd), &sa.sa, &addrlen); + if (sock == INVALID_SOCKET) { +#else sock = accept(af->fd, &sa.sa, &addrlen); if (sock < 0) { +#endif JimAioSetError(interp, NULL); return JIM_ERR; } @@ -637,8 +666,12 @@ static int aio_cmd_accept(Jim_Interp *interp, int argc, Jim_Obj *const *argv) } /* Create the file command */ - return JimMakeChannel(interp, NULL, sock, Jim_NewStringObj(interp, "accept", -1), - "aio.sockstream%ld", af->addr_family, "r+"); +#ifdef __MINGW32__ + return JimMakeChannel(interp, NULL, _open_osfhandle(sock, 0), +#else + return JimMakeChannel(interp, NULL, sock, +#endif + Jim_NewStringObj(interp, "accept", -1), "aio.sockstream%ld", af->addr_family, "r+"); } static int aio_cmd_listen(Jim_Interp *interp, int argc, Jim_Obj *const *argv) @@ -1209,7 +1242,11 @@ static int JimAioSockCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) SOCK_STREAM_SOCKETPAIR, }; int socktype; +#ifdef __MINGW32__ + SOCKET sock; +#else int sock; +#endif const char *hostportarg = NULL; int res; int on = 1; @@ -1446,7 +1483,11 @@ static int JimAioSockCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) return JIM_ERR; } +#ifdef __MINGW32__ + return JimMakeChannel(interp, NULL, _open_osfhandle(sock, 0), argv[1], hdlfmt, family, mode); +#else return JimMakeChannel(interp, NULL, sock, argv[1], hdlfmt, family, mode); +#endif } #endif /* JIM_BOOTSTRAP */ @@ -1512,6 +1553,14 @@ FILE *Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *command) int Jim_aioInit(Jim_Interp *interp) { +#ifdef __MINGW32__ + WSADATA data; + + if (WSAStartup(MAKEWORD(2, 2), &data) != 0) { + return JIM_ERR; + } +#endif + if (Jim_PackageProvide(interp, "aio", "1.0", JIM_ERRMSG)) return JIM_ERR; diff --git a/jim-eventloop.c b/jim-eventloop.c index 22ca5ff3..2371cc79 100644 --- a/jim-eventloop.c +++ b/jim-eventloop.c @@ -376,7 +376,7 @@ int Jim_ProcessEvents(Jim_Interp *interp, int flags) } } -#ifdef HAVE_SELECT +#if defined(HAVE_SELECT) || defined(__MINGW32__) if (flags & JIM_FILE_EVENTS) { int retval; struct timeval tv, *tvp = NULL; @@ -389,7 +389,11 @@ int Jim_ProcessEvents(Jim_Interp *interp, int flags) /* Check file events */ while (fe != NULL) { +#ifdef __MINGW32__ + SOCKET fd = _get_osfhandle(fileno(fe->handle)); +#else int fd = fileno(fe->handle); +#endif if (fe->mask & JIM_EVENT_READABLE) FD_SET(fd, &rfds); @@ -420,7 +424,11 @@ int Jim_ProcessEvents(Jim_Interp *interp, int flags) else if (retval > 0) { fe = eventLoop->fileEventHead; while (fe != NULL) { +#ifdef __MINGW32__ + SOCKET fd = _get_osfhandle(fileno(fe->handle)); +#else int fd = fileno(fe->handle); +#endif int mask = 0; if ((fe->mask & JIM_EVENT_READABLE) && FD_ISSET(fd, &rfds)) From 5456fe125cf719e4b10bba30942e7fff01fdfef2 Mon Sep 17 00:00:00 2001 From: Dima Krasner Date: Tue, 18 Aug 2015 00:18:51 +0300 Subject: [PATCH 2/4] Fixed gets and detection of socket() failure --- jim-aio.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/jim-aio.c b/jim-aio.c index 2044dcb5..153f5dca 100644 --- a/jim-aio.c +++ b/jim-aio.c @@ -477,8 +477,16 @@ static int aio_cmd_gets(Jim_Interp *interp, int argc, Jim_Obj *const *argv) objPtr = Jim_NewStringObj(interp, NULL, 0); while (1) { buf[AIO_BUF_LEN - 1] = '_'; - if (fgets(buf, AIO_BUF_LEN, af->fp) == NULL) + if (fgets(buf, AIO_BUF_LEN, af->fp) == NULL) { +#ifdef __MINGW32__ + int len = recv(_get_osfhandle(fileno(af->fp)), buf, AIO_BUF_LEN - 1, 0); + if (len <= 0) + break; + buf[len] = '\0'; +#else break; +#endif + } if (buf[AIO_BUF_LEN - 1] == '\0' && buf[AIO_BUF_LEN - 2] != '\n') { Jim_AppendString(interp, objPtr, buf, AIO_BUF_LEN - 1); @@ -1288,7 +1296,11 @@ static int JimAioSockCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) if (argc == 2) { /* No address, so an unconnected dgram socket */ sock = socket(family, SOCK_DGRAM, 0); +#ifdef __MINGW32__ + if (sock == INVALID_SOCKET) { +#else if (sock < 0) { +#endif JimAioSetError(interp, NULL); return JIM_ERR; } @@ -1313,7 +1325,11 @@ static int JimAioSockCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) return JIM_ERR; } sock = socket(family, (socktype == SOCK_DGRAM_CLIENT) ? SOCK_DGRAM : SOCK_STREAM, 0); +#ifdef __MINGW32__ + if (sock == INVALID_SOCKET) { +#else if (sock < 0) { +#endif JimAioSetError(interp, NULL); return JIM_ERR; } @@ -1345,7 +1361,11 @@ static int JimAioSockCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) return JIM_ERR; } sock = socket(family, (socktype == SOCK_DGRAM_SERVER) ? SOCK_DGRAM : SOCK_STREAM, 0); +#ifdef __MINGW32__ + if (sock == INVALID_SOCKET) { +#else if (sock < 0) { +#endif JimAioSetError(interp, NULL); return JIM_ERR; } From 5a9988d5ca182a1c961d4664b5c72e6b1bccf016 Mon Sep 17 00:00:00 2001 From: Dima Krasner Date: Thu, 20 Aug 2015 21:04:11 +0300 Subject: [PATCH 3/4] Fixed AIO error reporting on MinGW --- jim-aio.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/jim-aio.c b/jim-aio.c index 153f5dca..a0c86236 100644 --- a/jim-aio.c +++ b/jim-aio.c @@ -223,7 +223,7 @@ static int JimParseIpAddress(Jim_Interp *interp, const char *hostport, union soc } { -#ifdef HAVE_GETADDRINFO +#if defined(__MINGW32__) || defined(HAVE_GETADDRINFO) struct addrinfo req; struct addrinfo *ai; memset(&req, '\0', sizeof(req)); @@ -307,12 +307,45 @@ static int JimFormatIpAddress(Jim_Interp *interp, Jim_Obj *varObjPtr, const unio static void JimAioSetError(Jim_Interp *interp, Jim_Obj *name) { +#ifndef __MINGW32__ + const char *s; +#else + char *s; + int alloc = 0; + + /* try errno (which gets modified by FILE * functions, etc') first, then + * fall back to WSAGetLastError() (which gets modified by socket + * functions, i.e recv()) */ + if (errno != 0) { +#endif + s = strerror(errno); +#ifdef __MINGW32__ + } else { + if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + WSAGetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR)&s, + 0, + NULL) == 0) { + return; + } + alloc = 1; + } +#endif + if (name) { - Jim_SetResultFormatted(interp, "%#s: %s", name, strerror(errno)); + Jim_SetResultFormatted(interp, "%#s: %s", name, s); } else { - Jim_SetResultString(interp, strerror(errno), -1); + Jim_SetResultString(interp, s, -1); + } + +#ifdef __MINGW32__ + if (alloc) { + LocalFree(s); } +#endif } static void JimAioDelProc(Jim_Interp *interp, void *privData) @@ -337,6 +370,8 @@ static void JimAioDelProc(Jim_Interp *interp, void *privData) static int JimCheckStreamError(Jim_Interp *interp, AioFile *af) { + int err; + if (!ferror(af->fp)) { return JIM_OK; } @@ -345,13 +380,20 @@ static int JimCheckStreamError(Jim_Interp *interp, AioFile *af) if (feof(af->fp) || errno == EAGAIN || errno == EINTR) { return JIM_OK; } + +#ifdef __MINGW32__ + err = WSAGetLastError(); +#else + err = errno; +#endif + #ifdef ECONNRESET - if (errno == ECONNRESET) { + if (err == ECONNRESET) { return JIM_OK; } #endif #ifdef ECONNABORTED - if (errno != ECONNABORTED) { + if (err != ECONNABORTED) { return JIM_OK; } #endif From 61c0e02750590257b313e8094dfb2cfe69005b71 Mon Sep 17 00:00:00 2001 From: Dima Krasner Date: Thu, 20 Aug 2015 22:13:06 +0300 Subject: [PATCH 4/4] Bug fix - WSAGetLastError() should be used only for socket errors --- jim-aio.c | 48 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/jim-aio.c b/jim-aio.c index a0c86236..e001ccf2 100644 --- a/jim-aio.c +++ b/jim-aio.c @@ -311,19 +311,17 @@ static void JimAioSetError(Jim_Interp *interp, Jim_Obj *name) const char *s; #else char *s; - int alloc = 0; + int err, alloc = 0; - /* try errno (which gets modified by FILE * functions, etc') first, then - * fall back to WSAGetLastError() (which gets modified by socket - * functions, i.e recv()) */ - if (errno != 0) { -#endif - s = strerror(errno); -#ifdef __MINGW32__ - } else { + /* try WSAGetLastError() (which gets modified by socket + * functions, i.e recv()) first, then fall back to errno (which gets + * modified by FILE * functions, etc') */ + err = WSAGetLastError(); + if (err != 0) { + WSASetLastError(0); if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, - WSAGetLastError(), + err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&s, 0, @@ -331,6 +329,10 @@ static void JimAioSetError(Jim_Interp *interp, Jim_Obj *name) return; } alloc = 1; + } else { +#endif + s = strerror(errno); +#ifdef __MINGW32__ } #endif @@ -520,13 +522,22 @@ static int aio_cmd_gets(Jim_Interp *interp, int argc, Jim_Obj *const *argv) while (1) { buf[AIO_BUF_LEN - 1] = '_'; if (fgets(buf, AIO_BUF_LEN, af->fp) == NULL) { -#ifdef __MINGW32__ +#ifndef __MINGW32__ + break; +#else int len = recv(_get_osfhandle(fileno(af->fp)), buf, AIO_BUF_LEN - 1, 0); - if (len <= 0) + if (len == SOCKET_ERROR) { + /* for non-socket streams, we want to use errno to describe the error */ + if (WSAGetLastError() == WSAENOTSOCK) { + WSASetLastError(0); + } break; + } + if (len == 0) { + break; + } + buf[len] = '\0'; -#else - break; #endif } @@ -601,11 +612,18 @@ static int aio_cmd_puts(Jim_Interp *interp, int argc, Jim_Obj *const *argv) /* fwrite() doesn't seem to work with sockets, so we fall back to good ol' send() */ if (errno == 0) { SOCKET sock = _get_osfhandle(fileno(af->fp)); - if (send(sock, wdata, wlen, 0) == (unsigned)wlen) { + int out = send(sock, wdata, wlen, 0); + if (out == wlen) { if (argc == 2 || send(sock, "\n", 1, 0) == 1) { return JIM_OK; } } + if (out == SOCKET_ERROR) { + /* we want to use errno if af is not a socket */ + if (WSAGetLastError() == WSAENOTSOCK) { + WSASetLastError(0); + } + } } #endif JimAioSetError(interp, af->filename);