home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 September / Chip_2001-09_cd1.bin / zkuste / delphi / nastroje / d5 / MFTP.ZIP / src / FtpSock.pas < prev    next >
Pascal/Delphi Source File  |  2001-01-03  |  15KB  |  509 lines

  1. unit FTPSock;
  2.  
  3. {Microsoft Windows Socket implementation of Monster FTP}
  4. interface
  5.  
  6. uses Classes, Windows, Messages, SysUtils, WinSock;
  7.  
  8. {$I mftp.inc}
  9.  
  10. {$ifdef USE_WINSOCK2}
  11.    const SockLibName = 'ws2_32.dll';
  12. {$else}
  13.    const SockLibName = 'wsock32.dll';
  14. {$endif}
  15.  
  16. type
  17.    sockaddr_in = record
  18.       sin_family: SmallInt;
  19.       sin_port: u_short;
  20.       sin_addr: TInAddr;
  21.       sin_zero: array[0..7] of Char;
  22.    end;
  23.  
  24.   in6_addr = record
  25.     case integer of
  26.       0: (S_un_b: array[0..15] of Char);
  27.       1: (S_un_w: array[0..7] of Word);
  28.   end;
  29.   TInAddr6 = in6_addr;
  30.  
  31.    sockaddr_in6 = record
  32.       sin6_family: SmallInt;  
  33.       sin6_port: u_short;       { Transport level port number }
  34.       sin6_flowinfo: Longword;  { IPv6 flow information }
  35.       sin6_addr: TInAddr6;      { IPv6 address }
  36.       sin6_scope_id: Longword;  { set of interfaces for a scope }
  37.    end;
  38.      
  39.    sockaddr = record
  40.       sa_family: u_short;
  41.       sa_data: array[0..13] of Char; { should be 0..13 ?}
  42.    end;
  43.       
  44.    PInteger = ^Integer;
  45.    PSockAddr = ^SockAddr;
  46.  
  47.    function accept(s: TSocket; addr: PSockaddr; addrlen: PInteger): TSocket; stdcall; external SockLibName;
  48.    function bind(s: TSocket; addr: Psockaddr; namelen: Integer): Integer; stdcall; external SockLibName;
  49.    function closesocket(s: TSocket): Integer; stdcall; external SockLibName;
  50.    function connect(s: TSocket; name: Psockaddr; namelen: Integer): Integer; stdcall; external SockLibName;
  51.    function gethostname(name: PChar; len: Integer): Integer; stdcall; external SockLibName;
  52.    function getsocketname(s: TSocket; name: Psockaddr; namelen: PInteger): Integer; stdcall; external SockLibName name 'getsockname';
  53.    function htons(hostshort: u_short): u_short; stdcall; external SockLibName;
  54.    function inet_addr(cp: PChar): u_long; stdcall; external SockLibName;
  55.    function inet_ntoa(inaddr: TInAddr): PChar; stdcall; external SockLibName;
  56.    function listen(s: TSocket; backlog: Integer): Integer; stdcall; external SockLibName;
  57.    function ntohs(netshort: u_short): u_short; stdcall; external SockLibName;
  58.    function recv(s: TSocket; buf: PChar; len, flags: Integer): Integer; stdcall; external SockLibName;
  59.    function send(s: TSocket; buf: PChar; len, flags: Integer): Integer; stdcall; external SockLibName;
  60.    function socket(af, tp, protocol: Integer): TSocket; stdcall; external SockLibName;
  61.    function WSAAsyncGetHostByName(HWindow: HWND; wMsg: u_int; name, buf: PChar; buflen: Integer): THandle; stdcall; external SockLibName;
  62.    function WSAAsyncSelect(s: TSocket; HWindow: HWND; wMsg: u_int; lEvent: longint): Integer; stdcall; external SockLibName;
  63.    function WSACancelAsyncRequest(hAsyncTaskHandle: THandle): Integer; stdcall; external SockLibName;
  64.    function WSACleanup: Integer; stdcall; external SockLibName;
  65.    function WSAGetLastError: Integer; stdcall; external SockLibName;
  66.    function WSAStartup(wVersionRequired: Word; var lpWSData: TWSAData): Integer; stdcall; external SockLibName;
  67.  
  68. const
  69.    WM_ARPDONE = WM_USER;
  70.    WM_SOCKMSG = WM_USER + 1;
  71.  
  72. type TSSWndMethod = procedure(var Message: TMessage) of object;
  73.    
  74. type TMSocket = class(TComponent)
  75.    private
  76.       FHandle: HWND;
  77.       FSocket: TSocket;
  78.       FAddr: sockaddr_in;
  79.       FConnected: boolean;
  80.       FBytesSent: Integer;
  81.       FDescription: String;
  82.       FSystemStatus: String;
  83.       FMaxSockets: Integer;
  84.       FCustomMessage: TSSWndMethod;
  85.       MyWSAData: TWSAData;
  86.       FLookupNameDone, FOnConnected, FOnDisconnected, FTimeoutEvt: TNotifyEvent;
  87.       FOnReadReady, FOnWriteReady, FOnAccept: TNotifyEvent;
  88.       THostEntryBuf: array[1..MAXGETHOSTSTRUCT] of Byte;
  89.       sa: TInAddr;
  90.       ArpHandle: THandle;
  91.       FTimeOut: LongInt;
  92.       Timer: LongInt;
  93.       TimerID: LongInt;
  94.       dnsbuf: array[1..64] of Char;
  95.       procedure SockWndProc(var Message: TMessage);
  96.    protected
  97.       FVersion: String;
  98.       procedure LookupNameDone; virtual;
  99.       procedure Connected;
  100.       procedure Disconnected;
  101.    public
  102.       Address, Host, FServer: String;
  103.       FPort: u_short;
  104.       LastError: Word;
  105.       WantBlockingErrors: Boolean;
  106.       constructor Create(AOwner: TComponent); override;
  107.       destructor Destroy; override;
  108.       property Version: String read FVersion;
  109.  
  110.       procedure CreateTCPSocket;
  111.       procedure ReCreateTCPSocket;
  112.       procedure LookupName(host: String);
  113.       procedure FillName;
  114.       procedure FillAddress(address: String);
  115.       procedure FillPort(port: Word);
  116.       procedure Connect;
  117.       procedure Disconnect;
  118.       procedure Listen;
  119.       procedure Accept(ListeningSocket: TMSocket);
  120.       function GetAddressString: String;
  121.       function GetLocalHost: String;
  122.       function GetLocalAddress: String;
  123.       function GetLocalPort: u_short;
  124.       function SendBuf(buf: PChar; cnt: Integer): Integer;
  125.       function SendBufOOB(buf: PChar; cnt: Integer): Integer;
  126.       function RecvBuf(buf: PChar; cnt: Integer): Integer;
  127.       procedure SetServer(s: String);
  128.       procedure SetTimeout(seconds: LongInt);
  129.  
  130.       property Description: String read FDescription;
  131.       property SystemStatus: String read FSystemStatus;
  132.       property MaxSockets: Integer read FMaxSockets;
  133.       property Handle: HWND read FHandle;
  134.       property CustomMessage: TSSWndMethod read FCustomMessage write FCustomMessage;
  135.       property IsConnected: Boolean read FConnected;
  136.       property Socket: TSocket read FSocket;
  137.       property OnLookupNameDone: TNotifyEvent read FLookupNameDone write FLookupNameDone;
  138.       property OnConnected: TNotifyEvent read FOnConnected write FOnConnected;
  139.       property OnDisconnected: TNotifyEvent read FOnDisconnected write FOnDisconnected;
  140.       property OnReadReady: TNotifyEvent read FOnReadReady write FOnReadReady;
  141.       property OnWriteReady: TNotifyEvent read FOnWriteReady write FOnWriteReady;
  142.       property OnTimeOut: TNotifyEvent read FTimeOutEvt write FTimeOutEvt;
  143.       property OnAccept: TNotifyEvent read FOnAccept write FOnAccept;
  144.       property TimeOut: LongInt read FTimeOut write FTimeOut;
  145.  
  146.       property Server: String read FServer write SetServer;
  147.       property Port: u_short read FPort write FPort;
  148.    published
  149.    end;
  150.       
  151. var
  152.    S_un: TInAddr;
  153.  
  154. implementation
  155.  
  156. uses Forms;
  157.  
  158. constructor TMSocket.Create;
  159. begin
  160.    inherited Create(AOwner);
  161.  
  162.    FAddr.sin_family := PF_INET;
  163.    FAddr.sin_addr.s_addr := INADDR_ANY;
  164.    FAddr.sin_port := 0;
  165.    FHandle := AllocateHWND(SockWndProc);
  166.    FSocket := INVALID_SOCKET;
  167.    FConnected := False;
  168.    FBytesSent := 0;
  169.    FTimeOut := 20;
  170.  
  171.    if WSAStartup($0002, myWSAData) = 0 then
  172.    begin
  173.        with myWSAData do
  174.        begin
  175.           FDescription := StrPas(szDescription);
  176.           FSystemStatus := StrPas(szSystemStatus);
  177.           FMaxSockets := iMaxSockets;
  178.        end;
  179.    end;
  180.  
  181.    WantBlockingErrors := False;
  182. end;
  183.  
  184. destructor TMSocket.Destroy;
  185. begin
  186.    FSocket := -1;
  187.    DeallocateHwnd(FHandle);
  188.    WSACleanUp;
  189.  
  190.    inherited Destroy;
  191. end;
  192.  
  193. procedure TMSocket.SockWndProc;
  194. var phe: PHostEnt;
  195.     evt: Word;
  196. begin
  197.    if (Message.Msg > WM_SOCKMSG) and Assigned(FCustomMessage) then
  198.    begin
  199.       FCustomMessage(Message);
  200.       Exit;
  201.    end;
  202.    case Message.Msg of
  203.       {custom messages}
  204.       WM_ARPDONE: {received after WSAAsyncGetHostByName}
  205.       begin
  206.          SetTimeout(0);
  207.          LastError := HIWORD(Message.lParam);
  208.          if LastError = 0 then
  209.          begin
  210.             phe := PHostEnt(@THostEntryBuf);
  211.             with sa, phe^ do
  212.             begin
  213.                S_un_b.s_b1 := h_addr^[0];
  214.                S_un_b.s_b2 := h_addr^[1];
  215.                S_un_b.s_b3 := h_addr^[2];
  216.                S_un_b.s_b4 := h_addr^[3];
  217.             end;
  218.          end;
  219.          ArpHandle := 0;
  220.          LookupNameDone;
  221.       end;
  222.       WM_SOCKMSG:  {received after connect, read, write, disconnect notification}
  223.       begin
  224.          evt := LOWORD(Message.lParam);
  225.          LastError := HIWORD(Message.lParam);
  226.          case evt of
  227.             FD_CONNECT:
  228.             begin
  229.                FConnected := (LastError = 0);
  230.                SetTimeOut(0);
  231.                Connected;
  232.             end;
  233.             FD_CLOSE:
  234.             begin
  235.                if FConnected then
  236.                begin
  237.                   if Assigned(FOnReadReady) then FOnReadReady(Self);
  238.                   if Assigned(FOnWriteReady) then FOnWriteReady(Self);
  239.                   ShutDown(FSocket, 2);
  240.                   CloseSocket(FSocket);
  241.                end;
  242.                FConnected := False;
  243.                FSocket := INVALID_SOCKET;
  244.                Disconnected;
  245.             end;
  246.             FD_READ:
  247.             begin
  248.                if Assigned(FOnReadReady) then FOnReadReady(Self);
  249.                SetTimeOut(0);
  250.             end;
  251.             FD_WRITE: if Assigned(FOnWriteReady) then FOnWriteReady(Self);
  252.             FD_ACCEPT: if Assigned(FOnAccept) then FOnAccept(Self);
  253.          end;
  254.       end;
  255.       {end custom messages}
  256.       WM_TIMER:
  257.       begin
  258.          Dec(Timer);
  259.          if Timer = 0 then
  260.          begin
  261.             if Assigned(FTimeoutEvt) then
  262.                FTimeoutEvt(Self)
  263.             else
  264.                Disconnect;
  265.          end;
  266.       end;
  267.       WM_QUERYENDSESSION: Message.Result := 1; {end session bug}
  268.       else DefWindowProc(FHandle, Message.Msg, Message.wParam, Message.lParam);
  269.    end;
  270. end;
  271.  
  272. procedure TMSocket.SetTimeout;
  273. begin
  274.    if TimerID <> 0 then KillTimer(FHandle, TimerID);
  275.    if seconds <= 0 then
  276.       TimerId := 0
  277.    else
  278.    begin
  279.       Timer := seconds;
  280.       TimerID := SetTimer(FHandle, 1, 1000, nil);
  281.    end;
  282. end;
  283.  
  284. procedure TMSocket.CreateTCPSocket;
  285. begin
  286.    if FSocket <> INVALID_SOCKET then Exit;
  287.    FSocket := FTPSock.socket(PF_INET, SOCK_STREAM, IPPROTO_IP);
  288.    LastError := WSAGetLastError
  289. end;
  290.  
  291. procedure TMSocket.ReCreateTCPSocket;
  292. begin
  293.    CloseSocket(FSocket);
  294.    FSocket := INVALID_SOCKET;
  295.    CreateTCPSocket;
  296. end;
  297.  
  298. function TMSocket.GetAddressString;
  299. begin
  300.    Result := StrPas(inet_ntoa(FAddr.sin_addr));
  301. end;
  302.  
  303. procedure TMSocket.LookupName;
  304. begin
  305.    if ArpHandle <> 0 then Exit;
  306.    StrPCopy(@dnsbuf, host);
  307.    ArpHandle := WSAAsyncGetHostByName(FHandle, WM_ARPDONE, @dnsbuf, @THostEntryBuf, MAXGETHOSTSTRUCT);
  308.    LastError := WSAGetLastError;
  309.    if LastError = 0 then SetTimeout(FTimeOut);
  310. end;
  311.  
  312. procedure TMSocket.FillName;
  313. begin
  314.    FAddr.sin_addr := sa;
  315. end;
  316.  
  317. procedure TMSocket.FillAddress;
  318. var
  319.    s: array [1..32] of Char;
  320. begin
  321.    StrPCopy(@s, address);
  322.    FAddr.sin_addr.s_addr := inet_addr(@s);
  323. end;
  324.  
  325. procedure TMSocket.FillPort;
  326. begin
  327.    FAddr.sin_port := htons(port);
  328. end;
  329.  
  330. procedure TMSocket.LookupNameDone;
  331. begin
  332.    if Assigned(FLookupNameDone) then FLookupNameDone(Self);
  333. end;
  334.  
  335. procedure TMSocket.Connected;
  336. begin
  337.    if Assigned(FOnConnected) then FOnConnected(Self);
  338. end;
  339.  
  340. procedure TMSocket.Disconnected;
  341. begin
  342.    if Assigned(FOnDisconnected) then FOnDisconnected(Self);
  343. end;
  344.  
  345. procedure TMSocket.Connect;
  346. begin
  347.    WSAAsyncSelect(FSocket, FHandle, WM_SOCKMSG, FD_CONNECT or FD_CLOSE or FD_READ or FD_WRITE);
  348.    if FTPSock.connect(FSocket, Psockaddr(@FAddr), SizeOf(FAddr)) <> 0 then
  349.    begin
  350.       LastError := WSAGetLastError;
  351.       if not WantBlockingErrors then
  352.          if LastError = WSAEWOULDBLOCK then LastError := 0;
  353.    end;
  354.    if LastError = 0 then SetTimeout(FTimeOut);
  355. end;
  356.  
  357. procedure TMSocket.Listen;
  358. begin
  359.    bind(FSocket, Psockaddr(@FAddr), SizeOf(FAddr));
  360.    LastError := WSAGetLastError;
  361.  
  362.    if LastError = 0 then
  363.    begin
  364.       WSAAsyncSelect(FSocket, FHandle, WM_SOCKMSG, FD_ACCEPT);
  365.       FTPSock.listen(FSocket, 2);
  366.       LastError := WSAGetLastError;
  367.    end;
  368. end;
  369.  
  370. procedure TMSocket.Accept;
  371. var
  372.    nl: Integer;
  373. begin
  374.    nl := sizeof(sockaddr_in);
  375.    FSocket := FTPSock.accept(ListeningSocket.Socket, PSockaddr(@FAddr), @nl);
  376.    LastError := WSAGetLastError;
  377.  
  378.    if LastError = 0 then
  379.    begin
  380.       FConnected := True;
  381.       WSAAsyncSelect(FSocket, FHandle, WM_SOCKMSG, FD_CLOSE or FD_READ or FD_WRITE);
  382.    end;
  383. end;
  384.  
  385. procedure TMSocket.Disconnect;
  386. begin
  387.    if ArpHandle <> 0 then WSACancelAsyncRequest(ArpHandle);
  388.    SetTimeout(0);
  389.    if FSocket <> INVALID_SOCKET then
  390.    begin
  391.       WSAAsyncSelect(FSocket, FHandle, WM_SOCKMSG, FD_CLOSE);
  392.       CloseSocket(FSocket);
  393.       LastError := WSAGetLastError;
  394.       FSocket := INVALID_SOCKET;
  395.       FConnected := False;
  396.       Disconnected;
  397.    end;
  398. end;
  399.  
  400. function TMSocket.SendBuf;
  401. var
  402.    n: Integer;
  403. begin
  404.    Result := 0;
  405.    n := send(FSocket, buf, cnt, 0);
  406.    if n > 0 then
  407.    begin
  408.       Result := n;
  409.       LastError := 0;
  410.    end
  411.    else if (n = SOCKET_ERROR) then
  412.    begin
  413.       LastError := WSAGetLastError;
  414.       if not WantBlockingErrors then
  415.          if LastError = WSAEWOULDBLOCK then LastError := 0;
  416.    end;
  417. end;
  418.  
  419. function TMSocket.SendBufOOB;
  420. var
  421.    n: Integer;
  422. begin
  423.    Result := 0;
  424.    n := send(FSocket, buf, cnt, MSG_OOB);
  425.    if n > 0 then
  426.    begin
  427.       Result := n;
  428.       LastError := 0;
  429.    end
  430.    else if (n = SOCKET_ERROR) then
  431.    begin
  432.       LastError := WSAGetLastError;
  433.       if not WantBlockingErrors then
  434.          if LastError = WSAEWOULDBLOCK then LastError := 0;
  435.    end;
  436. end;
  437.  
  438. function TMSocket.RecvBuf;
  439. var
  440.    n: Integer;
  441. begin
  442.    Result := 0;
  443.    n := recv(FSocket, buf, cnt, 0);
  444.    if n > 0 then
  445.    begin
  446.       Result := n;
  447.       LastError := 0;
  448.    end
  449.    else if (n = SOCKET_ERROR) then
  450.    begin
  451.       LastError := WSAGetLastError;
  452.       if not WantBlockingErrors then
  453.          if LastError = WSAEWOULDBLOCK then LastError := 0;
  454.    end;
  455. end;
  456.  
  457. function TMSocket.GetLocalHost;
  458. var
  459.    sh: array [0..255] of Char;
  460. begin
  461.    if gethostname(sh, 255) = 0 then Result := StrPas(sh)
  462.    else Result := '';
  463.    LastError := WSAGetLastError;
  464. end;
  465.  
  466. function TMSocket.GetLocalAddress: String;
  467. var
  468.    sa: sockaddr_in;
  469.    nl: Integer;
  470. begin
  471.    Result := '';
  472.    nl := SizeOf(sa);
  473.    if FSocket = INVALID_SOCKET then exit;
  474.    if geTSocketname(FSocket, PSockaddr(@sa), @nl) = 0 then Result := StrPas(inet_ntoa(sa.sin_addr));
  475.    LastError := WSAGetLastError;
  476. end;
  477.  
  478. function TMSocket.GetLocalPort;
  479. var
  480.    sa: sockaddr_in;
  481.    nl: Integer;
  482. begin
  483.    Result := 0;
  484.    nl := Sizeof(sa);
  485.    if FSocket = INVALID_SOCKET then exit;
  486.    if geTSocketname(FSocket, PSockaddr(@sa), @nl) = 0 then Result := ntohs(sa.sin_port);
  487.    LastError := WSAGetLastError;
  488. end;
  489.  
  490. procedure TMSocket.SetServer;
  491. begin
  492.    FServer := Trim(S);
  493.    if FServer <> '' then
  494.    begin
  495.       if (FServer[1] >= '0') and (FServer[1] <= '9') then
  496.       begin
  497.          Address := FServer;
  498.          Host := '';
  499.       end
  500.       else
  501.       begin
  502.          Host := FServer;
  503.          Address := '';
  504.       end;
  505.    end;
  506. end;
  507.  
  508. end.
  509.