lcommon.pp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536
  1. { lCommon
  2. CopyRight (C) 2004-2008 Ales Katona
  3. This library is Free software; you can rediStribute it and/or modify it
  4. under the terms of the GNU Library General Public License as published by
  5. the Free Software Foundation; either version 2 of the License, or (at your
  6. option) any later version.
  7. This program is diStributed in the hope that it will be useful, but WITHOUT
  8. ANY WARRANTY; withOut even the implied warranty of MERCHANTABILITY or
  9. FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
  10. for more details.
  11. You should have received a Copy of the GNU Library General Public License
  12. along with This library; if not, Write to the Free Software Foundation,
  13. Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  14. This license has been modified. See File LICENSE.ADDON for more inFormation.
  15. Should you find these sources without a LICENSE File, please contact
  16. me at [email protected]
  17. }
  18. unit lCommon;
  19. {$mode objfpc}{$H+}
  20. {$inline on}
  21. interface
  22. uses
  23. {$i sys/osunits.inc}
  24. const
  25. {$IFDEF WINDOWS}
  26. SOL_SOCKET = $ffff;
  27. LMSG = 0;
  28. SOCKET_ERROR = WinSock2.SOCKET_ERROR;
  29. SHUT_RDWR = SD_BOTH;
  30. SHUT_WR = SD_SEND;
  31. {$ENDIF}
  32. {$IFDEF OS2}
  33. SOL_SOCKET = WinSock.SOL_SOCKET;
  34. LMSG = 0;
  35. SOCKET_ERROR = WinSock.SOCKET_ERROR;
  36. {$ENDIF}
  37. {$IFDEF NETWARE}
  38. SOL_SOCKET = WinSock.SOL_SOCKET;
  39. LMSG = 0;
  40. SOCKET_ERROR = WinSock.SOCKET_ERROR;
  41. {$ENDIF}
  42. {$IFDEF UNIX}
  43. INVALID_SOCKET = -1;
  44. SOCKET_ERROR = -1;
  45. {$IFDEF LINUX} // TODO: fix this crap, some don't even have MSG_NOSIGNAL
  46. LMSG = MSG_NOSIGNAL;
  47. {$ELSE}
  48. {$IFDEF FREEBSD}
  49. LMSG = $20000; // FPC BUG in 2.0.4-, freeBSD value
  50. {$ELSE}
  51. LMSG = 0;
  52. {$ENDIF}
  53. {$ENDIF}
  54. {$IFDEF DARWIN}
  55. SO_NOSIGPIPE = $1022; // for fpc 2.0.4
  56. {$ENDIF}
  57. {$ENDIF}
  58. { Default Values }
  59. LDEFAULT_BACKLOG = 5;
  60. BUFFER_SIZE = 262144;
  61. { Net types }
  62. LAF_INET = AF_INET;
  63. LAF_INET6 = AF_INET6;
  64. { Address constants }
  65. LADDR_ANY = '0.0.0.0';
  66. LADDR_BR = '255.255.255.255';
  67. LADDR_LO = '127.0.0.1';
  68. LADDR6_ANY = '::0';
  69. LADDR6_LO = '::1';
  70. { ICMP }
  71. LICMP_ECHOREPLY = 0;
  72. LICMP_UNREACH = 3;
  73. LICMP_ECHO = 8;
  74. LICMP_TIME_EXCEEDED = 11;
  75. { Protocols }
  76. LPROTO_IP = 0;
  77. LPROTO_ICMP = 1;
  78. LPROTO_IGMP = 2;
  79. LPROTO_TCP = 6;
  80. LPROTO_UDP = 17;
  81. LPROTO_IPV6 = 41;
  82. LPROTO_ICMPV6 = 58;
  83. LPROTO_RAW = 255;
  84. LPROTO_MAX = 256;
  85. type
  86. { TLSocketAddress }
  87. TLSocketAddress = record
  88. case Integer of
  89. LAF_INET : (IPv4: TInetSockAddr);
  90. LAF_INET6 : (IPv6: TInetSockAddr6);
  91. end;
  92. { Base functions }
  93. {$IFNDEF UNIX}
  94. function fpSelect(const nfds: Integer; const readfds, writefds, exceptfds: PFDSet;
  95. const timeout: PTimeVal): Integer; inline;
  96. function fpFD_ISSET(const Socket: Integer; var FDSet: TFDSet): Integer; inline;
  97. procedure fpFD_SET(const Socket: Integer; var FDSet: TFDSet); inline;
  98. procedure fpFD_ZERO(var FDSet: TFDSet); inline;
  99. {$ENDIF}
  100. { DNS }
  101. function GetHostName(const Address: string): string;
  102. function GetHostIP(const Name: string): string;
  103. function GetHostName6(const Address: string): string;
  104. function GetHostIP6(const Name: string): string;
  105. function LStrError(const Ernum: Longint; const UseUTF8: Boolean = False): string;
  106. function LSocketError: Longint;
  107. function SetBlocking(const aHandle: Integer; const aValue: Boolean): Boolean;
  108. // function SetNoDelay(const aHandle: Integer; const aValue: Boolean): Boolean;
  109. function IsBlockError(const anError: Integer): Boolean; inline;
  110. function IsNonFatalError(const anError: Integer): Boolean; inline;
  111. function IsPipeError(const anError: Integer): Boolean; inline;
  112. function TZSeconds: Integer; inline;
  113. function StrToHostAddr(const IP: string): Cardinal; inline;
  114. function HostAddrToStr(const Entry: Cardinal): string; inline;
  115. function StrToNetAddr(const IP: string): Cardinal; inline;
  116. function NetAddrToStr(const Entry: Cardinal): string; inline;
  117. procedure FillAddressInfo(var aAddrInfo: TLSocketAddress; const aFamily: sa_family_t;
  118. const Address: string; const aPort: Word);
  119. implementation
  120. uses
  121. StrUtils
  122. {$IFNDEF UNIX}
  123. {$IFDEF WINDOWS}
  124. , Windows, lws2tcpip;
  125. {$IFDEF WINCE}
  126. function LStrError(const Ernum: Longint; const UseUTF8: Boolean = False): string;
  127. const
  128. MAX_ERROR = 1024;
  129. var
  130. Tmp: string;
  131. TmpW: widestring;
  132. begin
  133. Result := '[' + IntToStr(Ernum) + '] ';
  134. SetLength(TmpW, MAX_ERROR);
  135. SetLength(TmpW, FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM or
  136. FORMAT_MESSAGE_IGNORE_INSERTS or
  137. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  138. nil, Ernum, 0, @TmpW[1], MAX_ERROR, nil));
  139. Tmp := UTF8Encode(TmpW);
  140. if Length(Tmp) > 2 then
  141. Delete(Tmp, Length(Tmp)-1, 2);
  142. Result := Tmp;
  143. end;
  144. {$ELSE} // any other windows
  145. function LStrError(const Ernum: Longint; const UseUTF8: Boolean = False): string;
  146. const
  147. MAX_ERROR = 1024;
  148. var
  149. Tmp: string;
  150. TmpW: widestring;
  151. begin
  152. Result := ' [' + IntToStr(Ernum) + ']: ';
  153. if USEUtf8 then begin
  154. SetLength(TmpW, MAX_ERROR);
  155. SetLength(TmpW, FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM or
  156. FORMAT_MESSAGE_IGNORE_INSERTS or
  157. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  158. nil, Ernum, 0, @TmpW[1], MAX_ERROR, nil));
  159. Tmp := UTF8Encode(TmpW);
  160. end else begin
  161. SetLength(Tmp, MAX_ERROR);
  162. SetLength(Tmp, FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM or
  163. FORMAT_MESSAGE_IGNORE_INSERTS or
  164. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  165. nil, Ernum, 0, @Tmp[1], MAX_ERROR, nil));
  166. end;
  167. if Length(Tmp) > 2 then
  168. Delete(Tmp, Length(Tmp)-1, 2);
  169. Result := Result + Tmp;
  170. end;
  171. {$ENDIF}
  172. function TZSeconds: integer; inline;
  173. var
  174. lInfo: Windows.TIME_ZONE_INFORMATION;
  175. begin
  176. { lInfo.Bias is in minutes }
  177. if Windows.GetTimeZoneInformation(@lInfo) <> $FFFFFFFF then
  178. Result := lInfo.Bias * 60
  179. else
  180. Result := 0;
  181. end;
  182. {$ELSE}
  183. ; // uses
  184. function LStrError(const Ernum: Longint; const UseUTF8: Boolean = False): string;
  185. begin
  186. Result := IntToStr(Ernum); // TODO: fix for non-windows winsock users
  187. end;
  188. function TZSeconds: integer; inline;
  189. begin
  190. Result := 0; // todo: fix for non-windows non unix
  191. end;
  192. {$ENDIF}
  193. function LSocketError: Longint;
  194. begin
  195. Result := WSAGetLastError;
  196. end;
  197. function CleanError(const Ernum: Longint): Byte;
  198. begin
  199. Result := Byte(Ernum - 10000);
  200. end;
  201. function fpSelect(const nfds: Integer; const readfds, writefds, exceptfds: PFDSet;
  202. const timeout: PTimeVal): Longint; inline;
  203. begin
  204. Result := Select(nfds, readfds, writefds, exceptfds, timeout);
  205. end;
  206. function fpFD_ISSET(const Socket: Longint; var FDSet: TFDSet): Integer; inline;
  207. begin
  208. Result := 0;
  209. if FD_ISSET(Socket, FDSet) then
  210. Result := 1;
  211. end;
  212. procedure fpFD_SET(const Socket: Longint; var FDSet: TFDSet); inline;
  213. begin
  214. FD_SET(Socket, FDSet);
  215. end;
  216. procedure fpFD_ZERO(var FDSet: TFDSet); inline;
  217. begin
  218. FD_ZERO(FDSet);
  219. end;
  220. function GetHostName(const Address: string): string;
  221. var
  222. HE: PHostEnt;
  223. Addr: DWord;
  224. begin
  225. Result := '';
  226. HE := nil;
  227. Addr := inet_addr(PChar(Address));
  228. HE := gethostbyaddr(@Addr, SizeOf(Addr), AF_INET);
  229. if Assigned(HE) then
  230. Result := HE^.h_name;
  231. end;
  232. function GetHostIP(const Name: string): string;
  233. var
  234. HE: PHostEnt;
  235. P: PDWord;
  236. begin
  237. Result := '';
  238. HE := nil;
  239. HE := gethostbyname(PChar(Name));
  240. if Assigned(HE) then begin
  241. P := Pointer(HE^.h_addr_list[0]);
  242. Result := NetAddrToStr(P^);
  243. end;
  244. end;
  245. function GetHostName6(const Address: string): string;
  246. var
  247. H: TAddrInfo;
  248. R: PAddrInfo;
  249. n: Integer;
  250. begin
  251. Result := '';
  252. ZeroMemory(@H, SizeOf(H));
  253. H.ai_flags := AI_NUMERICHOST;
  254. H.ai_family := AF_INET6;
  255. H.ai_protocol := PF_INET6;
  256. H.ai_socktype := SOCK_STREAM;
  257. n := getaddrinfo(pChar(Address), nil, @H, R);
  258. if n <> 0 then
  259. Exit;
  260. Result := R^.ai_canonname;
  261. freeaddrinfo(R);
  262. end;
  263. function GetHostIP6(const Name: string): string;
  264. var
  265. H: TAddrInfo;
  266. R: PAddrInfo;
  267. n: Integer;
  268. begin
  269. Result := '';
  270. ZeroMemory(@H, SizeOf(H));
  271. H.ai_family := AF_INET6;
  272. H.ai_protocol := PF_INET6;
  273. H.ai_socktype := SOCK_STREAM;
  274. n := getaddrinfo(pChar(Name), nil, @H, R);
  275. if n <> 0 then
  276. Exit;
  277. Result := NetAddrToStr6(sockets.in6_addr(R^.ai_addr^));
  278. freeaddrinfo(R);
  279. end;
  280. function SetBlocking(const aHandle: Integer; const aValue: Boolean): Boolean;
  281. const
  282. BlockAr: array[Boolean] of DWord = (1, 0);
  283. var
  284. opt: DWord;
  285. begin
  286. opt := BlockAr[aValue];
  287. if ioctlsocket(aHandle, Longint(FIONBIO), opt) = SOCKET_ERROR then
  288. Exit(False);
  289. Result := True;
  290. end;
  291. function IsBlockError(const anError: Integer): Boolean; inline;
  292. begin
  293. Result := anError = WSAEWOULDBLOCK;
  294. end;
  295. function IsNonFatalError(const anError: Integer): Boolean; inline;
  296. begin
  297. Result := (anError = WSAEINVAL) or (anError = WSAEFAULT)
  298. or (anError = WSAEOPNOTSUPP) or (anError = WSAEMSGSIZE)
  299. or (anError = WSAEADDRNOTAVAIL) or (anError = WSAEAFNOSUPPORT)
  300. or (anError = WSAEDESTADDRREQ);
  301. end;
  302. function IsPipeError(const anError: Integer): Boolean; inline;
  303. begin
  304. {$WARNING check these ambiguous errors}
  305. Result := anError = WSAECONNRESET;
  306. end;
  307. {$ELSE}
  308. // unix
  309. ,Errors, Unix;
  310. function LStrError(const Ernum: Longint; const UseUTF8: Boolean = False): string;
  311. begin
  312. Result := ' [' + IntToStr(Ernum) + ']: ' + Errors.StrError(Ernum);
  313. end;
  314. function LSocketError: Longint;
  315. begin
  316. Result := fpgeterrno;
  317. end;
  318. function CleanError(const Ernum: Longint): Longint; inline;
  319. begin
  320. Result := Byte(Ernum);
  321. end;
  322. function GetHostName(const Address: string): string;
  323. var
  324. HE: THostEntry;
  325. begin
  326. Result := '';
  327. if GetHostbyAddr(in_addr(StrToHostAddr(Address)), HE) then
  328. Result := HE.Name
  329. else if ResolveHostbyAddr(in_addr(StrToHostAddr(Address)), HE) then
  330. Result := HE.Name;
  331. end;
  332. function GetHostIP(const Name: string): string;
  333. var
  334. HE: THostEntry;
  335. begin
  336. Result := '';
  337. if GetHostByName(Name, HE) then
  338. Result := HostAddrToStr(Cardinal(HE.Addr)) // for localhost
  339. else if ResolveHostByName(Name, HE) then
  340. Result := NetAddrToStr(Cardinal(HE.Addr));
  341. end;
  342. function GetHostName6(const Address: string): string;
  343. var
  344. HE: THostEntry6;
  345. begin
  346. Result := '';
  347. { if GetHostByAddr(StrToHostAddr6(Address), HE) then
  348. Result := HE.Name
  349. else} if ResolveHostbyAddr6(StrToHostAddr6(Address), HE) then
  350. Result := HE.Name;
  351. end;
  352. function GetHostIP6(const Name: string): string;
  353. var
  354. HE: THostEntry6;
  355. begin
  356. Result := '';
  357. { if GetHostByName(Name, HE) then
  358. Result := HostAddrToStr6(HE.Addr) // for localhost
  359. else} if ResolveHostByName6(Name, HE) then
  360. Result := NetAddrToStr6(HE.Addr);
  361. end;
  362. function SetBlocking(const aHandle: Integer; const aValue: Boolean): Boolean;
  363. var
  364. opt: cInt;
  365. begin
  366. opt := fpfcntl(aHandle, F_GETFL);
  367. if opt = SOCKET_ERROR then
  368. Exit(False);
  369. if aValue then
  370. opt := opt and not O_NONBLOCK
  371. else
  372. opt := opt or O_NONBLOCK;
  373. if fpfcntl(aHandle, F_SETFL, opt) = SOCKET_ERROR then
  374. Exit(False);
  375. Result := True;
  376. end;
  377. function IsBlockError(const anError: Integer): Boolean; inline;
  378. begin
  379. Result := (anError = ESysEWOULDBLOCK) or (anError = ESysENOBUFS);
  380. end;
  381. function IsNonFatalError(const anError: Integer): Boolean; inline;
  382. begin
  383. Result := (anError = ESysEINTR) or (anError = ESysEMSGSIZE)
  384. or (anError = ESysEFAULT) or (anError = ESysEINVAL)
  385. or (anError = ESysEOPNOTSUPP);
  386. end;
  387. function IsPipeError(const anError: Integer): Boolean; inline;
  388. begin
  389. Result := anError = ESysEPIPE;
  390. end;
  391. function TZSeconds: Integer; inline;
  392. begin
  393. Result := unix.TZSeconds;
  394. end;
  395. {$ENDIF}
  396. {function SetNoDelay(const aHandle: Integer; const aValue: Boolean): Boolean;
  397. var
  398. opt: cInt = 0;
  399. begin
  400. if aValue then
  401. opt := 1;
  402. if fpsetsockopt(aHandle, IPPROTO_TCP, TCP_NODELAY, opt, SizeOf(opt)) < 0 then
  403. Exit(False);
  404. Result := True;
  405. end;}
  406. function StrToHostAddr(const IP: string): Cardinal; inline;
  407. begin
  408. Result := Cardinal(Sockets.StrToHostAddr(IP));
  409. end;
  410. function HostAddrToStr(const Entry: Cardinal): string; inline;
  411. begin
  412. Result := Sockets.HostAddrToStr(in_addr(Entry));
  413. end;
  414. function StrToNetAddr(const IP: string): Cardinal; inline;
  415. begin
  416. Result := Cardinal(Sockets.StrToNetAddr(IP));
  417. end;
  418. function NetAddrToStr(const Entry: Cardinal): string; inline;
  419. begin
  420. Result := Sockets.NetAddrToStr(in_addr(Entry));
  421. end;
  422. function IsIP6Empty(const aIP6: TInetSockAddr6): Boolean; inline;
  423. var
  424. i: Integer;
  425. begin
  426. Result := True;
  427. for i := 0 to High(aIP6.sin6_addr.u6_addr32) do
  428. if aIP6.sin6_addr.u6_addr32[i] <> 0 then
  429. Exit(False);
  430. end;
  431. procedure FillAddressInfo(var aAddrInfo: TLSocketAddress; const aFamily: sa_family_t;
  432. const Address: string; const aPort: Word);
  433. begin
  434. aAddrInfo.IPv4.sin_family := aFamily;
  435. aAddrInfo.IPv4.sin_Port := htons(aPort);
  436. case aFamily of
  437. LAF_INET :
  438. begin
  439. aAddrInfo.IPv4.sin_Addr.s_addr := StrToNetAddr(Address);
  440. if (Address <> LADDR_ANY) and (aAddrInfo.IPv4.sin_Addr.s_addr = 0) then
  441. aAddrInfo.IPv4.sin_Addr.s_addr := StrToNetAddr(GetHostIP(Address));
  442. end;
  443. LAF_INET6 :
  444. begin
  445. aAddrInfo.IPv6.sin6_addr := StrToNetAddr6(Address);
  446. if (Address <> LADDR6_ANY) and (IsIP6Empty(aAddrInfo.IPv6)) then
  447. aAddrInfo.IPv6.sin6_addr := StrToNetAddr6(GetHostIP6(Address));
  448. end;
  449. end;
  450. end;
  451. end.