Mega Code Archive

 
Categories / Delphi / LAN Web TCP
 

Simple functions to get raw html page (with or without proxy)

Title: Simple functions to get raw html page (with or without proxy) Question: Here is some functions to retreive a web paget. The code don't use any components or thread. Only pure windows api. It is usefull for console app that need to get a particular page from a server. It also works with Proxy. Answer: DESCRIPTION ----------- This functions are not embeded in classes. It is good-old-dos-in-line programming, and it works fine for my console app (a Web server security checker). There is 2 functions in U_HTTP.PAS : function HttpGet(const site, path, port : string ; var res : string) : integer; IN : site is the web site to connect to (eg 'www.delphi3000.com') path is the path of the web page (eg 'index.html') port is a string for the TCP port to connect to (eg '80') OUT : res is the raw web page, with the HTTP header. return an error code( Function HttpGetEx(var Request : THttpRequest) : integer; is an extension of the first function. It can use proxy to retreive data. You have to fill the THttpRequest struct before calling the function. This struct is use to pass in and out parameters to the function (I prefere this compared to OOP class). IN : THttpRequest.Site is the web site to connect to THttpRequest.Path is the web page to retreive THttpRequest.Port is the port to connect to THttpRequest.UseProxy set it to TRUE if you use a proxy THttpRequest.ProxyAddress is eventually the proxy address (eg 'proxy.prout.com') THttpRequest.ProxyPort is the proxy port (eg '8080' or '3128') THttpRequest.TimeOut is the maximum time, in seconds, before returning a timeout error IN / OUT THttpRequest.HttpCode set it to 1 when calling and the function will parse the http header and returning (in HttpCode) the HTTP status code (eg 200 if ok, 404 if page not found...) OUT : THttpRequest.Result is the raw web page THttpRequest.ResultLen is the number of bytes returned (the length of Result) THttpRequest.ResultCode is 0 if ok, or an error code ( THttpRequest.ResultTime is the time spend to retreive the data return 0 if ok or an error code The Error Code returned in both functions is a negative integer from -1 to -7. You should check WSAGetLastError to have a more precise error. SAMPLE PROGRAM -------------- Make a console app and copy and past this code : program SimpleHttp; uses WinSock, U_Http in 'U_Http.pas', u_SockUtil in 'u_SockUtil.pas'; {$R *.RES} var res : string; Req : THttpRequest; iRes : integer; begin // Fill the Request structure Req.Site := 'www.delphi3000.com'; Req.Path := '/'; Req.Port := '80'; Req.Timeout := 4; Req.UseProxy := true; // !! CHANGE THIS IF YOU DONT USE PROXY !! Req.ProxyAddress := '130.142.153.7'; Req.ProxyPort := '8080'; Req.HttpCode := 1; // 1 : Yes, i will check for http status code Writeln('Getting Data'); iRes := HttpGetEx(req); if (iRes 0) then begin // It works Writeln(Req.Result); Writeln('Http code : ',Req.HttpCode); Writeln('Length of data : ', Req.ResultLen); Writeln('Getting in : ', Req.ResultTime, ' ms'); end else begin // It fails Writeln('Error number :', Req.ResultCode); Writeln(SocketErrorMsg(WSAGetLastError)); end; ReadLn; end. THE UNITS --------- unit U_Http; {** U_Http.pas ** 05/02/2001 by Jerome Forestier ** Unit to get raw HTML result. Use low level winsock ** api (in U_SockUtil.pas), so it can be used in console app. ** Usefull for checking exploit. **} interface Uses Windows, Winsock, U_SockUtil; const RCV_BUFSIZE = 512; // Size of the incomming data buffer CRLF = #$0D#$0A; // DEFAULT_TIMEOUT_SECOND = 10; // // Error Code OK = 0; ERR_BIND = -1; ERR_CONNECT = -2; ERR_SEND = -3; ERR_TIMEOUT = -4; ERR_SELECT = -5; ERR_RECV = -6; ERR_PROXY_CONNECT = -7; type THttpRequest = packed record Site : string; // in : site address (www.yahoo.com) Path : string; // in : site path (/index.html) Port : string; // in : site port number (80) UseProxy : boolean; // in : use proxy for getting data ProxyAddress : String; // in : proxy address (proxy.toto.com) ProxyPort : string; // in : proxy port (3128) Timeout : word ; // in : tiemout for getting data in seconds Result : string; // out : raw html result ResultLen : integer; // out : number of bytes returned ResultCode : integer; // out : error code (if any) ResultTime : longint; // out : time, in ms, to get the data HttpCode : word; // in / out if 1, the http header will be parsed and the error code (404) returned in // if 0, no check for error code end; function HttpGet(const site, path, port : string ; var res : string) : integer; // The simpliest function to retreive html source of a page. // Raw html is in res variable. // The function return 0 if ok or an error code (ERR_xxx) Function HttpGetEx(var Request : THttpRequest) : integer; // Extended function to retreive html source of a page // Request parameters is in/out. Check out THttpRequest type // The function return the number of bytes retreived ( 0) if ok // or an error code (ERR_xxx) implementation uses sysutils; procedure InitSocket; var wsData : TWsAData; begin WSAStartup($0101, wsData); end; procedure DeInitSocket; begin WSACleanup; end; procedure CheckHttpHeader(buf :PCHAR ; len : integer ; var errorcode : word); // This is experimental ! // We enter in this proc only for the first incomming buffer, // it _should_ contain the http header with the error code // eg : HHTP/1.0 404 Not Founf var i : integer; code : integer; scode : pchar; begin if (ErrorCode 1) then exit; i := 0; // We search for the first space while (buf[i] ' ') and (buf[i] #0) and (i begin inc(i); end; if (buf[i] = ' ') then begin // char after the space are the error code scode := @buf[i+1]; code := StrToIntDef(Copy(scode,1,3), 0); errorcode := code; end else ErrorCode := 0; end; Function HttpGetEx(var Request : THttpRequest) : integer; label EndOfProc; var Socket : TSocket; iBindType : Integer; err : integer; ToSend : string; SndBuf : PCHAR; RcvBuf : array[0..RCV_BUFSIZE] of char; FD : TFDSet; TimeOut : TTimeVal; len : integer; Time : longint; begin Time := GetTickCount; result := -1; Request.Result := ''; Request.ResultCode := 0; Request.ResultLen := 0; TimeOut.tv_sec := Request.Timeout; TimeOut.tv_usec := 0; FD_ZERO(FD); iBindType := GET_PORT_AND_REMOTE_ADDR; socket := CreateSocket(iBindType, SOCK_STREAM); err := BindSocketToAddr(iBindType, socket, request.Port, 'TCP', true); if (err = SOCKET_ERROR) then begin Request.ResultCode := ERR_BIND; Goto EndOfProc; end; if (Request.UseProxy) then begin err := ConnectToServer(iBindType, Socket, Request.ProxyAddress, Request.ProxyPort, 'TCP'); if (err = SOCKET_ERROR) then Request.ResultCode := ERR_PROXY_CONNECT; end else begin err := ConnectToServer(iBindType, Socket, Request.Site, Request.Port, 'TCP'); if (err = SOCKET_ERROR) then Request.ResultCode := ERR_CONNECT; end; if (err = SOCKET_ERROR) then Goto EndOfProc; if (Request.UseProxy) then begin ToSend := Format('GET http://%s:%s%s HTTP/1.0'+CRLF, [Request.Site, Request.Port, Request.Path]); end else begin ToSend := Format('GET %s HTTP/1.0'+CRLF, [Request.Path]); end; ToSend := ToSend+'Accept: */*'+CRLF; ToSend := ToSend+'Accept-Language: en'+CRLF; ToSend := ToSend+'Accept-Encoding: gzip'+CRLF; ToSend := ToSend+'User-Agent: JemoreWebClient(AmstradOS; I)'+CRLF; ToSend := ToSend+'Host: '+Request.Site+':'+Request.port+CRLF; if (Request.UseProxy) then ToSend := ToSend + 'Proxy-Connection: Keep-Alive'+CRLF else ToSend := ToSend + 'Connection: Keep-Alive'+CRLF; ToSend := ToSend + CRLF+CRLF; len := Length(ToSend) - 1; SndBuf := PCHAR(ToSend); FD_SET(socket, FD); err := send(Socket, SndBuf^, len, 0); if (err = SOCKET_ERROR) then begin Request.ResultCode := ERR_SEND; goto EndOfProc; end; repeat err := Select(FD_SETSIZE, @FD, nil, nil, @TimeOut); if (err = 0) then begin Request.ResultCode := ERR_TIMEOUT; break; end else if (err = SOCKET_ERROR) then begin Request.ResultCode := ERR_SELECT; break; end; if (FD_ISSET(socket, FD)) then begin err := recv(Socket, RcvBuf, RCV_BUFSIZE, 0); if (err = SOCKET_ERROR) then begin Request.ResultCode := ERR_RECV; break; end else if (err 0) then begin rcvBuf[err] := #0; if (Request.HttpCode = 1) then CheckHttpHeader(RcvBuf, RCV_BUFSIZE, Request.HttpCode); Request.Result := Request.Result + rcvBuf; Request.ResultLen := Request.ResultLen + err; end; end; until (err = 0); EndOfProc : DestroySocket(socket); Request.ResultTime := GetTickCount - Time; result := Request.ResultLen; end; function HttpGet(const site, path, port : string ; var res : string) : integer; var socket : TSocket; iBindType : integer; err : integer; p : PCHAR; RcvBuf : array[0..RCV_BUFSIZE] of char; FD : TFDSet; TimeOut : TTimeVal; len : integer; begin FillChar(rcvBuf, RCV_BUFSIZE, 0); TimeOut.tv_sec := DEFAULT_TIMEOUT_SECOND; TimeOut.tv_usec := 0; res := ''; FD_ZERO(FD); iBindType := GET_PORT_AND_REMOTE_ADDR; socket := CreateSocket(iBindType, SOCK_STREAM); err := BindSocketToAddr(iBindType, socket, port, 'TCP', true); if (err = SOCKET_ERROR) then begin result := ERR_BIND; exit; end; err := ConnectToServer(iBindType, Socket, site, port, 'TCP'); if (err = SOCKET_ERROR) then begin result := ERR_CONNECT; exit; end; p := PCHAR(Format('GET %s HTTP/1.0'+CRLF+CRLF+CRLF, [path])); len := length(p) - 1; FD_SET(socket, FD); err := send(Socket, p^, len, 0); if (err = SOCKET_ERROR) then begin result := ERR_SEND; exit; end; repeat err := Select(FD_SETSIZE, @FD, nil, nil, @TimeOut); if (err = 0) then begin result := ERR_TIMEOUT; exit; end else if (err = SOCKET_ERROR) then begin result := ERR_SELECT; exit; end; if (FD_ISSET(socket, FD)) then begin err := recv(Socket, rcvBuf, RCV_BUFSIZE, 0); if (err = SOCKET_ERROR) then begin result := ERR_RECV; break; end else if (err 0) then begin rcvBuf[err] := #0; res := res + rcvBuf; end; end; until (err = 0); DestroySocket(socket); result := Ok; end; initialization initSocket; finalization DeInitSocket; end. -------------------------------------------------------------------------------- WMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWM WMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWM WMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWM -------------------------------------------------------------------------------- unit u_SockUtil; {** Based on Sockutil.c in ** "Network Windows Programming" by Alok K. Sinha **} interface uses Windows, Winsock; function WinSockInitialize : integer; function GetHostAddress(const hostname : string) : u_long; function GetLocalHostAddress : u_long; function GetPortForService(const serviceName, protocol : string) : u_short; function BindSocketToAddr(iBindType : integer ; soc : TSocket; servicename : string; const protocolname : string; fClient : BOOL) : integer; function CreateSocket(iBindType : integer; type_ : integer) : TSocket; procedure DestroySocket(socket : TSocket); function ConnectToServer(iBindType : integer; soc : TSocket ; HostName : string ; ServiceName : string ; ProtocolName : string) : integer; function GetHostAddressIPStr(const hostname : string) : string; function SocketErrorMsg(Error: integer) : string; const NETBIOS_NAME_LENGTH = 16; DEFAULT_PORT_ADDR = 1; FIXED_PORT_LOCAL_ADDR = 2; GET_PORT_AND_LOCAL_ADDR = 3; BIND_NETBIOS = 4; BIND_IPX = 5; GET_PORT_AND_REMOTE_ADDR = 6; FIXED_PORT = 80; CLIENT_QUEUE_SIZE = 5; READ_WRITE_LOOP = 1; SHUTDOWN = 'ShutDown'; type TSockAddr_nb = packed record snb_family : short; snb_type : u_short; snb_name : array[0..NETBIOS_NAME_LENGTH-1] of char; end; PSockAddr_nb = ^TSockAddr_nb; TSockAddr_ipx = packed record sa_family : short; sa_netnum : array[0..4-1] of char; sa_nodenum : array[0..6-1] of char; sa_socket : u_short; end; PSockAddr_ipx = ^TSockAddr_ipx; implementation uses SysUtils; const NETBIOS_UNIQUE_NAME = 0; NSPROTO_IPX = 0; NSPROTO_SPX = 1256; NSPROTO_SPXII = 1257; defIPXAddress : TSockAddr_ipx = ( sa_family : AF_IPX ; sa_netnum : (#0,#0,#0,#0) ; sa_nodenum: (#0,#0,#0,#0,#0,#0) ; sa_socket : $4040 ); procedure SET_NETBIOS_SOCKADDR(snb : PSockAddr_nb ; type_ : word ; name : PCHAR ; port : char); var i : integer; begin snb^.snb_family := AF_NETBIOS; snb^.snb_type := type_; for i := 0 to NETBIOS_NAME_LENGTH - 1 do begin snb^.snb_name := ' '; end; i := 0; while (name[i] #0) and (i begin snb^.snb_name[i] := name[i]; end; snb^.snb_name[NETBIOS_NAME_LENGTH - 1] := port; end; function WinSockInitialize : integer; var wVersionRequired : WORD; wsaData : TwsaData; begin wVersionRequired := MAKEWORD(1,1); result := WSAStartup(wVersionRequired, wsaData); end; function GetHostAddress(const hostname : string) : u_long; var pHostAddr : PHostEnt; type T = ^u_long; begin pHostAddr := gethostbyname(PCHAR(hostname)); if (pHostAddr = nil) then begin result := 0; end else begin result := T(pHostAddr^.h_addr^)^; end; end; function GetLocalHostAddress : u_long; var szHostName : array[0..MAX_PATH] of char; begin if (gethostname(szHostName, SizeOf(szHostName)) SOCKET_ERROR) then result := GetHostAddress(szHostName) else result := 0; end; function GetPortForService(const serviceName, protocol : string) : u_short; var pServAddr : PServent; begin pServAddr := getservbyname(PCHAR(servicename), PCHAR(protocol)); if (pServAddr nil) then result := pServAddr^.s_port else result := u_short(-1); end; function BindSocketToAddr(iBindType : integer ; soc : TSocket; servicename : string; const protocolname : string; fClient : BOOL) : integer; var LocalAddr : TSockAddrIn; NetBiosAddr : TSockAddr_nb; IpxAddr : TSockAddr_ipx; err : integer; ulHostAddress : u_long; usPortNo : u_short; bReuse : BOOL; szNbName : array[0..NETBIOS_NAME_LENGTH - 1] of char; tmp : pchar; begin bReuse := true; if (fClient) then begin if ((iBindType BIND_IPX) and (iBindType BIND_NETBIOS)) then iBindType := DEFAULT_PORT_ADDR; end; FillChar(LocalAddr, SizeOf(LocalAddr), 00); // err := SOCKET_ERROR; case (iBindType) of DEFAULT_PORT_ADDR : begin LocalAddr.sin_family := AF_INET; LocalAddr.sin_addr.S_addr := htonl(INADDR_ANY); LocalAddr.sin_port := 0; end; FIXED_PORT_LOCAL_ADDR : begin ulHostAddress := GetLocalHostAddress; if (ulHostAddress = 0) then begin result := -1; exit; end; LocalAddr.sin_family := AF_INET; LocalAddr.sin_addr.s_addr := ulHostAddress; LocalAddr.sin_port := htons(FIXED_PORT); end; GET_PORT_AND_LOCAL_ADDR : begin ulHostAddress := GetLocalHostAddress; if (ulHostAddress = 0) then begin result := -1; exit; end else usPortNo := GetPortForService(ServiceName, ProtocolName); if (usPortNo = 65535) then usPortNo := htons(StrToIntDef(ServiceName, -1)); LocalAddr.sin_family := AF_INET; LocalAddr.sin_addr.s_addr := ulHostAddress; LocalAddr.sin_port := usPortNo; end; BIND_NETBIOS : begin usPortNo := GetPortForService(serviceName, ProtocolName); if (usPortNo = 65535) then usPortNo := htons(StrToIntDef(ServiceName, -1)); if (fClient) then begin serviceName := 'WSockClient'; end; FillChar(szNbName, SizeOf(szNbName), 0); Move(serviceName, szNbName, Length(ServiceName)); SET_NETBIOS_SOCKADDR(@NetBiosAddr, NETBIOS_UNIQUE_NAME, szNbName, CHAR(usPortNo)); end; BIND_IPX: begin move(defIPXAddress, IpxAddr, SizeOf(TSOCKADDR_IPX)); tmp := PCHAR(ServiceName); move(tmp, ipxAddr.sa_nodenum, 6); tmp := PCHAR(ProtocolName); move(tmp, ipxAddr.sa_netnum, 4); if (fClient) then ipxAddr.sa_socket := 0; setsockopt(soc, SOL_SOCKET, SO_REUSEADDR, PCHAR(bReuse), 4); end; end; if (iBindType = BIND_NETBIOS) then err := bind(soc, TSockAddrIn(pSockAddrIn(@NetBiosAddr)^), SizeOf(NetBiosAddr)) else if (iBindType = BIND_IPX) then err := bind(soc, TSockAddrIn(pSockAddrIn(@IpxAddr)^), SizeOf(IpxAddr)) else err := bind(soc, TSockAddrIn(pSockAddrIn(@LocalAddr)^), SizeOf(LocalAddr)); result := err; end; function CreateSocket(iBindType : integer; type_ : integer) : TSocket; var soc : TSocket; begin case (iBindType) of BIND_IPX : begin if (type_ = SOCK_STREAM) then soc := Socket(AF_IPX, type_, NSPROTO_SPX) else soc := Socket(AF_IPX, type_, NSPROTO_IPX); end; BIND_NETBIOS : begin if (type_ = SOCK_STREAM) then soc := Socket(AF_IPX, type_, SOCK_SEQPACKET) else soc := Socket(AF_IPX, type_, SOCK_DGRAM); end; else begin soc := Socket(AF_INET, type_, 0); end; end; result := soc; end; function ConnectToServer(iBindType : integer; soc : TSocket ; HostName : string ; ServiceName : string ; ProtocolName : string) : integer; var RemAddr : TSockAddrIn; NetBiosAddr : TSockAddr_NB; IpxAddr : TSockAddr_ipx; err : integer; ulHostAddress : u_long; usPortNo : u_short; begin FillChar(RemAddr, 0, SizeOf(TSockAddrIn)); case (iBindType) of DEFAULT_PORT_ADDR : begin result := SOCKET_ERROR; exit; end; FIXED_PORT_LOCAL_ADDR : begin ulHostAddress := GetLocalHostAddress; if (ulHostAddress = 0) then begin result := SOCKET_ERROR; exit; end; RemAddr.sin_family := AF_INET; RemAddr.sin_addr.S_addr := UlHostAddress; RemAddr.sin_port := htons(FIXED_PORT); end; GET_PORT_AND_LOCAL_ADDR : begin ulHostAddress := GetLocalHostAddress; if (ulHostAddress = 0) then begin result := SOCKET_ERROR; exit; end; usPortNo := (GetPortForService(ServiceName, ProtocolName)); if (usPortNo = 65535) then usPortNo := htons(StrToIntDef(ServiceName, -1)); RemAddr.sin_family := AF_INET; RemAddr.sin_addr.s_addr := ulHostAddress; RemAddr.sin_port := usPortNo; end; GET_PORT_AND_REMOTE_ADDR : begin ulHostAddress := GetHostAddress(HostName); if (ulHostAddress = 0) then begin result := SOCKET_ERROR; exit; end; usPortNo := (GetPortForService(ServiceName, ProtocolName)); if (usPortNo = 65535) then usPortNo := htons(StrToIntDef(ServiceName, -1)); RemAddr.sin_family := AF_INET; RemAddr.sin_addr.s_addr := ulHostAddress; RemAddr.sin_port := usPortNo; end; BIND_IPX : begin Move(defIPXaddress, IpxAddr, SizeOf(TSockAddr_IPX)); end; end; if (iBindType = BIND_NETBIOS) then err := connect(soc, TSockAddrIn(pSockAddrIn(@NetBiosAddr)^), SizeOf(NetBiosAddr)) else if (iBindType = BIND_IPX) then err := connect(soc, TSockAddrIn(pSockAddrIn(@IpxAddr)^), SizeOf(IpxAddr)) else err := Connect(soc, RemAddr, SizeOf(RemAddr)); result := Err; end; function GetHostAddressIPStr(const hostname : string) : string; var adr : u_long; in_ : TInAddr; begin adr := GetHostAddress(hostname); in_.S_addr := adr; result := inet_ntoa(in_); end; function SocketErrorMsg(Error: integer) : string; begin case Error of WSAEINTR: SocketErrorMsg := 'Interrupted system call'; WSAEBADF: SocketErrorMsg := 'Bad file number'; WSAEACCES: SocketErrorMsg := 'Permission denied'; WSAEFAULT: SocketErrorMsg := 'Bad address'; WSAEINVAL: SocketErrorMsg := 'Invalid argument'; WSAEMFILE: SocketErrorMsg := 'Too many open files'; WSAEWOULDBLOCK: SocketErrorMsg := 'Operation would block'; WSAEINPROGRESS: SocketErrorMsg := 'Operation now in progress'; WSAEALREADY: SocketErrorMsg := 'Operation already in progress'; WSAENOTSOCK: SocketErrorMsg := 'Socket operation on non-socket'; WSAEDESTADDRREQ: SocketErrorMsg := 'Destination address required'; WSAEMSGSIZE: SocketErrorMsg := 'Message too long'; WSAEPROTOTYPE: SocketErrorMsg := 'Protocol wrong type for socket'; WSAENOPROTOOPT: SocketErrorMsg := 'Protocol not available'; WSAEPROTONOSUPPORT: SocketErrorMsg := 'Protocol not supported'; WSAESOCKTNOSUPPORT: SocketErrorMsg := 'Socket type not supported'; WSAEOPNOTSUPP: SocketErrorMsg := 'Operation not supported on socket'; WSAEPFNOSUPPORT: SocketErrorMsg := 'Protocol family not supported'; WSAEAFNOSUPPORT: SocketErrorMsg := 'Address family not supported by protocol family'; WSAEADDRINUSE: SocketErrorMsg := 'Address already in use'; WSAEADDRNOTAVAIL: SocketErrorMsg := 'Can''t assign requested address'; WSAENETDOWN: SocketErrorMsg := 'Network is down'; WSAENETUNREACH: SocketErrorMsg := 'Network is unreachable'; WSAENETRESET: SocketErrorMsg := 'Network dropped connection on reset'; WSAECONNABORTED: SocketErrorMsg := 'Software caused connection abort'; WSAECONNRESET: SocketErrorMsg := 'Connection reset by peer'; WSAENOBUFS: SocketErrorMsg := 'No buffer space available'; WSAEISCONN: SocketErrorMsg := 'Socket is already connected'; WSAENOTCONN: SocketErrorMsg := 'Socket is not connected'; WSAESHUTDOWN: SocketErrorMsg := 'Can''t send after socket shutdown'; WSAETOOMANYREFS: SocketErrorMsg := 'Too many references: can''t splice'; WSAETIMEDOUT: SocketErrorMsg := 'Connection timed out'; WSAECONNREFUSED: SocketErrorMsg := 'Connection refused'; WSAELOOP: SocketErrorMsg := 'Too many levels of symbolic links'; WSAENAMETOOLONG: SocketErrorMsg := 'File name too long'; WSAEHOSTDOWN: SocketErrorMsg := 'Host is down'; WSAEHOSTUNREACH: SocketErrorMsg := 'No route to host'; WSAENOTEMPTY: SocketErrorMsg := 'Directory not empty'; WSAEPROCLIM: SocketErrorMsg := 'Too many processes'; WSAEUSERS: SocketErrorMsg := 'Too many users'; WSAEDQUOT: SocketErrorMsg := 'Disc quota exceeded'; WSAESTALE: SocketErrorMsg := 'Stale NFS file handle'; WSAEREMOTE: SocketErrorMsg := 'Too many levels of remote in path'; WSASYSNOTREADY: SocketErrorMsg := 'Network sub-system is unusable'; WSAVERNOTSUPPORTED: SocketErrorMsg := 'WinSock DLL cannot support this application'; WSANOTINITIALISED: SocketErrorMsg := 'WinSock not initialized'; WSAHOST_NOT_FOUND: SocketErrorMsg := 'Host not found'; WSATRY_AGAIN: SocketErrorMsg := 'Non-authoritative host not found'; WSANO_RECOVERY: SocketErrorMsg := 'Non-recoverable error'; WSANO_DATA: SocketErrorMsg := 'No Data'; else SocketErrorMsg := 'Unknown WinSock error'; end; end; procedure DestroySocket(socket : TSocket); begin Winsock.Shutdown(socket,1); CloseSocket(Socket); end; end. // Tested with D3 and NT4