IdStackWindows.pas 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  1. { $HDR$}
  2. {**********************************************************************}
  3. { Unit archived using Team Coherence }
  4. { Team Coherence is Copyright 2002 by Quality Software Components }
  5. { }
  6. { For further information / comments, visit our WEB site at }
  7. { http://www.TeamCoherence.com }
  8. {**********************************************************************}
  9. {}
  10. { $Log: 10349: IdStackWindows.pas
  11. {
  12. Rev 1.3 5/19/2003 5:58:06 PM BGooijen
  13. TIdStackWindows.WSGetHostByAddr raised an ERangeError when the last number in
  14. the ip>127
  15. }
  16. {
  17. Rev 1.2 4/25/2003 7:01:18 PM BGooijen
  18. changed TIdStackWindows.TInAddrToString back
  19. }
  20. {
  21. { Rev 1.1 4/20/03 1:51:46 PM RLebeau
  22. { Updated TInAddrToString() to use inet_ntoa() instead of parsing the values
  23. { manually.
  24. {
  25. { Updated TranslateStringToTInAddr() to use new TIdSTack::GetIPInfo() method.
  26. }
  27. {
  28. { Rev 1.0 2002.11.12 10:53:40 PM czhower
  29. }
  30. unit IdStackWindows;
  31. interface
  32. uses
  33. Classes,
  34. IdStack, IdStackConsts, IdWinsock2, Windows;
  35. type
  36. TIdSocketListWindows = class (TIdSocketList)
  37. protected
  38. FFDSet: TFDSet;
  39. //
  40. function GetItem(AIndex: Integer): TIdStackSocketHandle; override;
  41. public
  42. procedure Add(AHandle: TIdStackSocketHandle); override;
  43. procedure Remove(AHandle: TIdStackSocketHandle); override;
  44. function Count: Integer; override;
  45. End;//TIdSocketList
  46. TIdStackWindows = class(TIdStack)
  47. protected
  48. procedure PopulateLocalAddresses; override;
  49. function WSGetLocalAddress: string; override;
  50. function WSGetLocalAddresses: TStrings; override;
  51. public
  52. constructor Create; override;
  53. destructor Destroy; override;
  54. function TInAddrToString(var AInAddr): string; override;
  55. procedure TranslateStringToTInAddr(AIP: string; var AInAddr); override;
  56. //
  57. function WSAccept(ASocket: TIdStackSocketHandle; var VIP: string; var VPort: Integer)
  58. : TIdStackSocketHandle; override;
  59. function WSBind(ASocket: TIdStackSocketHandle; const AFamily: Integer;
  60. const AIP: string; const APort: Integer): Integer; override;
  61. function WSCloseSocket(ASocket: TIdStackSocketHandle): Integer; override;
  62. function WSConnect(const ASocket: TIdStackSocketHandle; const AFamily: Integer;
  63. const AIP: string; const APort: Integer): Integer; override;
  64. function WSGetHostByAddr(const AAddress: string): string; override;
  65. function WSGetHostByName(const AHostName: string): string; override;
  66. function WSGetHostName: string; override;
  67. function WSGetServByName(const AServiceName: string): Integer; override;
  68. function WSGetServByPort(const APortNumber: Integer): TStrings; override;
  69. procedure WSGetPeerName(ASocket: TIdStackSocketHandle; var VFamily: Integer;
  70. var VIP: string; var VPort: Integer); override;
  71. procedure WSGetSockName(ASocket: TIdStackSocketHandle; var VFamily: Integer;
  72. var VIP: string; var VPort: Integer); override;
  73. function WSHToNs(AHostShort: Word): Word; override;
  74. function WSListen(ASocket: TIdStackSocketHandle; ABackLog: Integer): Integer; override;
  75. function WSNToHs(ANetShort: Word): Word; override;
  76. function WSHToNL(AHostLong: LongWord): LongWord; override;
  77. function WSNToHL(ANetLong: LongWord): LongWord; override;
  78. function WSRecv(ASocket: TIdStackSocketHandle; var ABuffer; const ABufferLength, AFlags: Integer)
  79. : integer; override;
  80. function WSRecvFrom(const ASocket: TIdStackSocketHandle; var ABuffer;
  81. const ALength, AFlags: Integer; var VIP: string; var VPort: Integer): Integer; override;
  82. function WSSelect(ARead, AWrite, AErrors: TList; ATimeout: Integer): Integer; override;
  83. function WSSend(ASocket: TIdStackSocketHandle; var ABuffer;
  84. const ABufferLength, AFlags: Integer): Integer; override;
  85. function WSSendTo(ASocket: TIdStackSocketHandle; var ABuffer;
  86. const ABufferLength, AFlags: Integer; const AIP: string; const APort: integer): Integer;
  87. override;
  88. function WSSetSockOpt(ASocket: TIdStackSocketHandle; ALevel, AOptName: Integer; AOptVal: PChar;
  89. AOptLen: Integer): Integer; override;
  90. function WSSocket(AFamily, AStruct, AProtocol: Integer): TIdStackSocketHandle; override;
  91. function WSShutdown(ASocket: TIdStackSocketHandle; AHow: Integer): Integer; override;
  92. function WSTranslateSocketErrorMsg(const AErr: integer): string; override;
  93. function WSGetLastError: Integer; override;
  94. function WSGetSockOpt(ASocket: TIdStackSocketHandle; Alevel, AOptname: Integer; AOptval: PChar; var AOptlen: Integer): Integer; override;
  95. end;
  96. TLinger = record
  97. l_onoff: Word;
  98. l_linger: Word;
  99. end;
  100. TIdLinger = TLinger;
  101. implementation
  102. uses
  103. IdException,
  104. IdGlobal, IdResourceStrings,
  105. SysUtils;
  106. var
  107. GStarted: Boolean = False;
  108. constructor TIdStackWindows.Create;
  109. var
  110. sData: TWSAData;
  111. begin
  112. inherited Create;
  113. if not GStarted then
  114. begin
  115. if WSAStartup($202, sData) = SOCKET_ERROR then begin
  116. raise EIdStackInitializationFailed.Create(RSWinsockInitializationError);
  117. end;
  118. GStarted := True;
  119. end;
  120. end;
  121. destructor TIdStackWindows.Destroy;
  122. begin
  123. //DLL Unloading and Cleanup is done at finalization
  124. inherited Destroy;
  125. end;
  126. //function TIdStackWindows.TInAddrToString(AInAddr: TInAddr): string;
  127. function TIdStackWindows.TInAddrToString(var AInAddr): string;
  128. begin
  129. with TInAddr(AInAddr).S_un_b do begin
  130. result := IntToStr(s_b1) + '.' + IntToStr(s_b2) + '.' + IntToStr(s_b3) + '.' {Do not Localize}
  131. + IntToStr(s_b4);
  132. end;
  133. // RL: 4/13/2003
  134. // Result := inet_ntoa(TInAddr(AInAddr)); //BGO: Causes socket error 0
  135. end;
  136. function TIdStackWindows.WSAccept(ASocket: TIdStackSocketHandle;
  137. var VIP: string; var VPort: Integer): TIdStackSocketHandle;
  138. var
  139. i: Integer;
  140. Addr: TSockAddr;
  141. begin
  142. i := SizeOf(addr);
  143. result := Accept(ASocket, @addr, @i);
  144. VIP := TInAddrToString(Addr.sin_addr);
  145. VPort := NToHs(Addr.sin_port);
  146. end;
  147. function TIdStackWindows.WSBind(ASocket: TIdStackSocketHandle;
  148. const AFamily: Integer; const AIP: string;
  149. const APort: Integer): Integer;
  150. var
  151. Addr: TSockAddrIn;
  152. begin
  153. Addr.sin_family := AFamily;
  154. if length(AIP) = 0 then begin
  155. Addr.sin_addr.s_addr := INADDR_ANY;
  156. end else begin
  157. Addr.sin_addr := TInAddr(StringToTInAddr(AIP));
  158. end;
  159. Addr.sin_port := HToNS(APort);
  160. result := Bind(ASocket, @addr, SizeOf(Addr));
  161. end;
  162. function TIdStackWindows.WSCloseSocket(ASocket: TIdStackSocketHandle): Integer;
  163. begin
  164. result := CloseSocket(ASocket);
  165. end;
  166. function TIdStackWindows.WSConnect(const ASocket: TIdStackSocketHandle;
  167. const AFamily: Integer; const AIP: string;
  168. const APort: Integer): Integer;
  169. var
  170. Addr: TSockAddrIn;
  171. begin
  172. Addr.sin_family := AFamily;
  173. Addr.sin_addr := TInAddr(StringToTInAddr(AIP));
  174. Addr.sin_port := HToNS(APort);
  175. result := Connect(ASocket, @Addr, SizeOf(Addr));
  176. end;
  177. function TIdStackWindows.WSGetHostByName(const AHostName: string): string;
  178. var
  179. pa: PChar;
  180. sa: TInAddr;
  181. Host: PHostEnt;
  182. begin
  183. Host := GetHostByName(PChar(AHostName));
  184. if Host = nil then begin
  185. CheckForSocketError(SOCKET_ERROR);
  186. end else begin
  187. pa := Host^.h_address_list^;
  188. sa.S_un_b.s_b1 := Ord(pa[0]);
  189. sa.S_un_b.s_b2 := Ord(pa[1]);
  190. sa.S_un_b.s_b3 := Ord(pa[2]);
  191. sa.S_un_b.s_b4 := Ord(pa[3]);
  192. result := TInAddrToString(sa);
  193. end;
  194. end;
  195. function TIdStackWindows.WSGetHostByAddr(const AAddress: string): string;
  196. var
  197. Host: PHostEnt;
  198. LAddr: u_long;
  199. begin
  200. LAddr := inet_addr(PChar(AAddress));
  201. Host := GetHostByAddr(@LAddr, SizeOf(LAddr), AF_INET);
  202. if Host = nil then begin
  203. CheckForSocketError(SOCKET_ERROR);
  204. end else begin
  205. result := Host^.h_name;
  206. end;
  207. end;
  208. function TIdStackWindows.WSGetHostName: string;
  209. begin
  210. SetLength(result, 250);
  211. GetHostName(PChar(result), Length(result));
  212. Result := String(PChar(result));
  213. end;
  214. function TIdStackWindows.WSListen(ASocket: TIdStackSocketHandle;
  215. ABackLog: Integer): Integer;
  216. begin
  217. result := Listen(ASocket, ABacklog);
  218. end;
  219. function TIdStackWindows.WSRecv(ASocket: TIdStackSocketHandle; var ABuffer;
  220. const ABufferLength, AFlags: Integer) : Integer;
  221. begin
  222. result := Recv(ASocket, ABuffer, ABufferLength, AFlags);
  223. end;
  224. function TIdStackWindows.WSRecvFrom(const ASocket: TIdStackSocketHandle;
  225. var ABuffer; const ALength, AFlags: Integer; var VIP: string;
  226. var VPort: Integer): Integer;
  227. var
  228. iSize: integer;
  229. Addr: TSockAddrIn;
  230. begin
  231. iSize := SizeOf(Addr);
  232. result := RecvFrom(ASocket, ABuffer, ALength, AFlags, @Addr, @iSize);
  233. VIP := TInAddrToString(Addr.sin_addr);
  234. VPort := NToHs(Addr.sin_port);
  235. end;
  236. function TIdStackWindows.WSSelect(ARead, AWrite, AErrors: TList; ATimeout: Integer): Integer;
  237. var
  238. tmTo: TTimeVal;
  239. FDRead, FDWrite, FDError: TFDSet;
  240. procedure GetFDSet(AList: TList; var ASet: TFDSet);
  241. var
  242. i: Integer;
  243. begin
  244. if assigned( AList ) then begin
  245. AList.Clear; // SG 18/10/00: ALWAYS clear the result list
  246. AList.Capacity := ASet.fd_count;
  247. for i := 0 to ASet.fd_count - 1 do begin
  248. AList.Add(TObject(ASet.fd_array[i]));
  249. end;
  250. end;
  251. end;
  252. procedure SetFDSet(AList: TList; var ASet: TFDSet);
  253. var
  254. i: integer;
  255. begin
  256. if AList <> nil then begin
  257. if AList.Count > FD_SETSIZE then begin
  258. raise EIdStackSetSizeExceeded.Create(RSSetSizeExceeded);
  259. end;
  260. for i := 0 to AList.Count - 1 do begin
  261. ASet.fd_array[i] := TIdStackSocketHandle(AList[i]);
  262. end;
  263. ASet.fd_count := AList.Count;
  264. end;
  265. end;
  266. begin
  267. FillChar(FDRead, SizeOf(FDRead), 0);
  268. FillChar(FDWrite, SizeOf(FDWrite), 0);
  269. FillChar(FDError, SizeOf(FDError), 0);
  270. SetFDSet(ARead, FDRead);
  271. SetFDSet(AWrite, FDWrite);
  272. SetFDSet(AErrors, FDError);
  273. if ATimeout = IdTimeoutInfinite then begin
  274. Result := Select(0, @FDRead, @FDWrite, @FDError, nil);
  275. end else begin
  276. tmTo.tv_sec := ATimeout div 1000;
  277. tmTo.tv_usec := (ATimeout mod 1000) * 1000;
  278. Result := Select(0, @FDRead, @FDWrite, @FDError, @tmTO);
  279. end;
  280. GetFDSet(ARead, FDRead);
  281. GetFDSet(AWrite, FDWrite);
  282. GetFDSet(AErrors, FDError);
  283. end;
  284. function TIdStackWindows.WSSend(ASocket: TIdStackSocketHandle;
  285. var ABuffer; const ABufferLength, AFlags: Integer): Integer;
  286. begin
  287. result := Send(ASocket, ABuffer, ABufferLength, AFlags);
  288. end;
  289. function TIdStackWindows.WSSendTo(ASocket: TIdStackSocketHandle;
  290. var ABuffer; const ABufferLength, AFlags: Integer; const AIP: string;
  291. const APort: integer): Integer;
  292. var
  293. Addr: TSockAddrIn;
  294. begin
  295. FillChar(Addr, SizeOf(Addr), 0);
  296. with Addr do
  297. begin
  298. sin_family := Id_PF_INET;
  299. sin_addr := TInAddr(StringToTInAddr(AIP));
  300. sin_port := HToNs(APort);
  301. end;
  302. result := SendTo(ASocket, ABuffer, ABufferLength, AFlags, @Addr, SizeOf(Addr));
  303. end;
  304. function TIdStackWindows.WSSetSockOpt(ASocket: TIdStackSocketHandle;
  305. ALevel, AOptName: Integer; AOptVal: PChar; AOptLen: Integer): Integer;
  306. begin
  307. result := SetSockOpt(ASocket, ALevel, AOptName, AOptVal, AOptLen);
  308. end;
  309. function TIdStackWindows.WSGetLocalAddresses: TStrings;
  310. begin
  311. if FLocalAddresses = nil then
  312. begin
  313. FLocalAddresses := TStringList.Create;
  314. end;
  315. PopulateLocalAddresses;
  316. Result := FLocalAddresses;
  317. end;
  318. function TIdStackWindows.WSGetLastError: Integer;
  319. begin
  320. result := WSAGetLastError;
  321. end;
  322. function TIdStackWindows.WSSocket(AFamily, AStruct, AProtocol: Integer): TIdStackSocketHandle;
  323. begin
  324. result := Socket(AFamily, AStruct, AProtocol);
  325. end;
  326. function TIdStackWindows.WSHToNs(AHostShort: Word): Word;
  327. begin
  328. result := HToNs(AHostShort);
  329. end;
  330. function TIdStackWindows.WSNToHs(ANetShort: Word): Word;
  331. begin
  332. result := NToHs(ANetShort);
  333. end;
  334. function TIdStackWindows.WSGetServByName(const AServiceName: string): Integer;
  335. var
  336. ps: PServEnt;
  337. begin
  338. ps := GetServByName(PChar(AServiceName), nil);
  339. if ps <> nil then
  340. begin
  341. Result := Ntohs(ps^.s_port);
  342. end
  343. else
  344. begin
  345. try
  346. Result := StrToInt(AServiceName);
  347. except
  348. on EConvertError do raise EIdInvalidServiceName.CreateFmt(RSInvalidServiceName, [AServiceName]);
  349. end;
  350. end;
  351. end;
  352. function TIdStackWindows.WSGetServByPort(
  353. const APortNumber: Integer): TStrings;
  354. var
  355. ps: PServEnt;
  356. i: integer;
  357. p: array of PChar;
  358. begin
  359. Result := TStringList.Create;
  360. p := nil;
  361. try
  362. ps := GetServByPort(HToNs(APortNumber), nil);
  363. if ps <> nil then
  364. begin
  365. Result.Add(ps^.s_name);
  366. i := 0;
  367. p := pointer(ps^.s_aliases);
  368. while p[i] <> nil do
  369. begin
  370. Result.Add(PChar(p[i]));
  371. inc(i);
  372. end;
  373. end;
  374. except
  375. Result.Free;
  376. Result := nil;
  377. end;
  378. end;
  379. function TIdStackWindows.WSHToNL(AHostLong: LongWord): LongWord;
  380. begin
  381. Result := HToNL(AHostLong);
  382. end;
  383. function TIdStackWindows.WSNToHL(ANetLong: LongWord): LongWord;
  384. begin
  385. Result := NToHL(ANetLong);
  386. end;
  387. procedure TIdStackWindows.PopulateLocalAddresses;
  388. type
  389. TaPInAddr = Array[0..250] of PInAddr;
  390. PaPInAddr = ^TaPInAddr;
  391. var
  392. i: integer;
  393. AHost: PHostEnt;
  394. PAdrPtr: PaPInAddr;
  395. begin
  396. FLocalAddresses.Clear ;
  397. AHost := GetHostByName(PChar(WSGetHostName));
  398. if AHost = nil then
  399. begin
  400. CheckForSocketError(SOCKET_ERROR);
  401. end
  402. else
  403. begin
  404. PAdrPtr := PAPInAddr(AHost^.h_address_list);
  405. i := 0;
  406. while PAdrPtr^[i] <> nil do
  407. begin
  408. FLocalAddresses.Add(TInAddrToString(PAdrPtr^[I]^));
  409. Inc(I);
  410. end;
  411. end;
  412. end;
  413. function TIdStackWindows.WSGetLocalAddress: string;
  414. begin
  415. Result := LocalAddresses[0];
  416. end;
  417. { TIdStackVersionWinsock }
  418. function ServeFile(ASocket: TIdStackSocketHandle; AFileName: string): cardinal;
  419. var
  420. LFileHandle: THandle;
  421. begin
  422. result := 0;
  423. LFileHandle := CreateFile(PChar(AFileName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING
  424. , FILE_ATTRIBUTE_NORMAL or FILE_FLAG_SEQUENTIAL_SCAN, 0); try
  425. if TransmitFile(ASocket, LFileHandle, 0, 0, nil, nil, 0) then begin
  426. result := getFileSize(LFileHandle, nil);
  427. end;
  428. finally CloseHandle(LFileHandle); end;
  429. end;
  430. procedure TIdStackWindows.TranslateStringToTInAddr(AIP: string; var AInAddr);
  431. begin
  432. with TInAddr(AInAddr).S_un_b do
  433. begin
  434. if not GetIPInfo(AIP, @s_b1, @s_b2, @s_b3, @s_b4) then
  435. begin
  436. raise EIdInvalidIPAddress.CreateFmt(RSStackInvalidIP, [AIP]);
  437. end;
  438. end;
  439. end;
  440. function TIdStackWindows.WSShutdown(ASocket: TIdStackSocketHandle; AHow: Integer): Integer;
  441. begin
  442. result := Shutdown(ASocket, AHow);
  443. end;
  444. procedure TIdStackWindows.WSGetPeerName(ASocket: TIdStackSocketHandle;
  445. var VFamily: Integer; var VIP: string; var VPort: Integer);
  446. var
  447. i: Integer;
  448. LAddr: TSockAddrIn;
  449. begin
  450. i := SizeOf(LAddr);
  451. CheckForSocketError(GetPeerName(ASocket, @LAddr, i));
  452. VFamily := LAddr.sin_family;
  453. VIP := TInAddrToString(LAddr.sin_addr);
  454. VPort := Ntohs(LAddr.sin_port);
  455. end;
  456. procedure TIdStackWindows.WSGetSockName(ASocket: TIdStackSocketHandle;
  457. var VFamily: Integer; var VIP: string; var VPort: Integer);
  458. var
  459. i: Integer;
  460. LAddr: TSockAddrIn;
  461. begin
  462. i := SizeOf(LAddr);
  463. CheckForSocketError(GetSockName(ASocket, @LAddr, i));
  464. VFamily := LAddr.sin_family;
  465. VIP := TInAddrToString(LAddr.sin_addr);
  466. VPort := Ntohs(LAddr.sin_port);
  467. end;
  468. function TIdStackWindows.WSGetSockOpt(ASocket: TIdStackSocketHandle; Alevel, AOptname: Integer; AOptval: PChar; var AOptlen: Integer): Integer;
  469. begin
  470. Result := GetSockOpt(ASocket, ALevel, AOptname, AOptval, AOptlen);
  471. end;
  472. { TIdSocketListWindows }
  473. procedure TIdSocketListWindows.Add(AHandle: TIdStackSocketHandle);
  474. Begin
  475. if FFDSet.fd_count >= FD_SETSIZE then begin
  476. raise EIdStackSetSizeExceeded.Create(RSSetSizeExceeded);
  477. end;
  478. FFDSet.fd_array[FFDSet.fd_count] := AHandle;
  479. inc(FFDSet.fd_count);
  480. End;//
  481. function TIdSocketListWindows.Count: Integer;
  482. Begin
  483. Result := FFDSet.fd_count;
  484. End;
  485. function TIdSocketListWindows.GetItem(AIndex: Integer): TIdStackSocketHandle;
  486. Begin
  487. if (AIndex>=0) and (AIndex<FFDSet.fd_count) then begin
  488. Result := FFDSet.fd_array[AIndex];
  489. end else begin
  490. raise EIdStackSetSizeExceeded.Create(RSSetSizeExceeded);
  491. end;
  492. End;//
  493. procedure TIdSocketListWindows.Remove(AHandle: TIdStackSocketHandle);
  494. var
  495. i: Integer;
  496. Begin
  497. for i:=0 to FFDSet.fd_count-1 do begin
  498. if FFDSet.fd_array[i] = AHandle then begin
  499. dec(FFDSet.fd_count);
  500. FFDSet.fd_array[i] := FFDSet.fd_array[FFDSet.fd_count];
  501. FFDSet.fd_array[FFDSet.fd_count] := 0; //extra purity
  502. Break;
  503. end;//if found
  504. end;
  505. End;//
  506. function TIdStackWindows.WSTranslateSocketErrorMsg(const AErr: integer): string;
  507. Begin
  508. case AErr of
  509. wsahost_not_found: Result := RSStackHOST_NOT_FOUND;
  510. else
  511. Result := inherited WSTranslateSocketErrorMsg(AErr);
  512. EXIT;
  513. end;
  514. Result := Format(RSStackError, [AErr, Result]);
  515. End;//
  516. initialization
  517. GSocketListClass := TIdSocketListWindows;
  518. // Check if we are running under windows NT
  519. if (SysUtils.Win32Platform = VER_PLATFORM_WIN32_NT) then begin
  520. GServeFileProc := ServeFile;
  521. end;
  522. finalization
  523. if GStarted then begin
  524. WSACleanup;
  525. end;
  526. end.