From: Pat Thoyts Date: Thu, 11 Nov 2004 23:47:11 +0000 (+0000) Subject: Tidied up and made a public release. X-Git-Tag: tclresolver-0-4-0 X-Git-Url: https://privyetmir.co.uk/gitweb.cgi?a=commitdiff_plain;h=f69b6f7ecc7fa45d8ae2050fd85706a54cb04cfe;p=tclresolver Tidied up and made a public release. --- diff --git a/ChangeLog b/ChangeLog index d832364..8f105bc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2004-11-11 Pat Thoyts + + ==== TAG tclresolver-0-4-0 ==== + + * tclresolver3.c: Renamed to tclresolver. This is the thread + version. + * tclresolver2.c, resolvchk.c: Removed. + 2004-08-26 Pat Thoyts * all: Initial checkin diff --git a/Makefile b/Makefile index 6df5a7d..b49d965 100644 --- a/Makefile +++ b/Makefile @@ -8,23 +8,13 @@ DEFS =-DUSE_TCL_STUBS INC =-Ic:\opt\tcl\include LIBS =c:\opt\tcl\lib\tclstub84.lib ws2_32.lib -all: resolver.exe resolvchk.exe tclresolver.dll tclresolver2.dll tclresolver3.dll +all: resolver.exe tclresolver.dll resolver.exe: resolver.c $(CC) $(CFLAGS) -o $@ $** -resolvchk.exe: resolvchk.c - $(CC) $(CFLAGS) -o $@ $** - tclresolver.dll: tclresolver.obj $(LD) $(LDFLAGS) -out:$@ $(LIBS) $** - -tclresolver2.dll: tclresolver2.obj - $(LD) $(LDFLAGS) -out:$@ $(LIBS) $** - -tclresolver3.dll: tclresolver3.obj - $(LD) $(LDFLAGS) -out:$@ $(LIBS) $** - .c.obj:: $(CC) $(CFLAGS) $(DEFS) $(INC) -c @<< $< @@ -32,18 +22,9 @@ $< clean: @if exist tclresolver.obj del tclresolver.obj - @if exist tclresolver2.obj del tclresolver2.obj - @if exist tclresolver3.obj del tclresolver3.obj realclean: clean @if exist tclresolver.dll del tclresolver.dll @if exist tclresolver.exp del tclresolver.exp @if exist tclresolver.lib del tclresolver.lib - @if exist tclresolver2.dll del tclresolver2.dll - @if exist tclresolver2.exp del tclresolver2.exp - @if exist tclresolver2.lib del tclresolver2.lib - @if exist tclresolver3.dll del tclresolver3.dll - @if exist tclresolver3.exp del tclresolver3.exp - @if exist tclresolver3.lib del tclresolver3.lib @if exist resolver.exe del resolver.exe - @if exist resolvchk.exe del resolvchk.exe diff --git a/demo/demo.tcl b/demo/demo.tcl index 57b6093..74c4c08 100644 --- a/demo/demo.tcl +++ b/demo/demo.tcl @@ -1,5 +1,5 @@ -if {[file exists tclresolver3.dll]} { - load tclresolver3.dll Tclresolver +if {[file exists tclresolver.dll]} { + load tclresolver.dll Tclresolver } else { package require Tclresolver } diff --git a/pkgIndex.tcl b/pkgIndex.tcl new file mode 100644 index 0000000..8ed4e52 --- /dev/null +++ b/pkgIndex.tcl @@ -0,0 +1,3 @@ +# pkgIndex.tcl - Copyright (C) 2004 Pat Thoyts +# +package ifneeded Tclresolver 0.4.0 [list load [file join $dir tclresolver.dll]] diff --git a/resolvchk.c b/resolvchk.c deleted file mode 100644 index ce8db7e..0000000 --- a/resolvchk.c +++ /dev/null @@ -1,233 +0,0 @@ -#define WIN32_LEAN_AND_MEAN -#include -#include -#include -#include - -#define BUFSIZE 4096 - -typedef struct { - HANDLE hReady; - HANDLE hDone; - HANDLE hIn; - HANDLE hOut; - LPBYTE pData; - BOOL bRunning; -} LookupInfo; - -static LPCTSTR LookupHostname(LookupInfo * pLookupInfo, LPCTSTR szHostname); -static DWORD WINAPI Reader(LPVOID clientData); -static BOOL CreateChildProcess(HANDLE hChildStdoutWr, HANDLE hChildStdinRd); -static void ErrorExit(LPTSTR); -static void Win32Error(FILE *fp, LPCTSTR szMessage, HRESULT hr); - -DWORD -_tmain(int argc, LPCTSTR argv[]) -{ - HANDLE hChildStdinWr, hChildStdinWrDup, hChildStdoutRd, hChildStdoutRdDup; - HANDLE hChildStdinRd, hChildStdoutWr; - LookupInfo lookupinfo; - HANDLE hReaderThread = INVALID_HANDLE_VALUE; - DWORD idReaderThread = 0; - SECURITY_ATTRIBUTES saAttr; - BOOL fSuccess; - LPCTSTR szAddress; - int n; - - if (argc < 2) { - ErrorExit(_T("usage: resolvchk hostname ?hostname ...?")); - } - - // Set the bInheritHandle flag so pipe handles are inherited. - saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); - saAttr.bInheritHandle = TRUE; - saAttr.lpSecurityDescriptor = NULL; - - // Create a pipe for the child process's STDOUT. - if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) - ErrorExit("Stdout pipe creation failed\n"); - - // Create noninheritable read handle and close the inheritable read - // handle. - fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd, - GetCurrentProcess(), &hChildStdoutRdDup, - 0, FALSE, - DUPLICATE_SAME_ACCESS); - if( !fSuccess ) - ErrorExit("DuplicateHandle failed"); - CloseHandle(hChildStdoutRd); - - // Create a pipe for the child process's STDIN. - if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) - ErrorExit("Stdin pipe creation failed\n"); - - // Duplicate the write handle to the pipe so it is not inherited. - fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr, - GetCurrentProcess(), &hChildStdinWrDup, - 0, FALSE, // not inherited - DUPLICATE_SAME_ACCESS); - if (! fSuccess) - ErrorExit("DuplicateHandle failed"); - - CloseHandle(hChildStdinWr); - - // Create an event for lookup synch. - lookupinfo.hReady = CreateEvent(NULL, FALSE, FALSE, NULL); - lookupinfo.hDone = CreateEvent(NULL, FALSE, FALSE, NULL); - lookupinfo.hIn = hChildStdoutRdDup; - lookupinfo.hOut = hChildStdinWrDup; - lookupinfo.bRunning = TRUE; - lookupinfo.pData = (LPBYTE)malloc(BUFSIZE); - - // Create reader thread. - hReaderThread = CreateThread(NULL, 0, Reader, &lookupinfo, - 0, &idReaderThread); - - // Now create the child process. - fSuccess = CreateChildProcess(hChildStdoutWr, hChildStdinRd); - if (! fSuccess) - ErrorExit("Create process failed"); - - // Perform the address lookup. - for (n = 1; n < argc; n++) { - szAddress = LookupHostname(&lookupinfo, argv[n]); - _ftprintf(stdout, _T("'%s'\n"), szAddress); - } - - lookupinfo.bRunning = FALSE; - free((LPBYTE)lookupinfo.pData); - - // Close the pipe handle so the child process stops reading and exits. - if (! CloseHandle(hChildStdinWrDup)) - ErrorExit("Close pipe failed"); - if (!CloseHandle(hChildStdoutWr)) - ErrorExit("CloseHandle failed"); - - return 0; -} - -static LPCTSTR -LookupHostname(LookupInfo *pLookupInfo, LPCTSTR szHostname) -{ - DWORD dwWrote; - BOOL br; - - ZeroMemory(pLookupInfo->pData, BUFSIZE); - lstrcpy((LPTSTR)pLookupInfo->pData, szHostname); - lstrcat((LPTSTR)pLookupInfo->pData, _T("\n")); - br = WriteFile(pLookupInfo->hOut, pLookupInfo->pData, - lstrlen((LPTSTR)pLookupInfo->pData) * sizeof(TCHAR), - &dwWrote, NULL); - if (br) - br = FlushFileBuffers(pLookupInfo->hOut); - if (br) { - ZeroMemory(pLookupInfo->pData, BUFSIZE); - SetEvent(pLookupInfo->hReady); - WaitForSingleObject(pLookupInfo->hDone, INFINITE); - } - if (!br) { - Win32Error(stderr, _T("lookup hostname"), GetLastError()); - } - return (LPCTSTR)pLookupInfo->pData; -} - -static DWORD WINAPI -Reader(LPVOID clientData) -{ - LookupInfo *pLookupInfo = (LookupInfo *)clientData; - DWORD dwErr = 0, dwRead = 0; - BOOL br; - - while (pLookupInfo->bRunning) { - dwErr = WaitForSingleObject(pLookupInfo->hReady, 500); - if (dwErr == WAIT_OBJECT_0) { - br = ReadFile(pLookupInfo->hIn, pLookupInfo->pData, - BUFSIZE, &dwRead, NULL); - - if (dwRead > 0) { - LPTSTR p = (LPTSTR)pLookupInfo->pData; - for (p = p + lstrlen(p) - 1; - p > pLookupInfo->pData && _istspace(*p); - p--) - ; - *++p = 0; - } - SetEvent(pLookupInfo->hDone); - } else { - Win32Error(stderr, _T("reader wait"), dwErr); - } - } - return 0; -} - -static BOOL -CreateChildProcess(HANDLE hChildStdoutWr, HANDLE hChildStdinRd) -{ - PROCESS_INFORMATION piProcInfo; - STARTUPINFO siStartInfo; - BOOL bFuncRetn = FALSE; - - // Set up members of the PROCESS_INFORMATION structure. - ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) ); - - // Set up members of the STARTUPINFO structure. - ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) ); - siStartInfo.cb = sizeof(STARTUPINFO); - siStartInfo.hStdError = hChildStdoutWr; - siStartInfo.hStdOutput = hChildStdoutWr; - siStartInfo.hStdInput = hChildStdinRd; - siStartInfo.dwFlags |= STARTF_USESTDHANDLES; - - // Create the child process. - bFuncRetn = CreateProcess(NULL, - "resolver", // command line - NULL, // process security attributes - NULL, // primary thread security attributes - TRUE, // handles are inherited - 0, // creation flags - NULL, // use parent's environment - NULL, // use parent's current directory - &siStartInfo, // STARTUPINFO pointer - &piProcInfo); // receives PROCESS_INFORMATION - - if (bFuncRetn == 0) { - ErrorExit("CreateProcess failed"); - return FALSE; - } else { - CloseHandle(piProcInfo.hProcess); - CloseHandle(piProcInfo.hThread); - return bFuncRetn; - } -} - -static void -ErrorExit (LPTSTR lpszMessage) -{ - _ftprintf(stderr, _T("%s\n"), lpszMessage); - ExitProcess(0); -} - -static void -Win32Error(FILE *fp, LPCTSTR szMessage, HRESULT hr) -{ - LPTSTR lpBuffer = NULL; - DWORD dwLen = 0; - - dwLen = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER - | FORMAT_MESSAGE_FROM_SYSTEM, - NULL, (DWORD)hr, LANG_NEUTRAL, - (LPTSTR)&lpBuffer, 0, NULL); - if (dwLen < 1) { - dwLen = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER - | FORMAT_MESSAGE_FROM_STRING - | FORMAT_MESSAGE_ARGUMENT_ARRAY, - _T("code 0x%1!08X!%n"), 0, LANG_NEUTRAL, - (LPTSTR)&lpBuffer, 0, (va_list *)&hr); - } - _ftprintf(fp, _T("%s"), szMessage); - if (dwLen > 0) { - _ftprintf(fp, _T(": ")); - _ftprintf(fp, lpBuffer); - } - LocalFree((HLOCAL)lpBuffer); -} diff --git a/tclresolver2.c b/tclresolver2.c deleted file mode 100644 index 6684408..0000000 --- a/tclresolver2.c +++ /dev/null @@ -1,319 +0,0 @@ -/* tclresolver.c - Copyright (C) 2004 Pat Thoyts - * - * - * - * $Id$ - */ - -#define WIN32_LEAN_AND_MEAN -#include -#include -#include -#include - -#include - -#if _MSC_VER >= 1000 -#pragma comment(lib, "ws2_32") -#endif - -#define BUFSIZE 4096 -#undef TCL_STORAGE_CLASS -#define TCL_STORAGE_CLASS DLLEXPORT - -static const char ASSOC_KEY[] = "tclresolver_key"; - -EXTERN int Tclresolver_Init(Tcl_Interp *interp); -EXTERN int Tclresolver_Unload(Tcl_Interp *interp); -EXTERN int TclGetHostByName(LPSOCKADDR_IN saddrPtr, - const char *hostname, int port); - -typedef struct { - HANDLE hReader; - DWORD idReader; - HANDLE hReady; - HANDLE hDone; - LPBYTE pData; - BOOL bRunning; - Tcl_ThreadId tclid; - Tcl_Command command; -} LOOKUPINFO, *LPLOOKUPINFO; - -typedef struct { - Tcl_Event header; - LPLOOKUPINFO info; -} RESOLVEREVENT, *LPRESOLVEREVENT; - -static Tcl_ObjCmdProc TclresolverObjCmd; -static Tcl_ExitProc Terminate; -static int Initialize(Tcl_Interp *interp, LPLOOKUPINFO pLookupInfo); -static LPCTSTR LookupHostname(LPLOOKUPINFO pLookupInfo, LPCTSTR szHostname); -static DWORD WINAPI Reader(LPVOID clientData); -static void QueueEvent(LPLOOKUPINFO pLookupInfo); -static int ResolverEventProc(Tcl_Event *evPtr, int flags); -static int GetAddress(char *query); -static Tcl_Obj *Win32Error(const char * szPrefix, HRESULT hr); - -/* ---------------------------------------------------------------------- */ - -int -Tclresolver_Init(Tcl_Interp *interp) -{ - int initialized = 0; - LPLOOKUPINFO pLookupInfo = NULL; - -#ifdef USE_TCL_STUBS - if (Tcl_InitStubs(interp, "8.1", 0) == NULL) { - return TCL_ERROR; - } -#endif - - pLookupInfo = (LPLOOKUPINFO)Tcl_Alloc(sizeof(LOOKUPINFO)); - if (pLookupInfo == NULL) { - Tcl_SetResult(interp, "out of memory", TCL_STATIC); - return TCL_ERROR; - } - ZeroMemory(pLookupInfo, sizeof(LOOKUPINFO)); - - if (Initialize(interp, pLookupInfo) != TCL_OK) { - Tcl_Free((char*)pLookupInfo); - return TCL_ERROR; - } - pLookupInfo->tclid = Tcl_GetCurrentThread(); - pLookupInfo->command = Tcl_CreateObjCommand(interp, "resolve", - TclresolverObjCmd, - (ClientData)pLookupInfo, - (Tcl_CmdDeleteProc *)NULL); - Tcl_CreateExitHandler(Terminate, (ClientData)pLookupInfo); - Tcl_SetAssocData(interp, ASSOC_KEY, NULL, (ClientData)pLookupInfo); - return Tcl_PkgProvide(interp, "Tclresolver", "1.2.0"); -} - -EXTERN int -Tclresolver_SafeInit(Tcl_Interp *interp) -{ - return Tclresolver_Init(interp); -} - -int -Tclresolver_Unload(Tcl_Interp *interp) -{ - LPLOOKUPINFO pLookupInfo = NULL; - pLookupInfo = (LPLOOKUPINFO)Tcl_GetAssocData(interp, ASSOC_KEY, NULL); - Tcl_DeleteCommandFromToken(interp, pLookupInfo->command); - Terminate((ClientData)pLookupInfo); - Tcl_SetAssocData(interp, ASSOC_KEY, NULL, (ClientData)NULL); - return TCL_OK; -} - -static int -TclresolverObjCmd(ClientData clientData, Tcl_Interp *interp, - int objc, Tcl_Obj *CONST objv[]) -{ - LPLOOKUPINFO pLookupInfo = (LPLOOKUPINFO)clientData; - Tcl_Obj *resObj = NULL; - if (objc != 2) { - Tcl_WrongNumArgs(interp, objc, objv, "hostname"); - return TCL_ERROR; - } - resObj = Tcl_NewStringObj(LookupHostname(pLookupInfo, - Tcl_GetString(objv[1])), -1); - Tcl_SetObjResult(interp, resObj); - return TCL_OK; -} - -/* ---------------------------------------------------------------------- */ - -static int -Initialize(Tcl_Interp *interp, LPLOOKUPINFO pLookupInfo) -{ - WSADATA wsd; - - OutputDebugString(_T("Initialize\n")); - - /* Initialize windows sockets. */ - if (WSAStartup(MAKEWORD(2,2), &wsd) != 0) { - Tcl_Obj *errObj = Win32Error("WSAStartup error", GetLastError()); - Tcl_SetObjResult(interp, errObj); - return TCL_ERROR; - } - - if (LOBYTE(wsd.wVersion) != 2 || - HIBYTE(wsd.wVersion) != 2) { - Tcl_SetResult(interp, - "error: failed to load a compatible winsock version", TCL_STATIC); - WSACleanup(); - return TCL_ERROR; - } - - /* Create synchronization events */ - pLookupInfo->hReady = CreateEvent(NULL, FALSE, FALSE, NULL); - pLookupInfo->hDone = CreateEvent(NULL, FALSE, FALSE, NULL); - pLookupInfo->bRunning = TRUE; - pLookupInfo->pData = (LPBYTE)Tcl_Alloc(BUFSIZE); - - /* Create the reader thread */ - pLookupInfo->hReader = CreateThread(NULL, 0, Reader, pLookupInfo, - 0, &pLookupInfo->idReader); - - return TCL_OK; -} - -static void -Terminate(ClientData clientData) -{ - LPLOOKUPINFO pLookupInfo = (LPLOOKUPINFO)clientData; - OutputDebugString(_T("Terminate\n")); - pLookupInfo->bRunning = FALSE; - Tcl_DeleteExitHandler(Terminate, clientData); - WaitForSingleObject(pLookupInfo->hReader, 400); - CloseHandle(pLookupInfo->hReader); - CloseHandle(pLookupInfo->hReady); - CloseHandle(pLookupInfo->hDone); - Tcl_Free(pLookupInfo->pData); - Tcl_Free((LPBYTE)pLookupInfo); - WSACleanup(); -} - -static LPCTSTR -LookupHostname(LPLOOKUPINFO pLookupInfo, LPCTSTR szHostname) -{ - DWORD dwWait; - - /* copy the hostname into out buffer */ - ZeroMemory(pLookupInfo->pData, BUFSIZE); - lstrcpy((LPTSTR)pLookupInfo->pData, szHostname); - - /* notify the reader thread that it should begin reading */ - SetEvent(pLookupInfo->hReady); - - /* Run a tcl event loop while we wait for the answer */ - while (1) { - Tcl_DoOneEvent(0); /* when tk loaded */ - //Tcl_DoOneEvent(TCL_ALL_EVENTS|TCL_DONT_WAIT); - OutputDebugString("done one event\n"); - dwWait = WaitForSingleObject(pLookupInfo->hDone, 0); - if (dwWait == WAIT_OBJECT_0) - break; - } - - return (LPCTSTR)pLookupInfo->pData; -} - -static DWORD WINAPI -Reader(LPVOID clientData) -{ - LPLOOKUPINFO pLookupInfo = (LPLOOKUPINFO)clientData; - DWORD dwErr = 0, dwRead = 0; - - while (pLookupInfo->bRunning) { - dwErr = WaitForSingleObject(pLookupInfo->hReady, 500); - if (dwErr == WAIT_OBJECT_0) { - GetAddress((char *)pLookupInfo->pData); - QueueEvent(pLookupInfo); - } - } - return 0; -} - -static void -QueueEvent(LPLOOKUPINFO pLookupInfo) -{ - LPRESOLVEREVENT evPtr; - OutputDebugString(_T("QueueEvent\n")); - evPtr = (LPRESOLVEREVENT)Tcl_Alloc(sizeof(RESOLVEREVENT)); - evPtr->header.proc = ResolverEventProc; - evPtr->header.nextPtr = NULL; - evPtr->info = pLookupInfo; - Tcl_ThreadQueueEvent(pLookupInfo->tclid, - (Tcl_Event *)evPtr, TCL_QUEUE_TAIL); -} - -static int -ResolverEventProc(Tcl_Event *evPtr, int flags) -{ - LPRESOLVEREVENT revPtr = (LPRESOLVEREVENT)evPtr; - OutputDebugString(_T("ResolverEventProc\n")); - SetEvent(revPtr->info->hDone); - return 1; -} - -static Tcl_Obj * -Win32Error(const char * szPrefix, HRESULT hr) -{ - Tcl_Obj *msgObj = NULL; - char * lpBuffer = NULL; - DWORD dwLen = 0; - - dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER - | FORMAT_MESSAGE_FROM_SYSTEM, - NULL, (DWORD)hr, LANG_NEUTRAL, - (LPTSTR)&lpBuffer, 0, NULL); - if (dwLen < 1) { - dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER - | FORMAT_MESSAGE_FROM_STRING - | FORMAT_MESSAGE_ARGUMENT_ARRAY, - "code 0x%1!08X!%n", 0, LANG_NEUTRAL, - (LPTSTR)&lpBuffer, 0, (va_list *)&hr); - } - - msgObj = Tcl_NewStringObj(szPrefix, -1); - if (dwLen > 0) { - char *p = lpBuffer + dwLen - 1; /* remove cr-lf at end */ - for ( ; p && *p && isspace(*p); p--) - ; - *++p = 0; - Tcl_AppendToObj(msgObj, ": ", 2); - Tcl_AppendToObj(msgObj, lpBuffer, -1); - } - LocalFree((HLOCAL)lpBuffer); - return msgObj; -} - -static int -GetAddress(char *query) -{ - struct addrinfo hints = {0}; - struct addrinfo *res = NULL; - char *hostname, *p, *q; - int r = 0, nc = 0; - - /* trim whitespace */ - for (p = query; *p && isspace(*p); p++) - ; - for (q = p + strlen(p) - 1; q > p && *q && isspace(*q); q--) - ; - *++q = 0; - hostname = p; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - hints.ai_flags = AI_CANONNAME; - hints.ai_socktype = SOCK_STREAM; - r = getaddrinfo(hostname, "", &hints, &res); - *query = 0; - - if (r != 0) { - Tcl_Obj *o = Win32Error("error", WSAGetLastError()); - strcpy(query, Tcl_GetString(o)); - Tcl_DecrRefCount(o); - } else { - struct addrinfo *resPtr = res; - for (resPtr = res; resPtr != NULL; resPtr = resPtr->ai_next) { - char name[NI_MAXHOST]; - - getnameinfo(resPtr->ai_addr, resPtr->ai_addrlen, - name, NI_MAXHOST, - NULL, 0, - NI_NUMERICHOST | NI_NUMERICSERV); - - if (resPtr != res) - strcat(query, " "); - strcat(query, name); - } - freeaddrinfo(res); - } - return r; -} - - diff --git a/tclresolver3.c b/tclresolver3.c deleted file mode 100644 index d465b5b..0000000 --- a/tclresolver3.c +++ /dev/null @@ -1,336 +0,0 @@ -/* tclresolver.c - Copyright (C) 2004 Pat Thoyts - * - * Non-blocking name resolution. - * - * $Id$ - */ - -#define WIN32_LEAN_AND_MEAN -#include -#include -#include - -#include - -#if _MSC_VER >= 1000 -#pragma comment(lib, "ws2_32") -#pragma comment(lib, "user32") -#endif - -#define BUFSIZE 4096 -#define XWM_RESOLVE WM_APP + 1 - -#undef TCL_STORAGE_CLASS -#define TCL_STORAGE_CLASS DLLEXPORT - -static const char ASSOC_KEY[] = "tclresolver_key"; - -EXTERN int Tclresolver_Init(Tcl_Interp *interp); -EXTERN int Tclresolver_Unload(Tcl_Interp *interp); -EXTERN int TclGetHostByName(LPSOCKADDR_IN saddrPtr, - const char *hostname, int port); - -typedef struct { - HANDLE hReader; - DWORD idReader; - Tcl_ThreadId tclid; - Tcl_Command command; -} PKGINFO, *LPPKGINFO; - -typedef struct { - HANDLE lock; - LONG cookie; - char data[BUFSIZE]; -} QUERYINFO, *LPQUERYINFO; - -typedef struct { - Tcl_Event header; - LPQUERYINFO query; -} RESOLVEREVENT, *LPRESOLVEREVENT; - -static Tcl_ObjCmdProc TclresolverObjCmd; -static Tcl_ExitProc Terminate; -static int Initialize(Tcl_Interp *interp, LPPKGINFO pkgPtr); -static Tcl_Obj *LookupHostname(LPPKGINFO pkgPtr, const char *hostname); -static DWORD WINAPI Reader(LPVOID clientData); -static void QueueEvent(Tcl_ThreadId id, LPQUERYINFO pQuery); -static int ResolverEventProc(Tcl_Event *evPtr, int flags); -static int GetAddress(char *query); -static Tcl_Obj *Win32Error(const char * szPrefix, HRESULT hr); - -/* ---------------------------------------------------------------------- */ - -int -Tclresolver_Init(Tcl_Interp *interp) -{ - int initialized = 0; - LPPKGINFO pkgPtr = NULL; - -#ifdef USE_TCL_STUBS - if (Tcl_InitStubs(interp, "8.1", 0) == NULL) { - return TCL_ERROR; - } -#endif - - pkgPtr = (LPPKGINFO)Tcl_Alloc(sizeof(PKGINFO)); - if (pkgPtr == NULL) { - Tcl_SetResult(interp, "out of memory", TCL_STATIC); - return TCL_ERROR; - } - ZeroMemory(pkgPtr, sizeof(PKGINFO)); - - if (Initialize(interp, pkgPtr) != TCL_OK) { - Tcl_Free((char*)pkgPtr); - return TCL_ERROR; - } - pkgPtr->tclid = Tcl_GetCurrentThread(); - pkgPtr->command = Tcl_CreateObjCommand(interp, "resolve", - TclresolverObjCmd, - (ClientData)pkgPtr, - (Tcl_CmdDeleteProc *)NULL); - Tcl_CreateExitHandler(Terminate, (ClientData)pkgPtr); - Tcl_SetAssocData(interp, ASSOC_KEY, NULL, (ClientData)pkgPtr); - return Tcl_PkgProvide(interp, "Tclresolver", "1.3.0"); -} - -EXTERN int -Tclresolver_SafeInit(Tcl_Interp *interp) -{ - return Tclresolver_Init(interp); -} - -int -Tclresolver_Unload(Tcl_Interp *interp) -{ - LPPKGINFO pkgPtr = NULL; - pkgPtr = (LPPKGINFO)Tcl_GetAssocData(interp, ASSOC_KEY, NULL); - Tcl_DeleteCommandFromToken(interp, pkgPtr->command); - Terminate((ClientData)pkgPtr); - Tcl_SetAssocData(interp, ASSOC_KEY, NULL, (ClientData)NULL); - return TCL_OK; -} - -static int -TclresolverObjCmd(ClientData clientData, Tcl_Interp *interp, - int objc, Tcl_Obj *CONST objv[]) -{ - LPPKGINFO pkgPtr = (LPPKGINFO)clientData; - Tcl_Obj *resObj = NULL; - if (objc != 2) { - Tcl_WrongNumArgs(interp, objc, objv, "hostname"); - return TCL_ERROR; - } - resObj = LookupHostname(pkgPtr, Tcl_GetString(objv[1])); - Tcl_SetObjResult(interp, resObj); - return TCL_OK; -} - -/* ---------------------------------------------------------------------- */ - -static int -Initialize(Tcl_Interp *interp, LPPKGINFO pkgPtr) -{ - WSADATA wsd; - - OutputDebugStringA("Initialize\n"); - - /* Initialize windows sockets. */ - if (WSAStartup(MAKEWORD(2,2), &wsd) != 0) { - Tcl_Obj *errObj = Win32Error("WSAStartup error", GetLastError()); - Tcl_SetObjResult(interp, errObj); - return TCL_ERROR; - } - - if (LOBYTE(wsd.wVersion) != 2 || - HIBYTE(wsd.wVersion) != 2) { - Tcl_SetResult(interp, - "error: failed to load a compatible winsock version", TCL_STATIC); - WSACleanup(); - return TCL_ERROR; - } - - /* Create the reader thread */ - pkgPtr->hReader = CreateThread(NULL, 0, Reader, pkgPtr, - 0, &pkgPtr->idReader); - - return TCL_OK; -} - -static void -Terminate(ClientData clientData) -{ - LPPKGINFO pkgPtr = (LPPKGINFO)clientData; - OutputDebugStringA("Terminate\n"); - PostThreadMessage(pkgPtr->idReader, WM_QUIT, 0, 0L); - Tcl_DeleteExitHandler(Terminate, clientData); - WaitForSingleObject(pkgPtr->hReader, 400); - CloseHandle(pkgPtr->hReader); - Tcl_Free((LPBYTE)pkgPtr); - WSACleanup(); -} - -static Tcl_Obj * -LookupHostname(LPPKGINFO pkgPtr, const char * hostname) -{ - Tcl_Obj *resObj = NULL; - DWORD dwWait; - LPQUERYINFO queryPtr; - static LONG cookie; - char sz[128]; - - /* copy the hostname into out buffer */ - queryPtr = (LPQUERYINFO)Tcl_Alloc(sizeof(QUERYINFO)); - memset(queryPtr, 0, sizeof(QUERYINFO)); - queryPtr->lock = CreateEvent(NULL, FALSE, FALSE, NULL); - queryPtr->cookie = InterlockedIncrement(&cookie); - strcpy(queryPtr->data, hostname); - - sprintf(sz, "query %d begin\n", queryPtr->cookie); - OutputDebugString(sz); - - /* notify the reader thread that it should begin reading */ - PostThreadMessage(pkgPtr->idReader, XWM_RESOLVE, 0, (LPARAM)queryPtr); - - /* Run a tcl event loop while we wait for the answer */ - while (1) { - Tcl_DoOneEvent(0); /* when tk loaded */ - //Tcl_DoOneEvent(TCL_ALL_EVENTS|TCL_DONT_WAIT); - dwWait = WaitForSingleObject(queryPtr->lock, 0); - if (dwWait == WAIT_OBJECT_0) { - sprintf(sz, "query %d complete\n", queryPtr->cookie); - OutputDebugString(sz); - break; - } - } - - resObj = Tcl_NewStringObj(queryPtr->data, -1); - CloseHandle(queryPtr->lock); - Tcl_Free((char *)queryPtr); - return resObj; -} - -static DWORD WINAPI -Reader(LPVOID clientData) -{ - LPPKGINFO pkgPtr = (LPPKGINFO)clientData; - LPQUERYINFO queryPtr = NULL; - MSG msg; - DWORD dwErr = 0, dwRead = 0; - - while(GetMessage(&msg, 0, 0, 0)) { - if (msg.hwnd == NULL) { - switch (msg.message) { - case XWM_RESOLVE: - queryPtr = (LPQUERYINFO)msg.lParam; - GetAddress(queryPtr->data); - QueueEvent(pkgPtr->tclid, queryPtr); - break; - } - } - DispatchMessage(&msg); - } - - OutputDebugStringA("Reader exiting.\n"); - return 0; -} - -static void -QueueEvent(Tcl_ThreadId id, LPQUERYINFO queryPtr) -{ - LPRESOLVEREVENT evPtr; - OutputDebugStringA("QueueEvent\n"); - evPtr = (LPRESOLVEREVENT)Tcl_Alloc(sizeof(RESOLVEREVENT)); - evPtr->header.proc = ResolverEventProc; - evPtr->header.nextPtr = NULL; - evPtr->query = queryPtr; - Tcl_ThreadQueueEvent(id, (Tcl_Event *)evPtr, TCL_QUEUE_TAIL); -} - -static int -ResolverEventProc(Tcl_Event *evPtr, int flags) -{ - LPRESOLVEREVENT revPtr = (LPRESOLVEREVENT)evPtr; - OutputDebugStringA("ResolverEventProc\n"); - SetEvent(revPtr->query->lock); - return 1; -} - -static Tcl_Obj * -Win32Error(const char * szPrefix, HRESULT hr) -{ - Tcl_Obj *msgObj = NULL; - char * lpBuffer = NULL; - DWORD dwLen = 0; - - dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER - | FORMAT_MESSAGE_FROM_SYSTEM, - NULL, (DWORD)hr, LANG_NEUTRAL, - (LPTSTR)&lpBuffer, 0, NULL); - if (dwLen < 1) { - dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER - | FORMAT_MESSAGE_FROM_STRING - | FORMAT_MESSAGE_ARGUMENT_ARRAY, - "code 0x%1!08X!%n", 0, LANG_NEUTRAL, - (LPTSTR)&lpBuffer, 0, (va_list *)&hr); - } - - msgObj = Tcl_NewStringObj(szPrefix, -1); - if (dwLen > 0) { - char *p = lpBuffer + dwLen - 1; /* remove cr-lf at end */ - for ( ; p && *p && isspace(*p); p--) - ; - *++p = 0; - Tcl_AppendToObj(msgObj, ": ", 2); - Tcl_AppendToObj(msgObj, lpBuffer, -1); - } - LocalFree((HLOCAL)lpBuffer); - return msgObj; -} - -static int -GetAddress(char *query) -{ - struct addrinfo hints = {0}; - struct addrinfo *res = NULL; - char *hostname, *p, *q; - int r = 0, nc = 0; - - /* trim whitespace */ - for (p = query; *p && isspace(*p); p++) - ; - for (q = p + strlen(p) - 1; q > p && *q && isspace(*q); q--) - ; - *++q = 0; - hostname = p; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_INET; /* use PF_UNSPEC if we want IPv6 too */ - hints.ai_flags = AI_CANONNAME; - hints.ai_socktype = SOCK_STREAM; - r = getaddrinfo(hostname, "", &hints, &res); - *query = 0; - - if (r != 0) { - Tcl_Obj *o = Win32Error("error", WSAGetLastError()); - strcpy(query, Tcl_GetString(o)); - Tcl_DecrRefCount(o); - } else { - struct addrinfo *resPtr = res; - for (resPtr = res; resPtr != NULL; resPtr = resPtr->ai_next) { - char name[NI_MAXHOST]; - - getnameinfo(resPtr->ai_addr, resPtr->ai_addrlen, - name, NI_MAXHOST, - NULL, 0, - NI_NUMERICHOST | NI_NUMERICSERV); - - if (resPtr != res) - strcat(query, " "); - strcat(query, name); - } - freeaddrinfo(res); - } - return r; -} - - diff --git a/w32cat.c b/w32cat.c deleted file mode 100644 index 560d15a..0000000 --- a/w32cat.c +++ /dev/null @@ -1,93 +0,0 @@ -/* w32cat.c - Copyright (C) 2004 Pat Thoyts - * - * This illustrates a line-oriented cat program. Each line read from the - * console is echoed to the output. - * - * NB: only reads from the CONSOLE though. Not piped input. - * - * $Id$ - */ - -#if defined(_UNICODE) && !defined(UNICODE) -#define UNICODE -#endif - -#define WIN32_LEAN_AND_MEAN -#include -#include - -void Win32Error(HANDLE hFile, LPCTSTR sz, HRESULT hr); - -int -_tmain(int argc, LPCTSTR argv[]) -{ - HANDLE hStdin, hStdout, hStderr; - DWORD dwMode; - - if ((hStderr = GetStdHandle(STD_ERROR_HANDLE)) == INVALID_HANDLE_VALUE) { - return -2; - } - - if ((hStdout = GetStdHandle(STD_OUTPUT_HANDLE)) == INVALID_HANDLE_VALUE) { - Win32Error(hStderr, _T("get stdout handle"), GetLastError()); - return -1; - } - - if ((hStdin = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) { - Win32Error(hStderr, _T("get stdin handle"), GetLastError()); - return -1; - } - - /* - * By default the console input is processed line oriented so we - * don't need to do anything special. - */ - - GetConsoleMode(hStdin, &dwMode); - dwMode &= ~ENABLE_LINE_INPUT; - SetConsoleMode(hStdin, dwMode); - GetConsoleMode(hStdout, &dwMode); - dwMode &= ~ENABLE_LINE_INPUT; - SetConsoleMode(hStdout, dwMode); - - while (1) { - DWORD cbRead = 0; - TCHAR buffer[1024]; - - if (! ReadFile(hStdin, buffer, 1023, &cbRead, NULL)) - break; - if (CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, - _T("quit"), 4, buffer, 4) == CSTR_EQUAL) - break; - - WriteFile(hStdout, buffer, cbRead, NULL, NULL); - } - - return 0; -} - -void -Win32Error(HANDLE hFile, LPCTSTR sz, HRESULT hr) -{ - LPTSTR lpBuffer = NULL; - DWORD dwLen = 0; - - dwLen = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER - | FORMAT_MESSAGE_FROM_SYSTEM, - NULL, (DWORD)hr, LANG_NEUTRAL, - (LPTSTR)&lpBuffer, 0, NULL); - if (dwLen < 1) { - HRESULT ahr[1] = {hr}; - dwLen = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER - | FORMAT_MESSAGE_FROM_STRING - | FORMAT_MESSAGE_ARGUMENT_ARRAY, - _T("code: 0x%1!08X!%n"), 0, LANG_NEUTRAL, - (LPTSTR)&lpBuffer, 0, (va_list *)ahr); - } - WriteConsole(hFile, sz, lstrlen(sz), NULL, NULL); - if (dwLen > 0) { - WriteConsole(hFile, _T(": "), 3, NULL, NULL); - WriteConsole(hFile, lpBuffer, dwLen, NULL, NULL); - } - LocalFree((HLOCAL)lpBuffer); -} diff --git a/win/tclresolver.c b/win/tclresolver.c index bcd143f..3b7dc63 100644 --- a/win/tclresolver.c +++ b/win/tclresolver.c @@ -1,18 +1,25 @@ /* tclresolver.c - Copyright (C) 2004 Pat Thoyts * - * + * Non-blocking name resolution. * * $Id$ */ #define WIN32_LEAN_AND_MEAN #include -#include #include +#include #include +#if _MSC_VER >= 1000 +#pragma comment(lib, "ws2_32") +#pragma comment(lib, "user32") +#endif + #define BUFSIZE 4096 +#define XWM_RESOLVE WM_APP + 1 + #undef TCL_STORAGE_CLASS #define TCL_STORAGE_CLASS DLLEXPORT @@ -26,32 +33,30 @@ EXTERN int TclGetHostByName(LPSOCKADDR_IN saddrPtr, typedef struct { HANDLE hReader; DWORD idReader; - HANDLE hReady; - HANDLE hDone; - HANDLE hIn; - HANDLE hOut; - LPBYTE pData; - BOOL bRunning; Tcl_ThreadId tclid; Tcl_Command command; -} LOOKUPINFO, *LPLOOKUPINFO; +} PKGINFO, *LPPKGINFO; + +typedef struct { + HANDLE lock; + LONG cookie; + char data[BUFSIZE]; +} QUERYINFO, *LPQUERYINFO; typedef struct { Tcl_Event header; - LPLOOKUPINFO info; + LPQUERYINFO query; } RESOLVEREVENT, *LPRESOLVEREVENT; -//static int TclResolverObjCmd(ClientData clientData, Tcl_Interp *interp, -// int objc, Tcl_Obj *CONST objv[]); static Tcl_ObjCmdProc TclresolverObjCmd; static Tcl_ExitProc Terminate; -static int Initialize(Tcl_Interp *interp, LPLOOKUPINFO pLookupInfo); -static BOOL CreateChildProcess(HANDLE hChildStdoutWr, HANDLE hChildStdinRd); -static LPCTSTR LookupHostname(LPLOOKUPINFO pLookupInfo, LPCTSTR szHostname); +static int Initialize(Tcl_Interp *interp, LPPKGINFO pkgPtr); +static Tcl_Obj *LookupHostname(LPPKGINFO pkgPtr, const char *hostname); static DWORD WINAPI Reader(LPVOID clientData); -static void QueueEvent(LPLOOKUPINFO pLookupInfo); +static void QueueEvent(Tcl_ThreadId id, LPQUERYINFO pQuery); static int ResolverEventProc(Tcl_Event *evPtr, int flags); - +static int GetAddress(char *query); +static Tcl_Obj *Win32Error(const char * szPrefix, HRESULT hr); /* ---------------------------------------------------------------------- */ @@ -59,7 +64,7 @@ int Tclresolver_Init(Tcl_Interp *interp) { int initialized = 0; - LPLOOKUPINFO pLookupInfo = NULL; + LPPKGINFO pkgPtr = NULL; #ifdef USE_TCL_STUBS if (Tcl_InitStubs(interp, "8.1", 0) == NULL) { @@ -67,26 +72,25 @@ Tclresolver_Init(Tcl_Interp *interp) } #endif - pLookupInfo = (LPLOOKUPINFO)Tcl_Alloc(sizeof(LOOKUPINFO)); - if (pLookupInfo == NULL) { + pkgPtr = (LPPKGINFO)Tcl_Alloc(sizeof(PKGINFO)); + if (pkgPtr == NULL) { Tcl_SetResult(interp, "out of memory", TCL_STATIC); return TCL_ERROR; } - ZeroMemory(pLookupInfo, sizeof(LOOKUPINFO)); + ZeroMemory(pkgPtr, sizeof(PKGINFO)); - if (Initialize(interp, pLookupInfo) != TCL_OK) { - Tcl_Free((char*)pLookupInfo); - //Tcl_SetResult(interp, "failed to initialize package", TCL_STATIC); + if (Initialize(interp, pkgPtr) != TCL_OK) { + Tcl_Free((char*)pkgPtr); return TCL_ERROR; } - pLookupInfo->tclid = Tcl_GetCurrentThread(); - pLookupInfo->command = Tcl_CreateObjCommand(interp, "resolve", + pkgPtr->tclid = Tcl_GetCurrentThread(); + pkgPtr->command = Tcl_CreateObjCommand(interp, "resolve", TclresolverObjCmd, - (ClientData)pLookupInfo, + (ClientData)pkgPtr, (Tcl_CmdDeleteProc *)NULL); - Tcl_CreateExitHandler(Terminate, (ClientData)pLookupInfo); - Tcl_SetAssocData(interp, ASSOC_KEY, NULL, (ClientData)pLookupInfo); - return Tcl_PkgProvide(interp, "Tclresolver", "1.0.0"); + Tcl_CreateExitHandler(Terminate, (ClientData)pkgPtr); + Tcl_SetAssocData(interp, ASSOC_KEY, NULL, (ClientData)pkgPtr); + return Tcl_PkgProvide(interp, "Tclresolver", "0.4.0"); } EXTERN int @@ -98,10 +102,10 @@ Tclresolver_SafeInit(Tcl_Interp *interp) int Tclresolver_Unload(Tcl_Interp *interp) { - LPLOOKUPINFO pLookupInfo = NULL; - pLookupInfo = (LPLOOKUPINFO)Tcl_GetAssocData(interp, ASSOC_KEY, NULL); - Tcl_DeleteCommandFromToken(interp, pLookupInfo->command); - Terminate((ClientData)pLookupInfo); + LPPKGINFO pkgPtr = NULL; + pkgPtr = (LPPKGINFO)Tcl_GetAssocData(interp, ASSOC_KEY, NULL); + Tcl_DeleteCommandFromToken(interp, pkgPtr->command); + Terminate((ClientData)pkgPtr); Tcl_SetAssocData(interp, ASSOC_KEY, NULL, (ClientData)NULL); return TCL_OK; } @@ -110,14 +114,13 @@ static int TclresolverObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { - LPLOOKUPINFO pLookupInfo = (LPLOOKUPINFO)clientData; + LPPKGINFO pkgPtr = (LPPKGINFO)clientData; Tcl_Obj *resObj = NULL; if (objc != 2) { Tcl_WrongNumArgs(interp, objc, objv, "hostname"); return TCL_ERROR; } - resObj = Tcl_NewStringObj(LookupHostname(pLookupInfo, - Tcl_GetString(objv[1])), -1); + resObj = LookupHostname(pkgPtr, Tcl_GetString(objv[1])); Tcl_SetObjResult(interp, resObj); return TCL_OK; } @@ -125,251 +128,210 @@ TclresolverObjCmd(ClientData clientData, Tcl_Interp *interp, /* ---------------------------------------------------------------------- */ static int -Initialize(Tcl_Interp *interp, LPLOOKUPINFO pLookupInfo) -{ - SECURITY_ATTRIBUTES saAttr; - BOOL fSuccess; - HANDLE hChildStdinRd, hChildStdinWr, hChildStdoutRd, hChildStdoutWr; - HANDLE hChildStdoutRdDup, hChildStdinWrDup; - - // Set the bInheritHandle flag so pipe handles are inherited. - saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); - saAttr.bInheritHandle = TRUE; - saAttr.lpSecurityDescriptor = NULL; - - // Create a pipe for the child process's STDOUT. - if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) { - Tcl_SetResult(interp, "Stdout pipe creation failed", TCL_STATIC); - return TCL_ERROR; - } - - // Create noninheritable read handle and close the inheritable read - // handle. - fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd, - GetCurrentProcess(), &hChildStdoutRdDup , 0, - FALSE, - DUPLICATE_SAME_ACCESS); - if( !fSuccess ) { - Tcl_SetResult(interp, "DuplicateHandle failed", TCL_STATIC); - return TCL_ERROR; - } - CloseHandle(hChildStdoutRd); - - // Create a pipe for the child process's STDIN. - if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) { - Tcl_SetResult(interp, "Stdin pipe creation failed", TCL_STATIC); +Initialize(Tcl_Interp *interp, LPPKGINFO pkgPtr) +{ + WSADATA wsd; + + OutputDebugStringA("Initialize\n"); + + /* Initialize windows sockets. */ + if (WSAStartup(MAKEWORD(2,2), &wsd) != 0) { + Tcl_Obj *errObj = Win32Error("WSAStartup error", GetLastError()); + Tcl_SetObjResult(interp, errObj); return TCL_ERROR; } - - // Duplicate the write handle to the pipe so it is not inherited. - fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr, - GetCurrentProcess(), &hChildStdinWrDup, 0, - FALSE, // not inherited - DUPLICATE_SAME_ACCESS); - if (! fSuccess) { - Tcl_SetResult(interp, "DuplicateHandle failed", TCL_STATIC); + + if (LOBYTE(wsd.wVersion) != 2 || + HIBYTE(wsd.wVersion) != 2) { + Tcl_SetResult(interp, + "error: failed to load a compatible winsock version", TCL_STATIC); + WSACleanup(); return TCL_ERROR; } - CloseHandle(hChildStdinWr); - - /* Create synchronization events */ - pLookupInfo->hReady = CreateEvent(NULL, FALSE, FALSE, NULL); - pLookupInfo->hDone = CreateEvent(NULL, FALSE, FALSE, NULL); - pLookupInfo->hIn = hChildStdoutRdDup; - pLookupInfo->hOut = hChildStdinWrDup; - pLookupInfo->bRunning = TRUE; - pLookupInfo->pData = (LPBYTE)Tcl_Alloc(BUFSIZE); /* Create the reader thread */ - pLookupInfo->hReader = CreateThread(NULL, 0, Reader, pLookupInfo, - 0, &pLookupInfo->idReader); + pkgPtr->hReader = CreateThread(NULL, 0, Reader, pkgPtr, + 0, &pkgPtr->idReader); - /* Now create the child process. */ - fSuccess = CreateChildProcess(hChildStdoutWr, hChildStdinRd); - if (! fSuccess) { - Tcl_SetResult(interp, "Create process failed", TCL_STATIC); - return TCL_ERROR; - } - return TCL_OK; } static void Terminate(ClientData clientData) { - LPLOOKUPINFO pLookupInfo = (LPLOOKUPINFO)clientData; - OutputDebugString("Pkgdeleteproc\n"); - pLookupInfo->bRunning = FALSE; - WaitForSingleObject(pLookupInfo->hReader, 400); - CloseHandle(pLookupInfo->hReader); - CloseHandle(pLookupInfo->hReady); - CloseHandle(pLookupInfo->hDone); - CloseHandle(pLookupInfo->hIn); - CloseHandle(pLookupInfo->hOut); - Tcl_Free(pLookupInfo->pData); - Tcl_Free((LPBYTE)pLookupInfo); + LPPKGINFO pkgPtr = (LPPKGINFO)clientData; + OutputDebugStringA("Terminate\n"); + PostThreadMessage(pkgPtr->idReader, WM_QUIT, 0, 0L); + Tcl_DeleteExitHandler(Terminate, clientData); + WaitForSingleObject(pkgPtr->hReader, 400); + CloseHandle(pkgPtr->hReader); + Tcl_Free((LPBYTE)pkgPtr); + WSACleanup(); } -static LPCTSTR -LookupHostname(LPLOOKUPINFO pLookupInfo, LPCTSTR szHostname) +static Tcl_Obj * +LookupHostname(LPPKGINFO pkgPtr, const char * hostname) { - DWORD dwWrote, dwWait; - BOOL br; + Tcl_Obj *resObj = NULL; + DWORD dwWait; + LPQUERYINFO queryPtr; + static LONG cookie; + char sz[128]; + + /* copy the hostname into out buffer */ + queryPtr = (LPQUERYINFO)Tcl_Alloc(sizeof(QUERYINFO)); + memset(queryPtr, 0, sizeof(QUERYINFO)); + queryPtr->lock = CreateEvent(NULL, FALSE, FALSE, NULL); + queryPtr->cookie = InterlockedIncrement(&cookie); + strcpy(queryPtr->data, hostname); + + sprintf(sz, "query %d begin\n", queryPtr->cookie); + OutputDebugString(sz); - ZeroMemory(pLookupInfo->pData, BUFSIZE); - lstrcpy((LPTSTR)pLookupInfo->pData, szHostname); - lstrcat((LPTSTR)pLookupInfo->pData, _T("\n")); - br = WriteFile(pLookupInfo->hOut, pLookupInfo->pData, - lstrlen((LPTSTR)pLookupInfo->pData) * sizeof(TCHAR), - &dwWrote, NULL); - if (br) - br = FlushFileBuffers(pLookupInfo->hOut); - if (br) { - /* clear out the buffer ready for reading */ - ZeroMemory(pLookupInfo->pData, BUFSIZE); - /* notify the reader thread that it should begin reading */ - SetEvent(pLookupInfo->hReady); -#ifdef USE_WIN32_EVENTS - /* Doing this will block Tcl event processing */ - dwWait = WaitForSingleObject(pLookupInfo->hDone, INFINITE); -#else - /* Run a tcl event loop while we wait for the answer */ - while (1) { - Tcl_DoOneEvent(0); /* when tk loaded */ - //Tcl_DoOneEvent(TCL_ALL_EVENTS|TCL_DONT_WAIT); - OutputDebugString("done one event\n"); - dwWait = WaitForSingleObject(pLookupInfo->hDone, 0); - if (dwWait == WAIT_OBJECT_0) - break; - } -#endif - } - if (!br) { - return _T(""); - } - return (LPCTSTR)pLookupInfo->pData; -} - -static BOOL -CreateChildProcess(HANDLE hChildStdoutWr, HANDLE hChildStdinRd) -{ - PROCESS_INFORMATION piProcInfo; - STARTUPINFO siStartInfo; - BOOL bFuncRetn = FALSE; - - /* Set up members of the PROCESS_INFORMATION structure.*/ - ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) ); - - /* Set up members of the STARTUPINFO structure.*/ - ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) ); - siStartInfo.cb = sizeof(STARTUPINFO); - siStartInfo.hStdError = hChildStdoutWr; - siStartInfo.hStdOutput = hChildStdoutWr; - siStartInfo.hStdInput = hChildStdinRd; - siStartInfo.dwFlags |= STARTF_USESTDHANDLES; - - /* Create the child process.*/ - bFuncRetn = CreateProcess(NULL, - "resolver", // command line - NULL, // process security attributes - NULL, // primary thread security attributes - TRUE, // handles are inherited - DETACHED_PROCESS, // no console - NULL, // use parent's environment - NULL, // use parent's current directory - &siStartInfo, // STARTUPINFO pointer - &piProcInfo); // receives PROCESS_INFORMATION - - if (bFuncRetn == 0) - return bFuncRetn; /*ErrorExit("CreateProcess failed");*/ - else - { - CloseHandle(piProcInfo.hProcess); - CloseHandle(piProcInfo.hThread); - return bFuncRetn; + /* notify the reader thread that it should begin reading */ + PostThreadMessage(pkgPtr->idReader, XWM_RESOLVE, 0, (LPARAM)queryPtr); + + /* Run a tcl event loop while we wait for the answer */ + while (1) { + Tcl_DoOneEvent(0); /* when tk loaded */ + //Tcl_DoOneEvent(TCL_ALL_EVENTS|TCL_DONT_WAIT); + dwWait = WaitForSingleObject(queryPtr->lock, 0); + if (dwWait == WAIT_OBJECT_0) { + sprintf(sz, "query %d complete\n", queryPtr->cookie); + OutputDebugString(sz); + break; + } } + + resObj = Tcl_NewStringObj(queryPtr->data, -1); + CloseHandle(queryPtr->lock); + Tcl_Free((char *)queryPtr); + return resObj; } static DWORD WINAPI Reader(LPVOID clientData) { - LPLOOKUPINFO pLookupInfo = (LPLOOKUPINFO)clientData; + LPPKGINFO pkgPtr = (LPPKGINFO)clientData; + LPQUERYINFO queryPtr = NULL; + MSG msg; DWORD dwErr = 0, dwRead = 0; - BOOL br; - - while (pLookupInfo->bRunning) { - dwErr = WaitForSingleObject(pLookupInfo->hReady, 500); - if (dwErr == WAIT_OBJECT_0) { - br = ReadFile(pLookupInfo->hIn, pLookupInfo->pData, - BUFSIZE, &dwRead, NULL); - - if (dwRead > 0) { - LPTSTR p = (LPTSTR)pLookupInfo->pData; - for (p = p + lstrlen(p) - 1; - p > pLookupInfo->pData && _istspace(*p); - p--) - ; - *++p = 0; - } -#ifdef USE_WIN32_EVENTS - SetEvent(pLookupInfo->hDone); -#else - QueueEvent(pLookupInfo); -#endif - } + + while(GetMessage(&msg, 0, 0, 0)) { + if (msg.hwnd == NULL) { + switch (msg.message) { + case XWM_RESOLVE: + queryPtr = (LPQUERYINFO)msg.lParam; + GetAddress(queryPtr->data); + QueueEvent(pkgPtr->tclid, queryPtr); + break; + } + } + DispatchMessage(&msg); } + + OutputDebugStringA("Reader exiting.\n"); return 0; } static void -QueueEvent(LPLOOKUPINFO pLookupInfo) +QueueEvent(Tcl_ThreadId id, LPQUERYINFO queryPtr) { LPRESOLVEREVENT evPtr; - OutputDebugString("queueevent\n"); + OutputDebugStringA("QueueEvent\n"); evPtr = (LPRESOLVEREVENT)Tcl_Alloc(sizeof(RESOLVEREVENT)); evPtr->header.proc = ResolverEventProc; evPtr->header.nextPtr = NULL; - evPtr->info = pLookupInfo; - Tcl_ThreadQueueEvent(pLookupInfo->tclid, - (Tcl_Event *)evPtr, TCL_QUEUE_TAIL); + evPtr->query = queryPtr; + Tcl_ThreadQueueEvent(id, (Tcl_Event *)evPtr, TCL_QUEUE_TAIL); } static int ResolverEventProc(Tcl_Event *evPtr, int flags) { LPRESOLVEREVENT revPtr = (LPRESOLVEREVENT)evPtr; - OutputDebugString("resolvereventproc\n"); - SetEvent(revPtr->info->hDone); + OutputDebugStringA("ResolverEventProc\n"); + SetEvent(revPtr->query->lock); return 1; } -#if 0 -int -TclGetHostByName(LPSOCKADDR_IN saddrPtr, const char *hostname, int port) +static Tcl_Obj * +Win32Error(const char * szPrefix, HRESULT hr) +{ + Tcl_Obj *msgObj = NULL; + char * lpBuffer = NULL; + DWORD dwLen = 0; + + dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER + | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, (DWORD)hr, LANG_NEUTRAL, + (LPTSTR)&lpBuffer, 0, NULL); + if (dwLen < 1) { + dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER + | FORMAT_MESSAGE_FROM_STRING + | FORMAT_MESSAGE_ARGUMENT_ARRAY, + "code 0x%1!08X!%n", 0, LANG_NEUTRAL, + (LPTSTR)&lpBuffer, 0, (va_list *)&hr); + } + + msgObj = Tcl_NewStringObj(szPrefix, -1); + if (dwLen > 0) { + char *p = lpBuffer + dwLen - 1; /* remove cr-lf at end */ + for ( ; p && *p && isspace(*p); p--) + ; + *++p = 0; + Tcl_AppendToObj(msgObj, ": ", 2); + Tcl_AppendToObj(msgObj, lpBuffer, -1); + } + LocalFree((HLOCAL)lpBuffer); + return msgObj; +} + +static int +GetAddress(char *query) { - struct in_addr addr; - - ZeroMemory(saddrPtr, sizeof(SOCKADDR_IN)); - saddrPtr->sin_family = AF_INET; - saddrPtr->sin_port = htons((unsigned short)port); - /* if no hostname then the answer is any host */ - if (hostname == NULL || *hostname == 0) { - addr.s_addr = INADDR_ANY; + struct addrinfo hints = {0}; + struct addrinfo *res = NULL; + char *hostname, *p, *q; + int r = 0, nc = 0; + + /* trim whitespace */ + for (p = query; *p && isspace(*p); p++) + ; + for (q = p + strlen(p) - 1; q > p && *q && isspace(*q); q--) + ; + *++q = 0; + hostname = p; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_INET; /* use PF_UNSPEC if we want IPv6 too */ + hints.ai_family = PF_UNSPEC; + hints.ai_flags = AI_CANONNAME; + hints.ai_socktype = SOCK_STREAM; + r = getaddrinfo(hostname, "", &hints, &res); + *query = 0; + + if (r != 0) { + Tcl_Obj *o = Win32Error("error", WSAGetLastError()); + strcpy(query, Tcl_GetString(o)); + Tcl_DecrRefCount(o); } else { - /* see if we have been given an ip number already */ - addr.s_addr = inet_addr(hostname); - if (addr.s_addr == INADDR_NONE) { - /* Perform the address lookup via our subprocess */ - addr.s_addr = inet_addr(LookupHostname(hostname)); - if (addr.s_addr == INADDR_NONE) { -#ifdef EHOSTUNREACH - Tcl_SetErrno(EHOSTUNREACH); -#endif - return 0; /* error */ - } - } + struct addrinfo *resPtr = res; + for (resPtr = res; resPtr != NULL; resPtr = resPtr->ai_next) { + char name[NI_MAXHOST]; + + getnameinfo(resPtr->ai_addr, resPtr->ai_addrlen, + name, NI_MAXHOST, + NULL, 0, + NI_NUMERICHOST | NI_NUMERICSERV); + + if (resPtr != res) + strcat(query, " "); + strcat(query, name); + } + freeaddrinfo(res); } - saddrPtr->sin_addr.s_addr = addr.s_addr; - return 1; + return r; } -#endif + +