unit dnswin; interface uses binipstuff,classes,lcore; {$include lcoreconfig.inc} //on failure a null string or zeroed out binip will be retuned and error will be //set to a windows error code (error will be left untouched under non error //conditions). function winforwardlookuplist(name : string;familyhint:integer;var error : integer) : tbiniplist; function winreverselookup(ip:tbinip;var error:integer):string; type //do not call destroy on a tdnswinasync instead call release and the //dnswinasync will be freed when appropriate. Calling destroy will block //the calling thread until the dns lookup completes. //release should only be called from the main thread tdnswinasync=class(tthread) private freverse : boolean; error : integer; freewhendone : boolean; hadevent : boolean; protected procedure execute; override; public onrequestdone:tsocketevent; name : string; iplist : tbiniplist; procedure forwardlookup(name:string); procedure reverselookup(ip:tbinip); destructor destroy; override; procedure release; constructor create; property reverse : boolean read freverse; end; implementation uses lsocket,pgtypes,sysutils,winsock,windows,messages; type //taddrinfo = record; //forward declaration paddrinfo = ^taddrinfo; taddrinfo = packed record ai_flags : longint; ai_family : longint; ai_socktype : longint; ai_protocol : longint; ai_addrlen : taddrint; ai_canonname : pchar; ai_addr : pinetsockaddrv; ai_next : paddrinfo; end; ppaddrinfo = ^paddrinfo; tgetaddrinfo = function(nodename : pchar; servname : pchar; hints : paddrinfo;res : ppaddrinfo) : longint; stdcall; tfreeaddrinfo = procedure(ai : paddrinfo); stdcall; tgetnameinfo = function(sa:Pinetsockaddrv;salen : longint; host:pchar;hostlen : longint;serv:pchar;servlen:longint;flags:longint) : longint;stdcall; var getaddrinfo : tgetaddrinfo; freeaddrinfo : tfreeaddrinfo; getnameinfo : tgetnameinfo; procedure v4onlyfreeaddrinfo(ai : paddrinfo); stdcall; var next:paddrinfo; begin while assigned(ai) do begin freemem(ai.ai_addr); next := ai.ai_next; freemem(ai); ai := next; end; end; type plongint = ^longint; pplongint = ^plongint; function v4onlygetaddrinfo(nodename : pchar; servname : pchar; hints : paddrinfo;res : ppaddrinfo) : longint; stdcall; var output,prev,first : paddrinfo; hostent : phostent; addrlist:^pointer; begin if hints.ai_family <> af_inet6 then begin result := 0; hostent := gethostbyname(nodename); if hostent = nil then begin result := wsagetlasterror; v4onlyfreeaddrinfo(output); exit; end; addrlist := pointer(hostent.h_addr_list); //ipint := pplongint(hostent.h_addr_list)^^; prev := nil; first := nil; repeat if not assigned(addrlist^) then break; getmem(output,sizeof(taddrinfo)); if assigned(prev) then prev.ai_next := output; getmem(output.ai_addr,sizeof(tinetsockaddr)); if servname <> nil then output.ai_addr.InAddr.port := htons(strtoint(servname)) else output.ai_addr.InAddr.port := 0; output.ai_addr.InAddr.addr := longint(addrlist^^); inc(integer(addrlist),4); output.ai_flags := 0; output.ai_family := af_inet; output.ai_socktype := 0; output.ai_protocol := 0; output.ai_addrlen := sizeof(tinetsockaddr); output.ai_canonname := nil; output.ai_next := nil; prev := output; if not assigned(first) then first := output; until false; res^ := first; end else begin result := WSANO_RECOVERY; end; end; function min(a,b : integer):integer; begin if a 0 then begin fillchar(result,0,sizeof(result)); error := getaddrinforesult; end; end; function winreverselookup(ip:tbinip;var error : integer):string; var sa : tinetsockaddrv; getnameinforesult : integer; begin if ip.family = AF_INET then begin sa.InAddr.family := AF_INET; sa.InAddr.port := 1; sa.InAddr.addr := ip.ip; end else {$ifdef ipv6}if ip.family = AF_INET6 then begin sa.InAddr6.sin6_family := AF_INET6; sa.InAddr6.sin6_port := 1; sa.InAddr6.sin6_addr := ip.ip6; end else{$endif} begin raise exception.create('unrecognised address family'); end; populateprocvars; setlength(result,1025); getnameinforesult := getnameinfo(@sa,sizeof(tinetsockaddrv),pchar(result),length(result),nil,0,0); if getnameinforesult <> 0 then begin error := getnameinforesult; result := ''; exit; end; if pos(#0,result) >= 0 then begin setlength(result,pos(#0,result)-1); end; end; var hwnddnswin : hwnd; function MyWindowProc( ahWnd : HWND; auMsg : Integer; awParam : WPARAM; alParam : LPARAM): Integer; stdcall; var dwas : tdnswinasync; begin if (ahwnd=hwnddnswin) and (aumsg=wm_user) then begin Dwas := tdnswinasync(alparam); if assigned (dwas.onrequestdone) then dwas.onrequestdone(dwas,awparam); dwas.hadevent := true; if dwas.freewhendone then dwas.free; end else begin //not passing unknown messages on to defwindowproc will cause window //creation to fail! --plugwash Result := DefWindowProc(ahWnd, auMsg, awParam, alParam) end; end; procedure tdnswinasync.forwardlookup(name:string); begin self.name := name; freverse := false; resume; end; procedure tdnswinasync.reverselookup(ip:tbinip); begin iplist := biniplist_new; biniplist_add(iplist,ip); freverse := true; resume; end; procedure tdnswinasync.execute; var error : integer; begin error := 0; if reverse then begin name := winreverselookup(biniplist_get(iplist,0),error); end else begin iplist := winforwardlookuplist(name,0,error); end; postmessage(hwnddnswin,wm_user,error,taddrint(self)); end; destructor tdnswinasync.destroy; begin WaitFor; inherited destroy; end; procedure tdnswinasync.release; begin if hadevent then destroy else begin onrequestdone := nil; freewhendone := true; end; end; constructor tdnswinasync.create; begin inherited create(true); end; var MyWindowClass : TWndClass = (style : 0; lpfnWndProc : @MyWindowProc; cbClsExtra : 0; cbWndExtra : 0; hInstance : 0; hIcon : 0; hCursor : 0; hbrBackground : 0; lpszMenuName : nil; lpszClassName : 'dnswinClass'); begin if Windows.RegisterClass(MyWindowClass) = 0 then halt; //writeln('about to create lcore handle, hinstance=',hinstance); hwnddnswin := CreateWindowEx(WS_EX_TOOLWINDOW, MyWindowClass.lpszClassName, '', { Window name } WS_POPUP, { Window Style } 0, 0, { X, Y } 0, 0, { Width, Height } 0, { hWndParent } 0, { hMenu } HInstance, { hInstance } nil); { CreateParam } //writeln('dnswin hwnd is ',hwnddnswin); //writeln('last error is ',GetLastError); end.