sockets.inc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by the Free Pascal development team
  4. See the file COPYING.FPC, included in this distribution,
  5. for details about the copyright.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. **********************************************************************}
  10. {******************************************************************************
  11. Text File Writeln/ReadLn Support
  12. ******************************************************************************}
  13. Procedure OpenSock(var F:Text);
  14. begin
  15. if textrec(f).handle=UnusedHandle then
  16. textrec(f).mode:=fmclosed
  17. else
  18. case textrec(f).userdata[1] of
  19. S_OUT : textrec(f).mode:=fmoutput;
  20. S_IN : textrec(f).mode:=fminput;
  21. else
  22. textrec(f).mode:=fmclosed;
  23. end;
  24. end;
  25. procedure iosock(var f:text);
  26. var r:sizeint;
  27. def_error:word;
  28. begin
  29. with textrec(f) do
  30. begin
  31. case mode of
  32. fmoutput:
  33. begin
  34. repeat
  35. {$ifdef use_readwrite}
  36. r:=fpwrite(handle,bufptr^,bufpos);
  37. {$else}
  38. r:=fpsend(handle,bufptr,bufpos,0);
  39. {$endif}
  40. until (r<>-1) or (SocketError <> EsockEINTR);
  41. bufend:=r;
  42. def_error:=101; {File write error.}
  43. end;
  44. fminput:
  45. begin
  46. repeat
  47. {$ifdef use_readwrite}
  48. r:=fpread(handle,bufptr^,bufsize);
  49. {$else}
  50. r:=fprecv(handle,bufptr,bufsize,0);
  51. {$endif}
  52. until (r<>-1) or (SocketError <> EsockEINTR);
  53. bufend:=r;
  54. def_error:=100; {File read error.}
  55. end;
  56. end;
  57. if r=-1 then
  58. case SocketError of
  59. EsockEBADF:
  60. { EsysENOTSOCK:} {Why is this constant not defined? (DM)}
  61. inoutres:=6; {Invalid file handle.}
  62. EsockEFAULT:
  63. inoutres:=217;
  64. EsockEINVAL:
  65. inoutres:=218;
  66. else
  67. inoutres:=def_error;
  68. end;
  69. bufpos:=0;
  70. end;
  71. end;
  72. Procedure FlushSock(var F:Text);
  73. begin
  74. if (textrec(f).mode=fmoutput) and (textrec(f).bufpos<>0) then
  75. begin
  76. IOSock(f);
  77. textrec(f).bufpos:=0;
  78. end;
  79. end;
  80. Procedure CloseSock(var F:text);
  81. begin
  82. { Nothing special has to be done here }
  83. end;
  84. Procedure Sock2Text(Sock:Longint;Var SockIn,SockOut:Text);
  85. {
  86. Set up two Pascal Text file descriptors for reading and writing)
  87. }
  88. begin
  89. { First the reading part.}
  90. Assign(SockIn,'.');
  91. Textrec(SockIn).Handle:=Sock;
  92. Textrec(Sockin).userdata[1]:=S_IN;
  93. TextRec(SockIn).OpenFunc:=@OpenSock;
  94. TextRec(SockIn).InOutFunc:=@IOSock;
  95. TextRec(SockIn).FlushFunc:=@FlushSock;
  96. TextRec(SockIn).CloseFunc:=@CloseSock;
  97. TextRec(SockIn).Mode := fmInput;
  98. Case DefaultTextLineBreakStyle Of
  99. tlbsLF: TextRec(sockin).LineEnd := #10;
  100. tlbsCRLF: TextRec(sockin).LineEnd := #13#10;
  101. tlbsCR: TextRec(sockin).LineEnd := #13;
  102. End;
  103. { Now the writing part. }
  104. Assign(SockOut,'.');
  105. Textrec(SockOut).Handle:=Sock;
  106. Textrec(SockOut).userdata[1]:=S_OUT;
  107. TextRec(SockOut).OpenFunc:=@OpenSock;
  108. TextRec(SockOut).InOutFunc:=@IOSock;
  109. TextRec(SockOut).FlushFunc:=@FlushSock;
  110. TextRec(SockOut).CloseFunc:=@CloseSock;
  111. TextRec(SockOut).Mode := fmOutput;
  112. Case DefaultTextLineBreakStyle Of
  113. tlbsLF: TextRec(sockout).LineEnd := #10;
  114. tlbsCRLF: TextRec(sockout).LineEnd := #13#10;
  115. tlbsCR: TextRec(sockout).LineEnd := #13;
  116. End;
  117. end;
  118. {******************************************************************************
  119. Untyped File
  120. ******************************************************************************}
  121. Procedure Sock2File(Sock:Longint;Var SockIn,SockOut:File);
  122. begin
  123. {Input}
  124. Assign(SockIn,'.');
  125. FileRec(SockIn).Handle:=Sock;
  126. FileRec(SockIn).RecSize:=1;
  127. FileRec(Sockin).userdata[1]:=S_IN;
  128. FileRec(SockIn).Mode := fmInput;
  129. {Output}
  130. Assign(SockOut,'.');
  131. FileRec(SockOut).Handle:=Sock;
  132. FileRec(SockOut).RecSize:=1;
  133. FileRec(SockOut).userdata[1]:=S_OUT;
  134. FileRec(SockOut).Mode := fmOutput;
  135. end;
  136. {******************************************************************************
  137. InetSock
  138. ******************************************************************************}
  139. Function DoAccept(Sock:longint;Var addr:TInetSockAddr):longint;
  140. Var AddrLen : Longint;
  141. begin
  142. AddrLEn:=SizeOf(Addr);
  143. repeat
  144. DoAccept:=fpaccept(Sock,@Addr,@AddrLen);
  145. until (DoAccept<>-1) or (SocketError <> EsockEINTR);
  146. end;
  147. Function DoConnect(Sock:longint;const addr: TInetSockAddr): Boolean;
  148. var
  149. res: longint;
  150. begin
  151. repeat
  152. res:=fpconnect(Sock,@Addr,SizeOF(TInetSockAddr));
  153. until (res<>-1) or (SocketError <> EsockEINTR);
  154. DoConnect:= res = 0;
  155. end;
  156. {$warnings off}
  157. Function Connect(Sock:longint;const addr: TInetSockAddr;var SockIn,SockOut:text):Boolean;
  158. begin
  159. Connect:=DoConnect(Sock,addr);
  160. If Connect then
  161. Sock2Text(Sock,SockIn,SockOut);
  162. end;
  163. Function Connect(Sock:longint;const addr:TInetSockAddr;var SockIn,SockOut:file):Boolean;
  164. begin
  165. Connect:=DoConnect(Sock,addr);
  166. If Connect then
  167. Sock2File(Sock,SockIn,SockOut);
  168. end;
  169. Function Accept(Sock:longint;var addr:TInetSockAddr;var SockIn,SockOut:text):Boolean;
  170. var
  171. s : longint;
  172. begin
  173. S:=DoAccept(Sock,addr);
  174. if S>0 then
  175. begin
  176. Sock2Text(S,SockIn,SockOut);
  177. Accept:=true;
  178. end
  179. else
  180. Accept:=false;
  181. end;
  182. Function Accept(Sock:longint;var addr:TInetSockAddr;var SockIn,SockOut:File):Boolean;
  183. var
  184. s : longint;
  185. begin
  186. S:=DoAccept(Sock,addr);
  187. if S>0 then
  188. begin
  189. Sock2File(S,SockIn,SockOut);
  190. Accept:=true;
  191. end
  192. else
  193. Accept:=false;
  194. end;
  195. {$warnings on}
  196. type thostaddr= packed array[1..4] of byte;
  197. function htonl( host : longint):longint; inline;overload;deprecated;
  198. begin
  199. {$ifdef FPC_BIG_ENDIAN}
  200. htonl:=host;
  201. {$else}
  202. htonl:=SwapEndian(host);
  203. {$endif}
  204. end;
  205. function htonl( host : cardinal):cardinal; inline;overload;
  206. begin
  207. {$ifdef FPC_BIG_ENDIAN}
  208. htonl:=host;
  209. {$else}
  210. htonl:=SwapEndian(host);
  211. {$endif}
  212. end;
  213. Function NToHl (Net : longint) : longint; inline;overload;deprecated;
  214. begin
  215. {$ifdef FPC_BIG_ENDIAN}
  216. ntohl:=net;
  217. {$else}
  218. ntohl:=SwapEndian(net);
  219. {$endif}
  220. end;
  221. Function NToHl (Net : cardinal) : cardinal; inline;overload;
  222. begin
  223. {$ifdef FPC_BIG_ENDIAN}
  224. ntohl:=net;
  225. {$else}
  226. ntohl:=SwapEndian(net);
  227. {$endif}
  228. end;
  229. function htons( host : word):word; inline;
  230. begin
  231. {$ifdef FPC_BIG_ENDIAN}
  232. htons:=host;
  233. {$else}
  234. htons:=SwapEndian(host);
  235. {$endif}
  236. end;
  237. Function NToHs (Net : word):word; inline;
  238. begin
  239. {$ifdef FPC_BIG_ENDIAN}
  240. ntohs:=net;
  241. {$else}
  242. ntohs:=SwapEndian(net);
  243. {$endif}
  244. end;
  245. Type array4int = array[1..4] of byte;
  246. function NetAddrToStr (Entry : in_addr) : AnsiString;
  247. Var Dummy : Ansistring;
  248. i,j : Longint;
  249. begin
  250. NetAddrToStr:='';
  251. j:=entry.s_addr;
  252. For I:=1 to 4 do
  253. begin
  254. Str(array4int(j)[i],Dummy);
  255. NetAddrToStr:=NetAddrToStr+Dummy;
  256. If I<4 Then
  257. NetAddrToStr:=NetAddrToStr+'.';
  258. end;
  259. end;
  260. function HostAddrToStr (Entry : in_addr) : AnsiString;
  261. Var x: in_addr;
  262. begin
  263. x.s_addr:=htonl(entry.s_addr);
  264. HostAddrToStr:=NetAddrToStr(x);
  265. end;
  266. function StrToHostAddr(IP : AnsiString) : in_addr ;
  267. Var
  268. Dummy : AnsiString;
  269. I,j,k : Longint;
  270. Temp : in_addr;
  271. begin
  272. strtohostaddr.s_addr:=0; //:=NoAddress;
  273. For I:=1 to 4 do
  274. begin
  275. If I<4 Then
  276. begin
  277. J:=Pos('.',IP);
  278. If J=0 then
  279. exit;
  280. Dummy:=Copy(IP,1,J-1);
  281. Delete (IP,1,J);
  282. end
  283. else
  284. Dummy:=IP;
  285. Val (Dummy,k,J);
  286. array4int(temp.s_addr)[i]:=k;
  287. If J<>0 then Exit;
  288. end;
  289. strtohostaddr.s_addr:=ntohl(Temp.s_addr);
  290. end;
  291. function StrToNetAddr(IP : AnsiString) : in_addr;
  292. begin
  293. StrToNetAddr.s_addr:=htonl(StrToHostAddr(IP).s_addr);
  294. end;
  295. Function HostToNet (Host : in_addr):in_addr;
  296. begin
  297. HostToNet.s_addr:=htonl(host.s_addr);
  298. end;
  299. Function NetToHost (Net : in_addr) : in_addr;
  300. begin
  301. NetToHost.s_addr:=ntohl(net.s_addr);
  302. end;
  303. Function HostToNet (Host : Longint) : Longint;
  304. begin
  305. HostToNet:=htonl(host);
  306. end;
  307. Function NetToHost (Net : Longint) : Longint;
  308. begin
  309. NetToHost:=ntohl(net);
  310. end;
  311. Function ShortHostToNet (Host : Word) : Word;
  312. begin
  313. ShortHostToNet:=htons(host);
  314. end;
  315. Function ShortNetToHost (Net : Word) : Word;
  316. begin
  317. ShortNEtToHost:=ntohs(net);
  318. end;
  319. const digittab : shortstring = ('0123456789ABCDEF');
  320. function lclinttohex (i:integer;digits:longint): ansistring;
  321. begin
  322. SetLength(lclinttohex,4);
  323. lclinttohex[4]:=digittab[1+(i and 15)];
  324. lclinttohex[3]:=digittab[1+((i shr 4) and 15)];
  325. lclinttohex[2]:=digittab[1+((i shr 8) and 15)];
  326. lclinttohex[1]:=digittab[1+((i shr 12) and 15)];;
  327. end;
  328. function HostAddrToStr6 (Entry : TIn6_Addr) :ansiString;
  329. var
  330. i: byte;
  331. zr1,zr2: set of byte;
  332. zc1,zc2: byte;
  333. have_skipped: boolean;
  334. begin
  335. zr1 := [];
  336. zr2 := [];
  337. zc1 := 0;
  338. zc2 := 0;
  339. for i := 0 to 7 do begin
  340. if Entry.u6_addr16[i] = 0 then begin
  341. include(zr2, i);
  342. inc(zc2);
  343. end else begin
  344. if zc1 < zc2 then begin
  345. zc1 := zc2;
  346. zr1 := zr2;
  347. zc2 := 0; zr2 := [];
  348. end;
  349. end;
  350. end;
  351. if zc1 < zc2 then begin
  352. zc1 := zc2;
  353. zr1 := zr2;
  354. end;
  355. SetLength(HostAddrToStr6, 8*5-1);
  356. SetLength(HostAddrToStr6, 0);
  357. have_skipped := false;
  358. for i := 0 to 7 do begin
  359. if not (i in zr1) then begin
  360. if have_skipped then begin
  361. if HostAddrToStr6 = ''
  362. then HostAddrToStr6 := '::'
  363. else HostAddrToStr6 := HostAddrToStr6 + ':';
  364. have_skipped := false;
  365. end;
  366. // FIXME: is that shortnettohost really proper there? I wouldn't be too sure...
  367. HostAddrToStr6 := HostAddrToStr6 +lclIntToHex(ShortNetToHost(Entry.u6_addr16[i]), 1) + ':';
  368. end else begin
  369. have_skipped := true;
  370. end;
  371. end;
  372. if have_skipped then
  373. if HostAddrToStr6 = ''
  374. then HostAddrToStr6 := '::'
  375. else HostAddrToStr6 := HostAddrToStr6 + ':';
  376. if HostAddrToStr6 = '' then HostAddrToStr6 := '::';
  377. if not (7 in zr1) then
  378. SetLength(HostAddrToStr6, Length(HostAddrToStr6)-1);
  379. end;
  380. function StrToHostAddr6(IP : String) : TIn6_addr;
  381. Var Part : String;
  382. IPv6 : TIn6_addr;
  383. P,J : Integer;
  384. W : Word;
  385. Index : Integer;
  386. ZeroAt : Integer;
  387. Begin
  388. FillChar(IPv6,SizeOf(IPv6),0);
  389. { Every 16-bit block is converted at its own and stored into Result. When }
  390. { the '::' zero-spacer is found, its location is stored. Afterwards the }
  391. { address is shifted and zero-filled. }
  392. Index := 0; ZeroAt := -1;
  393. J := 0;
  394. P := Pos(':',IP);
  395. While (P > 0) and (Length(IP) > 0) and (Index < 8) do
  396. Begin
  397. Part := '$'+Copy(IP,1,P-1);
  398. Delete(IP,1,P);
  399. if Length(Part) > 1 then { is there a digit after the '$'? }
  400. Val(Part,W,J)
  401. else W := 0;
  402. IPv6.u6_addr16[Index] := HtoNS(W);
  403. if J <> 0 then
  404. Begin
  405. FillChar(IPv6,SizeOf(IPv6),0);
  406. Exit;
  407. End;
  408. if IP[1] = ':' then
  409. Begin
  410. ZeroAt := Index;
  411. Delete(IP,1,1);
  412. End;
  413. Inc(Index);
  414. P := Pos(':',IP); if P = 0 then P := Length(IP)+1;
  415. End;
  416. { address a:b:c::f:g:h }
  417. { Result now a : b : c : f : g : h : 0 : 0, ZeroAt = 2, Index = 6 }
  418. { Result after a : b : c : 0 : 0 : f : g : h }
  419. if ZeroAt >= 0 then
  420. Begin
  421. Move(IPv6.u6_addr16[ZeroAt+1],IPv6.u6_addr16[(8-Index)+ZeroAt+1],2*(Index-ZeroAt-1));
  422. FillChar(IPv6.u6_addr16[ZeroAt+1],2*(8-Index),0);
  423. End;
  424. StrToHostAddr6:=IPv6;
  425. End;
  426. function NetAddrToStr6 (Entry : TIn6_Addr) : ansiString;
  427. begin
  428. netaddrtostr6 := HostAddrToStr6((Entry));
  429. end;
  430. function StrToNetAddr6(IP : ansiString) : TIn6_Addr;
  431. begin
  432. StrToNetAddr6 := StrToHostAddr6(IP);
  433. end;