summaryrefslogtreecommitdiffstats
path: root/win
diff options
context:
space:
mode:
Diffstat (limited to 'win')
-rw-r--r--win/Makefile.in18
-rwxr-xr-xwin/buildall.vc.bat41
-rwxr-xr-xwin/configure16
-rw-r--r--win/configure.in10
-rw-r--r--win/makefile.vc4
-rw-r--r--win/nmakehlp.c19
-rw-r--r--win/rules.vc26
-rw-r--r--win/tclWinDde.c2
-rw-r--r--win/tclWinPort.h1
-rw-r--r--win/tclWinSock.c332
-rw-r--r--win/tclooConfig.sh2
11 files changed, 252 insertions, 219 deletions
diff --git a/win/Makefile.in b/win/Makefile.in
index aa5558b..b616737 100644
--- a/win/Makefile.in
+++ b/win/Makefile.in
@@ -456,8 +456,12 @@ ${TEST_DLL_FILE}: ${TCLTEST_OBJS} ${TCL_STUB_LIB_FILE}
@MAKE_DLL@ ${TCLTEST_OBJS} $(TCL_STUB_LIB_FILE) $(SHLIB_LD_LIBS)
# use pre-built zlib1.dll
-${ZLIB_DLL_FILE}: $(ZLIB_DIR)/win32/${ZLIB_DLL_FILE}
- @$(COPY) $(ZLIB_DIR)/win32/${ZLIB_DLL_FILE} ${ZLIB_DLL_FILE}
+${ZLIB_DLL_FILE}: ${TCL_STUB_LIB_FILE}
+ @if test "@ZLIB_LIBS@set" == "${ZLIB_DIR}/win64/zdll.libset" ; then \
+ $(COPY) $(ZLIB_DIR)/win64/${ZLIB_DLL_FILE} ${ZLIB_DLL_FILE}; \
+ else \
+ $(COPY) $(ZLIB_DIR)/win32/${ZLIB_DLL_FILE} ${ZLIB_DLL_FILE}; \
+ fi;
# Add the object extension to the implicit rules. By default .obj is not
# automatically added.
@@ -643,8 +647,8 @@ install-libraries: libraries install-tzdata install-msgs
do \
$(COPY) "$$j" "$(SCRIPT_INSTALL_DIR)/opt0.4"; \
done;
- @echo "Installing package msgcat 1.4.5 as a Tcl Module";
- @$(COPY) $(ROOT_DIR)/library/msgcat/msgcat.tcl $(SCRIPT_INSTALL_DIR)/../tcl8/8.5/msgcat-1.4.5.tm;
+ @echo "Installing package msgcat 1.5.0 as a Tcl Module";
+ @$(COPY) $(ROOT_DIR)/library/msgcat/msgcat.tcl $(SCRIPT_INSTALL_DIR)/../tcl8/8.5/msgcat-1.5.0.tm;
@echo "Installing package tcltest 2.3.4 as a Tcl Module";
@$(COPY) $(ROOT_DIR)/library/tcltest/tcltest.tcl $(SCRIPT_INSTALL_DIR)/../tcl8/8.5/tcltest-2.3.4.tm;
@echo "Installing package platform 1.0.10 as a Tcl Module";
@@ -697,14 +701,14 @@ test-tcl: binaries $(TCLSH) $(CAT32) $(TEST_DLL_FILE)
TCL_LIBRARY="$(LIBRARY_DIR)"; export TCL_LIBRARY; \
./$(TCLSH) "$(ROOT_DIR_NATIVE)/tests/all.tcl" $(TESTFLAGS) \
-load "package ifneeded Tcltest ${VERSION}@TCL_PATCH_LEVEL@ [list load [file normalize ${TEST_DLL_FILE}] Tcltest]; \
- package ifneeded dde 1.4.0 [list load [file normalize ${DDE_DLL_FILE}] dde]; \
+ package ifneeded dde 1.4.0b2 [list load [file normalize ${DDE_DLL_FILE}] dde]; \
package ifneeded registry 1.3.0 [list load [file normalize ${REG_DLL_FILE}] registry]" | ./$(CAT32)
# Useful target to launch a built tclsh with the proper path,...
runtest: binaries $(TCLSH) $(TEST_DLL_FILE)
@TCL_LIBRARY="$(LIBRARY_DIR)"; export TCL_LIBRARY; \
./$(TCLSH) $(TESTFLAGS) -load "package ifneeded Tcltest ${VERSION}@TCL_PATCH_LEVEL@ [list load [file normalize ${TEST_DLL_FILE}] Tcltest]; \
- package ifneeded dde 1.4.0 [list load [file normalize ${DDE_DLL_FILE}] dde]; \
+ package ifneeded dde 1.4.0b2 [list load [file normalize ${DDE_DLL_FILE}] dde]; \
package ifneeded registry 1.3.0 [list load [file normalize ${REG_DLL_FILE}] registry]" $(SCRIPT)
# This target can be used to run tclsh from the build directory via
@@ -782,7 +786,7 @@ test-packages: tcltest packages
pkg=`basename $$i`; \
if [ -f $(PKG_DIR)/$$pkg/Makefile ]; then \
echo "Testing package '$$pkg'"; \
- ( cd $(PKG_DIR)/$$pkg; $(MAKE) "LD_LIBRARY_PATH=$$builddir:${LD_LIBRARY_PATH}" "TCL_LIBRARY=${TCL_BUILDTIME_LIBRARY}" "TCLLIBPATH=$$builddir/pkgs" test "TCLSH_PROG=$$builddir/tcltest"; ) \
+ ( cd $(PKG_DIR)/$$pkg; $(MAKE) "LD_LIBRARY_PATH=$$builddir:${LD_LIBRARY_PATH}" "TCL_LIBRARY=${TCL_BUILDTIME_LIBRARY}" "TCLLIBPATH=$$builddir/pkgs" test "TCLSH_PROG=$$builddir/${TCLSH}"; ) \
fi; \
fi; \
done; \
diff --git a/win/buildall.vc.bat b/win/buildall.vc.bat
index c33aefd..e4f0a30 100755
--- a/win/buildall.vc.bat
+++ b/win/buildall.vc.bat
@@ -1,4 +1,5 @@
@echo off
+
:: This is an example batchfile for building everything. Please
:: edit this (or make your own) for your needs and wants using
:: the instructions for calling makefile.vc found in makefile.vc
@@ -26,10 +27,11 @@ cd > nul
:: path or have already run vcvars32.bat. Testing these envars proves
:: cl.exe and friends are in your path.
::
-if defined VCINSTALLDIR (goto :startBuilding)
-if defined MSDRVDIR (goto :startBuilding)
-if defined MSVCDIR (goto :startBuilding)
-if defined MSSDK (goto :startBuilding)
+if defined VCINSTALLDIR (goto :startBuilding)
+if defined MSDEVDIR (goto :startBuilding)
+if defined MSVCDIR (goto :startBuilding)
+if defined MSSDK (goto :startBuilding)
+if defined WINDOWSSDKDIR (goto :startBuilding)
:: We need to run the development environment batch script that comes
:: with developer studio (v4,5,6,7,etc...) All have it. This path
@@ -62,42 +64,13 @@ if not %SYMBOLS%.==. set OPTS=symbols
nmake -nologo -f makefile.vc release htmlhelp OPTS=%OPTS% %1
if errorlevel 1 goto error
-:: Build the static core, dlls and shell.
-::
-set OPTS=static
-if not %SYMBOLS%.==. set OPTS=symbols,static
-nmake -nologo -f makefile.vc release OPTS=%OPTS% %1
-if errorlevel 1 goto error
-
-:: Build the special static libraries that use the dynamic runtime.
+:: Build the static core and shell.
::
set OPTS=static,msvcrt
if not %SYMBOLS%.==. set OPTS=symbols,static,msvcrt
-nmake -nologo -f makefile.vc core dlls OPTS=%OPTS% %1
-if errorlevel 1 goto error
-
-:: Build the core and shell for thread support.
-::
-set OPTS=threads
-if not %SYMBOLS%.==. set OPTS=symbols,threads
nmake -nologo -f makefile.vc shell OPTS=%OPTS% %1
if errorlevel 1 goto error
-:: Build a static, thread support core library with a shell.
-::
-set OPTS=static,threads
-if not %SYMBOLS%.==. set OPTS=symbols,static,threads
-nmake -nologo -f makefile.vc shell OPTS=%OPTS% %1
-if errorlevel 1 goto error
-
-:: Build the special static libraries that use the dynamic runtime,
-:: but now with thread support.
-::
-set OPTS=static,msvcrt,threads
-if not %SYMBOLS%.==. set OPTS=symbols,static,msvcrt,threads
-nmake -nologo -f makefile.vc core dlls OPTS=%OPTS% %1
-if errorlevel 1 goto error
-
set OPTS=
set SYMBOLS=
goto end
diff --git a/win/configure b/win/configure
index f5a23fe..521fc51 100755
--- a/win/configure
+++ b/win/configure
@@ -1311,7 +1311,7 @@ SHELL=/bin/sh
TCL_VERSION=8.6
TCL_MAJOR_VERSION=8
TCL_MINOR_VERSION=6
-TCL_PATCH_LEVEL="b2"
+TCL_PATCH_LEVEL="b3"
VER=$TCL_MAJOR_VERSION$TCL_MINOR_VERSION
TCL_DDE_VERSION=1.4
@@ -4344,7 +4344,7 @@ esac
# as we just assume that the platform hasn't got a usable z.lib
#------------------------------------------------------------------------
-if test "$do64bit" = "yes"; then
+if test "$do64bit" = "yes" && test "$GCC" != "yes"; then
tcl_ok=no
@@ -4368,7 +4368,17 @@ if test "$tcl_ok" = "yes"; then
ZLIB_DLL_FILE=\${ZLIB_DLL_FILE}
- ZLIB_LIBS=\${ZLIB_DIR}/win32/zdll.lib
+ if test "$do64bit" = "yes"; then
+
+ ZLIB_LIBS=\${ZLIB_DIR}/win64/zdll.lib
+
+
+else
+
+ ZLIB_LIBS=\${ZLIB_DIR}/win32/zdll.lib
+
+
+fi
else
diff --git a/win/configure.in b/win/configure.in
index d17f815..9145ff3 100644
--- a/win/configure.in
+++ b/win/configure.in
@@ -14,7 +14,7 @@ SHELL=/bin/sh
TCL_VERSION=8.6
TCL_MAJOR_VERSION=8
TCL_MINOR_VERSION=6
-TCL_PATCH_LEVEL="b2"
+TCL_PATCH_LEVEL="b3"
VER=$TCL_MAJOR_VERSION$TCL_MINOR_VERSION
TCL_DDE_VERSION=1.4
@@ -120,7 +120,7 @@ esac
# as we just assume that the platform hasn't got a usable z.lib
#------------------------------------------------------------------------
-AS_IF([test "$do64bit" = "yes"], [
+AS_IF([test "$do64bit" = "yes" && test "$GCC" != "yes"], [
tcl_ok=no
], [
AS_IF([test "${enable_shared+set}" = "set"], [
@@ -132,7 +132,11 @@ AS_IF([test "${enable_shared+set}" = "set"], [
])
AS_IF([test "$tcl_ok" = "yes"], [
AC_SUBST(ZLIB_DLL_FILE,[\${ZLIB_DLL_FILE}])
- AC_SUBST(ZLIB_LIBS,[\${ZLIB_DIR}/win32/zdll.lib])
+ AS_IF([test "$do64bit" = "yes"], [
+ AC_SUBST(ZLIB_LIBS,[\${ZLIB_DIR}/win64/zdll.lib])
+ ], [
+ AC_SUBST(ZLIB_LIBS,[\${ZLIB_DIR}/win32/zdll.lib])
+ ])
], [
AC_SUBST(ZLIB_OBJS,[\${ZLIB_OBJS}])
AC_DEFINE_UNQUOTED(NO_VIZ, 1)
diff --git a/win/makefile.vc b/win/makefile.vc
index 2784140..d097e26 100644
--- a/win/makefile.vc
+++ b/win/makefile.vc
@@ -578,13 +578,13 @@ test-core: setup $(TCLTEST) dlls $(CAT32)
set TCL_LIBRARY=$(ROOT:\=/)/library
!if "$(OS)" == "Windows_NT" || "$(MSVCDIR)" == "IDE"
$(DEBUGGER) $(TCLTEST) "$(ROOT:\=/)/tests/all.tcl" $(TESTFLAGS) -loadfile <<
- package ifneeded dde 1.4.0 [list load "$(TCLDDELIB:\=/)" dde]
+ package ifneeded dde 1.4.0b2 [list load "$(TCLDDELIB:\=/)" dde]
package ifneeded registry 1.3.0 [list load "$(TCLREGLIB:\=/)" registry]
<<
!else
@echo Please wait while the tests are collected...
$(TCLTEST) "$(ROOT:\=/)/tests/all.tcl" $(TESTFLAGS) -loadfile << > tests.log
- package ifneeded dde 1.4.0 "$(TCLDDELIB:\=/)" dde]
+ package ifneeded dde 1.4.0b2 "$(TCLDDELIB:\=/)" dde]
package ifneeded registry 1.3.0 "$(TCLREGLIB:\=/)" registry]
<<
type tests.log | more
diff --git a/win/nmakehlp.c b/win/nmakehlp.c
index 2868857..b1a1517 100644
--- a/win/nmakehlp.c
+++ b/win/nmakehlp.c
@@ -47,7 +47,7 @@ static int CheckForLinkerFeature(const char *option);
static int IsIn(const char *string, const char *substring);
static int SubstituteFile(const char *substs, const char *filename);
static int QualifyPath(const char *path);
-static const char *GetVersionFromFile(const char *filename, const char *match);
+static const char *GetVersionFromFile(const char *filename, const char *match, int numdots);
static DWORD WINAPI ReadFromPipe(LPVOID args);
/* globals */
@@ -153,7 +153,7 @@ main(
&dwWritten, NULL);
return 0;
}
- printf("%s\n", GetVersionFromFile(argv[2], argv[3]));
+ printf("%s\n", GetVersionFromFile(argv[2], argv[3], *(argv[1]+2) - '0'));
return 0;
case 'Q':
if (argc != 3) {
@@ -479,7 +479,8 @@ IsIn(
static const char *
GetVersionFromFile(
const char *filename,
- const char *match)
+ const char *match,
+ int numdots)
{
size_t cbBuffer = 100;
static char szBuffer[100];
@@ -497,9 +498,10 @@ GetVersionFromFile(
p = strstr(szBuffer, match);
if (p != NULL) {
/*
- * Skip to first digit.
+ * Skip to first digit after the match.
*/
+ p += strlen(match);
while (*p && !isdigit(*p)) {
++p;
}
@@ -509,7 +511,8 @@ GetVersionFromFile(
*/
q = p;
- while (*q && (isalnum(*q) || *q == '.')) {
+ while (*q && (strchr("0123456789.ab", *q)) && ((!strchr(".ab", *q)
+ && (!strchr("ab", q[-1])) || --numdots))) {
++q;
}
@@ -628,11 +631,11 @@ SubstituteFile(
}
}
#endif
-
+
/*
* Run the substitutions over each line of the input
*/
-
+
while (fgets(szBuffer, cbBuffer, fp) != NULL) {
list_item_t *p = NULL;
for (p = substPtr; p != NULL; p = p->nextPtr) {
@@ -652,7 +655,7 @@ SubstituteFile(
}
printf(szBuffer);
}
-
+
list_free(&substPtr);
}
fclose(fp);
diff --git a/win/rules.vc b/win/rules.vc
index f09e2ea..1513198 100644
--- a/win/rules.vc
+++ b/win/rules.vc
@@ -218,7 +218,7 @@ DEBUG = 0
SYMBOLS = 0
PROFILE = 0
PGO = 0
-MSVCRT = 0
+MSVCRT = 1
LOIMPACT = 0
TCL_USE_STATIC_PACKAGES = 0
USE_THREAD_ALLOC = 1
@@ -234,9 +234,13 @@ STATIC_BUILD = 0
!message *** Doing msvcrt
MSVCRT = 1
!else
+!if !$(STATIC_BUILD)
+MSVCRT = 1
+!else
MSVCRT = 0
!endif
-!if [nmakehlp -f $(OPTS) "staticpkg"]
+!endif
+!if [nmakehlp -f $(OPTS) "staticpkg"] && $(STATIC_BUILD)
!message *** Doing staticpkg
TCL_USE_STATIC_PACKAGES = 1
!else
@@ -245,6 +249,7 @@ TCL_USE_STATIC_PACKAGES = 0
!if [nmakehlp -f $(OPTS) "nothreads"]
!message *** Compile explicitly for non-threaded tcl
TCL_THREADS = 0
+USE_THREAD_ALLOC= 0
!else
TCL_THREADS = 1
USE_THREAD_ALLOC= 1
@@ -298,15 +303,6 @@ UNCHECKED = 0
!endif
!endif
-
-!if !$(STATIC_BUILD)
-# Make sure we don't build overly fat DLLs.
-MSVCRT = 1
-# We shouldn't statically put the extensions inside the shell when dynamic.
-TCL_USE_STATIC_PACKAGES = 0
-!endif
-
-
#----------------------------------------------------------
# Figure-out how to name our intermediate and output directories.
# We wouldn't want different builds to use the same .obj files
@@ -348,10 +344,8 @@ TMP_DIRFULL = .\$(BUILDDIRTOP)\$(PROJECT)_ThreadedDynamicStaticX
TMP_DIRFULL = $(TMP_DIRFULL:Static=)
SUFX = $(SUFX:s=)
EXT = dll
-!if $(MSVCRT)
TMP_DIRFULL = $(TMP_DIRFULL:X=)
SUFX = $(SUFX:x=)
-!endif
!else
TMP_DIRFULL = $(TMP_DIRFULL:Dynamic=)
EXT = lib
@@ -583,12 +577,6 @@ Failed to find tcl.h. The TCLDIR macro does not appear correct.
TCL_VERSION = $(TCL_MAJOR_VERSION)$(TCL_MINOR_VERSION)
-!if $(TCL_VERSION) < 81
-TCL_DOES_STUBS = 0
-!else
-TCL_DOES_STUBS = 1
-!endif
-
!if $(TCLINSTALL)
TCLSH = "$(_TCLDIR)\bin\tclsh$(TCL_VERSION)$(SUFX).exe"
!if !exist($(TCLSH)) && $(TCL_THREADS)
diff --git a/win/tclWinDde.c b/win/tclWinDde.c
index d0600e6..f5c0484 100644
--- a/win/tclWinDde.c
+++ b/win/tclWinDde.c
@@ -96,7 +96,7 @@ static DWORD ddeInstance; /* The application instance handle given to us
* by DdeInitialize. */
static int ddeIsServer = 0;
-#define TCL_DDE_VERSION "1.4.0"
+#define TCL_DDE_VERSION "1.4.0b2"
#define TCL_DDE_PACKAGE_NAME "dde"
#define TCL_DDE_SERVICE_NAME TEXT("TclEval")
#define TCL_DDE_EXECUTE_RESULT TEXT("$TCLEVAL$EXECUTE$RESULT")
diff --git a/win/tclWinPort.h b/win/tclWinPort.h
index c6ac2b7..48f7894 100644
--- a/win/tclWinPort.h
+++ b/win/tclWinPort.h
@@ -538,7 +538,6 @@ typedef DWORD_PTR * PDWORD_PTR;
#define getservbyname TclWinGetServByName
#define getsockopt TclWinGetSockOpt
-#define ntohs TclWinNToHS
#define setsockopt TclWinSetSockOpt
/* This type is not defined in the Windows headers */
#define socklen_t int
diff --git a/win/tclWinSock.c b/win/tclWinSock.c
index 7894920..1a74354 100644
--- a/win/tclWinSock.c
+++ b/win/tclWinSock.c
@@ -72,7 +72,6 @@
#undef getservbyname
#undef getsockopt
-#undef ntohs
#undef setsockopt
/*
@@ -163,7 +162,7 @@ struct SocketInfo {
* socket event occurs.
*/
-typedef struct SocketEvent {
+typedef struct {
Tcl_Event header; /* Information that is standard for all
* events. */
SOCKET socket; /* Socket descriptor that is ready. Used to
@@ -191,7 +190,7 @@ typedef struct SocketEvent {
#define SOCKET_PENDING (1<<3) /* A message has been sent for this
* socket */
-typedef struct ThreadSpecificData {
+typedef struct {
HWND hwnd; /* Handle to window for socket messages. */
HANDLE socketThread; /* Thread handling the window */
Tcl_ThreadId threadId; /* Parent thread. */
@@ -220,7 +219,7 @@ static void SocketExitHandler(ClientData clientData);
static LRESULT CALLBACK SocketProc(HWND hwnd, UINT message, WPARAM wParam,
LPARAM lParam);
static int SocketsEnabled(void);
-static void TcpAccept(TcpFdList *fds);
+static void TcpAccept(TcpFdList *fds, SOCKET newSocket, address addr);
static int WaitForSocketEvent(SocketInfo *infoPtr, int events,
int *errorCodePtr);
static DWORD WINAPI SocketThread(LPVOID arg);
@@ -692,6 +691,9 @@ SocketEventProc(
int mask = 0, events;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
TcpFdList *fds;
+ SOCKET newSocket;
+ address addr;
+ int len;
if (!(flags & TCL_FILE_EVENTS)) {
return 0;
@@ -708,13 +710,13 @@ SocketEventProc(
break;
}
}
- SetEvent(tsdPtr->socketListLock);
/*
* Discard events that have gone stale.
*/
if (!infoPtr) {
+ SetEvent(tsdPtr->socketListLock);
return 1;
}
@@ -726,11 +728,65 @@ SocketEventProc(
if (infoPtr->readyEvents & FD_ACCEPT) {
for (fds = infoPtr->sockets; fds != NULL; fds = fds->next) {
- TcpAccept(fds);
+
+ /*
+ * Accept the incoming connection request.
+ */
+ len = sizeof(address);
+
+ newSocket = accept(fds->fd, &(addr.sa), &len);
+
+ /* On Tcl server sockets with multiple OS fds we loop over the fds trying
+ * an accept() on each, so we expect INVALID_SOCKET. There are also other
+ * network stack conditions that can result in FD_ACCEPT but a subsequent
+ * failure on accept() by the time we get around to it.
+ * Access to sockets (acceptEventCount, readyEvents) in socketList
+ * is still protected by the lock (prevents reintroduction of
+ * SF Tcl Bug 3056775.
+ */
+
+ if (newSocket == INVALID_SOCKET) {
+ /* int err = WSAGetLastError(); */
+ continue;
+ }
+
+ /*
+ * It is possible that more than one FD_ACCEPT has been sent, so an extra
+ * count must be kept. Decrement the count, and reset the readyEvent bit
+ * if the count is no longer > 0.
+ */
+ infoPtr->acceptEventCount--;
+
+ if (infoPtr->acceptEventCount <= 0) {
+ infoPtr->readyEvents &= ~(FD_ACCEPT);
+ }
+
+ SetEvent(tsdPtr->socketListLock);
+
+ /* Caution: TcpAccept() has the side-effect of evaluating the server
+ * accept script (via AcceptCallbackProc() in tclIOCmd.c), which can
+ * close the server socket and invalidate infoPtr and fds.
+ * If TcpAccept() accepts a socket we must return immediately and let
+ * SocketCheckProc queue additional FD_ACCEPT events.
+ */
+ TcpAccept(fds, newSocket, addr);
+ return 1;
}
+
+ /* Loop terminated with no sockets accepted; clear the ready mask so
+ * we can detect the next connection request. Note that connection
+ * requests are level triggered, so if there is a request already
+ * pending, a new event will be generated.
+ */
+ infoPtr->acceptEventCount = 0;
+ infoPtr->readyEvents &= ~(FD_ACCEPT);
+
+ SetEvent(tsdPtr->socketListLock);
return 1;
}
+ SetEvent(tsdPtr->socketListLock);
+
/*
* Mask off unwanted events and compute the read/write mask so we can
* notify the channel.
@@ -872,9 +928,15 @@ TcpCloseProc(
* background.
*/
- if (closesocket(infoPtr->sockets->fd) == SOCKET_ERROR) {
- TclWinConvertError((DWORD) WSAGetLastError());
- errorCode = Tcl_GetErrno();
+ while ( infoPtr->sockets != NULL ) {
+ TcpFdList *thisfd = infoPtr->sockets;
+ infoPtr->sockets = thisfd->next;
+
+ if (closesocket(thisfd->fd) == SOCKET_ERROR) {
+ TclWinConvertError((DWORD) WSAGetLastError());
+ errorCode = Tcl_GetErrno();
+ }
+ ckfree(thisfd);
}
}
@@ -934,6 +996,8 @@ TcpClose2Proc(
return TCL_ERROR;
}
+ /* single fd operation: Tcl_OpenTcpServer() does not set TCL_READABLE or
+ * TCL_WRITABLE so this should never be called for a server socket. */
if (shutdown(infoPtr->sockets->fd, sd) == SOCKET_ERROR) {
TclWinConvertError((DWORD) WSAGetLastError());
errorCode = Tcl_GetErrno();
@@ -945,6 +1009,51 @@ TcpClose2Proc(
/*
*----------------------------------------------------------------------
*
+ * AddSocketInfoFd --
+ *
+ * This function adds a SOCKET file descriptor to the 'sockets' linked
+ * list of a SocketInfo structure.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None, except for allocation of memory.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+AddSocketInfoFd(
+ SocketInfo *infoPtr,
+ SOCKET socket)
+{
+ TcpFdList *fds = infoPtr->sockets;
+
+ if ( fds == NULL ) {
+ /* Add the first FD */
+ infoPtr->sockets = ckalloc(sizeof(TcpFdList));
+ fds = infoPtr->sockets;
+ } else {
+ /* Find end of list and append FD */
+ while ( fds->next != NULL ) {
+ fds = fds->next;
+ }
+
+ fds->next = ckalloc(sizeof(TcpFdList));
+ fds = fds->next;
+ }
+
+ /* Populate new FD */
+ fds->fd = socket;
+ fds->infoPtr = infoPtr;
+ fds->next = NULL;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
* NewSocketInfo --
*
* This function allocates and initializes a new SocketInfo structure.
@@ -963,14 +1072,10 @@ NewSocketInfo(
SOCKET socket)
{
SocketInfo *infoPtr = ckalloc(sizeof(SocketInfo));
- TcpFdList *fds = ckalloc(sizeof(TcpFdList));
- fds->fd = socket;
- fds->next = NULL;
- fds->infoPtr = infoPtr;
/* ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); */
infoPtr->channel = 0;
- infoPtr->sockets = fds;
+ infoPtr->sockets = NULL;
infoPtr->flags = 0;
infoPtr->watchEvents = 0;
infoPtr->readyEvents = 0;
@@ -988,6 +1093,8 @@ NewSocketInfo(
infoPtr->nextPtr = NULL;
+ AddSocketInfoFd(infoPtr, socket);
+
return infoPtr;
}
@@ -1057,7 +1164,6 @@ CreateSocket(
}
if (server) {
- TcpFdList *fds = NULL, *newfds;
for (addrPtr = addrlist; addrPtr != NULL; addrPtr = addrPtr->ai_next) {
sock = socket(addrPtr->ai_family, SOCK_STREAM, 0);
@@ -1140,7 +1246,6 @@ CreateSocket(
*/
infoPtr = NewSocketInfo(sock);
- fds = infoPtr->sockets;
/*
* Set up the select mask for connection request events.
@@ -1150,13 +1255,7 @@ CreateSocket(
infoPtr->watchEvents |= FD_ACCEPT;
} else {
- newfds = ckalloc(sizeof(TcpFdList));
- memset(newfds, (int) 0, sizeof(TcpFdList));
- newfds->fd = sock;
- newfds->infoPtr = infoPtr;
- newfds->next = NULL;
- fds->next = newfds;
- fds = newfds;
+ AddSocketInfoFd( infoPtr, sock );
}
}
} else {
@@ -1534,8 +1633,9 @@ Tcl_OpenTcpServer(
*
* TcpAccept --
*
- * Accept a TCP socket connection. This is called by SocketEventProc and
- * it in turns calls the registered accept function.
+ * Creates a channel for a newly accepted socket connection. This is
+ * called by SocketEventProc and it in turns calls the registered
+ * accept function.
*
* Results:
* None.
@@ -1548,60 +1648,18 @@ Tcl_OpenTcpServer(
static void
TcpAccept(
- TcpFdList *fds) /* Socket to accept. */
+ TcpFdList *fds, /* Server socket that accepted newSocket. */
+ SOCKET newSocket, /* Newly accepted socket. */
+ address addr) /* Address of new socket. */
{
- SOCKET newSocket;
SocketInfo *newInfoPtr;
SocketInfo *infoPtr = fds->infoPtr;
- SOCKADDR_IN addr;
- int len;
+ int len = sizeof(addr);
char channelName[16 + TCL_INTEGER_SPACE];
+ char host[NI_MAXHOST], port[NI_MAXSERV];
ThreadSpecificData *tsdPtr = TclThreadDataKeyGet(&dataKey);
/*
- * Accept the incoming connection request.
- */
-
- len = sizeof(SOCKADDR_IN);
-
- newSocket = accept(fds->fd, (SOCKADDR *) &addr, &len);
-
- /*
- * Protect access to sockets (acceptEventCount, readyEvents) in socketList
- * by the lock. Fix for SF Tcl Bug 3056775.
- */
-
- WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
-
- /*
- * Clear the ready mask so we can detect the next connection request. Note
- * that connection requests are level triggered, so if there is a request
- * already pending, a new event will be generated.
- */
-
- if (newSocket == INVALID_SOCKET) {
- infoPtr->acceptEventCount = 0;
- infoPtr->readyEvents &= ~(FD_ACCEPT);
-
- SetEvent(tsdPtr->socketListLock);
- return;
- }
-
- /*
- * It is possible that more than one FD_ACCEPT has been sent, so an extra
- * count must be kept. Decrement the count, and reset the readyEvent bit
- * if the count is no longer > 0.
- */
-
- infoPtr->acceptEventCount--;
-
- if (infoPtr->acceptEventCount <= 0) {
- infoPtr->readyEvents &= ~(FD_ACCEPT);
- }
-
- SetEvent(tsdPtr->socketListLock);
-
- /*
* Win-NT has a misfeature that sockets are inherited in child processes
* by default. Turn off the inherit bit.
*/
@@ -1641,8 +1699,10 @@ TcpAccept(
*/
if (infoPtr->acceptProc != NULL) {
+ getnameinfo(&(addr.sa), len, host, sizeof(host), port, sizeof(port),
+ NI_NUMERICHOST|NI_NUMERICSERV);
infoPtr->acceptProc(infoPtr->acceptProcData, newInfoPtr->channel,
- inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
+ host, atoi(port));
}
}
@@ -1717,6 +1777,7 @@ TcpInputProc(
while (1) {
SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
(WPARAM) UNSELECT, (LPARAM) infoPtr);
+ /* single fd operation: this proc is only called for a connected socket. */
bytesRead = recv(infoPtr->sockets->fd, buf, toRead, 0);
infoPtr->readyEvents &= ~(FD_READ);
@@ -1837,6 +1898,7 @@ TcpOutputProc(
SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
(WPARAM) UNSELECT, (LPARAM) infoPtr);
+ /* single fd operation: this proc is only called for a connected socket. */
bytesWritten = send(infoPtr->sockets->fd, buf, toWrite, 0);
if (bytesWritten != SOCKET_ERROR) {
/*
@@ -1933,6 +1995,7 @@ TcpSetOptionProc(
}
#ifdef TCL_FEATURE_KEEPALIVE_NAGLE
+ #error "TCL_FEATURE_KEEPALIVE_NAGLE not reviewed for whether to treat infoPtr->sockets as single fd or list"
sock = infoPtr->sockets->fd;
if (!strcasecmp(optionName, "-keepalive")) {
@@ -2400,6 +2463,7 @@ SocketProc(
int event, error;
SOCKET socket;
SocketInfo *infoPtr;
+ TcpFdList *fds = NULL;
ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
#ifdef _WIN64
GetWindowLongPtr(hwnd, GWLP_USERDATA);
@@ -2444,58 +2508,60 @@ SocketProc(
WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
for (infoPtr = tsdPtr->socketList; infoPtr != NULL;
infoPtr = infoPtr->nextPtr) {
- if (infoPtr->sockets->fd == socket) {
- /*
- * Update the socket state.
- *
- * A count of FD_ACCEPTS is stored, so if an FD_CLOSE event
- * happens, then clear the FD_ACCEPT count. Otherwise,
- * increment the count if the current event is an FD_ACCEPT.
- */
-
- if (event & FD_CLOSE) {
- infoPtr->acceptEventCount = 0;
- infoPtr->readyEvents &= ~(FD_WRITE|FD_ACCEPT);
- } else if (event & FD_ACCEPT) {
- infoPtr->acceptEventCount++;
- }
-
- if (event & FD_CONNECT) {
+ for (fds = infoPtr->sockets; fds != NULL; fds = fds->next) {
+ if (fds->fd == socket) {
/*
- * The socket is now connected, clear the async connect
- * flag.
+ * Update the socket state.
+ *
+ * A count of FD_ACCEPTS is stored, so if an FD_CLOSE event
+ * happens, then clear the FD_ACCEPT count. Otherwise,
+ * increment the count if the current event is an FD_ACCEPT.
*/
- infoPtr->flags &= ~(SOCKET_ASYNC_CONNECT);
+ if (event & FD_CLOSE) {
+ infoPtr->acceptEventCount = 0;
+ infoPtr->readyEvents &= ~(FD_WRITE|FD_ACCEPT);
+ } else if (event & FD_ACCEPT) {
+ infoPtr->acceptEventCount++;
+ }
+
+ if (event & FD_CONNECT) {
+ /*
+ * The socket is now connected, clear the async connect
+ * flag.
+ */
- /*
- * Remember any error that occurred so we can report
- * connection failures.
- */
+ infoPtr->flags &= ~(SOCKET_ASYNC_CONNECT);
+
+ /*
+ * Remember any error that occurred so we can report
+ * connection failures.
+ */
- if (error != ERROR_SUCCESS) {
- TclWinConvertError((DWORD) error);
- infoPtr->lastError = Tcl_GetErrno();
+ if (error != ERROR_SUCCESS) {
+ TclWinConvertError((DWORD) error);
+ infoPtr->lastError = Tcl_GetErrno();
+ }
}
- }
- if (infoPtr->flags & SOCKET_ASYNC_CONNECT) {
- infoPtr->flags &= ~(SOCKET_ASYNC_CONNECT);
- if (error != ERROR_SUCCESS) {
- TclWinConvertError((DWORD) error);
- infoPtr->lastError = Tcl_GetErrno();
+ if (infoPtr->flags & SOCKET_ASYNC_CONNECT) {
+ infoPtr->flags &= ~(SOCKET_ASYNC_CONNECT);
+ if (error != ERROR_SUCCESS) {
+ TclWinConvertError((DWORD) error);
+ infoPtr->lastError = Tcl_GetErrno();
+ }
+ infoPtr->readyEvents |= FD_WRITE;
}
- infoPtr->readyEvents |= FD_WRITE;
- }
- infoPtr->readyEvents |= event;
+ infoPtr->readyEvents |= event;
- /*
- * Wake up the Main Thread.
- */
+ /*
+ * Wake up the Main Thread.
+ */
- SetEvent(tsdPtr->readyEvent);
- Tcl_ThreadAlert(tsdPtr->threadId);
- break;
+ SetEvent(tsdPtr->readyEvent);
+ Tcl_ThreadAlert(tsdPtr->threadId);
+ break;
+ }
}
}
SetEvent(tsdPtr->socketListLock);
@@ -2503,15 +2569,18 @@ SocketProc(
case SOCKET_SELECT:
infoPtr = (SocketInfo *) lParam;
- if (wParam == SELECT) {
- WSAAsyncSelect(infoPtr->sockets->fd, hwnd,
- SOCKET_MESSAGE, infoPtr->selectEvents);
- } else {
- /*
- * Clear the selection mask
- */
+ for (fds = infoPtr->sockets; fds != NULL; fds = fds->next) {
+ infoPtr = (SocketInfo *) lParam;
+ if (wParam == SELECT) {
+ WSAAsyncSelect(fds->fd, hwnd,
+ SOCKET_MESSAGE, infoPtr->selectEvents);
+ } else {
+ /*
+ * Clear the selection mask
+ */
- WSAAsyncSelect(infoPtr->sockets->fd, hwnd, 0, 0);
+ WSAAsyncSelect(fds->fd, hwnd, 0, 0);
+ }
}
break;
@@ -2666,23 +2735,6 @@ TclWinSetSockOpt(
return setsockopt(s, level, optname, optval, optlen);
}
-unsigned short
-TclWinNToHS(
- unsigned short netshort)
-{
- /*
- * Check that WinSock is initialized; do not call it if not, to prevent
- * system crashes. This can happen at exit time if the exit handler for
- * WinSock ran before other exit handlers that want to use sockets.
- */
-
- if (!SocketsEnabled()) {
- return (unsigned short) -1;
- }
-
- return ntohs(netshort);
-}
-
char *
TclpInetNtoa(
struct in_addr addr)
diff --git a/win/tclooConfig.sh b/win/tclooConfig.sh
index 68de106..dce540a 100644
--- a/win/tclooConfig.sh
+++ b/win/tclooConfig.sh
@@ -16,4 +16,4 @@ TCLOO_STUB_LIB_SPEC=""
TCLOO_INCLUDE_SPEC=""
TCLOO_PRIVATE_INCLUDE_SPEC=""
TCLOO_CFLAGS=-DUSE_TCLOO_STUBS
-TCLOO_VERSION=0.6.3
+TCLOO_VERSION=0.7