diff options
Diffstat (limited to 'win')
-rw-r--r-- | win/Makefile.in | 18 | ||||
-rwxr-xr-x | win/buildall.vc.bat | 41 | ||||
-rwxr-xr-x | win/configure | 16 | ||||
-rw-r--r-- | win/configure.in | 10 | ||||
-rw-r--r-- | win/makefile.vc | 4 | ||||
-rw-r--r-- | win/nmakehlp.c | 19 | ||||
-rw-r--r-- | win/rules.vc | 26 | ||||
-rw-r--r-- | win/tclWinDde.c | 2 | ||||
-rw-r--r-- | win/tclWinPort.h | 1 | ||||
-rw-r--r-- | win/tclWinSock.c | 332 | ||||
-rw-r--r-- | win/tclooConfig.sh | 2 |
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 |