sockets.inc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  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:=send(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:=recv(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. { Now the writing part. }
  99. Assign(SockOut,'.');
  100. Textrec(SockOut).Handle:=Sock;
  101. Textrec(SockOut).userdata[1]:=S_OUT;
  102. TextRec(SockOut).OpenFunc:=@OpenSock;
  103. TextRec(SockOut).InOutFunc:=@IOSock;
  104. TextRec(SockOut).FlushFunc:=@FlushSock;
  105. TextRec(SockOut).CloseFunc:=@CloseSock;
  106. TextRec(SockOut).Mode := fmOutput;
  107. end;
  108. {******************************************************************************
  109. Untyped File
  110. ******************************************************************************}
  111. Procedure Sock2File(Sock:Longint;Var SockIn,SockOut:File);
  112. begin
  113. {Input}
  114. Assign(SockIn,'.');
  115. FileRec(SockIn).Handle:=Sock;
  116. FileRec(SockIn).RecSize:=1;
  117. FileRec(Sockin).userdata[1]:=S_IN;
  118. FileRec(SockIn).Mode := fmInput;
  119. {Output}
  120. Assign(SockOut,'.');
  121. FileRec(SockOut).Handle:=Sock;
  122. FileRec(SockOut).RecSize:=1;
  123. FileRec(SockOut).userdata[1]:=S_OUT;
  124. FileRec(SockOut).Mode := fmOutput;
  125. end;
  126. {******************************************************************************
  127. InetSock
  128. ******************************************************************************}
  129. Function DoAccept(Sock:longint;Var addr:TInetSockAddr):longint;
  130. Var AddrLen : Longint;
  131. begin
  132. AddrLEn:=SizeOf(Addr);
  133. DoAccept:=Accept(Sock,Addr,AddrLen);
  134. end;
  135. Function DoConnect(Sock:longint;const addr: TInetSockAddr): Boolean;
  136. begin
  137. DoConnect:=Connect(Sock,Addr,SizeOF(TInetSockAddr));
  138. end;
  139. Function Connect(Sock:longint;const addr: TInetSockAddr;var SockIn,SockOut:text):Boolean;
  140. begin
  141. Connect:=DoConnect(Sock,addr);
  142. If Connect then
  143. Sock2Text(Sock,SockIn,SockOut);
  144. end;
  145. Function Connect(Sock:longint;const addr:TInetSockAddr;var SockIn,SockOut:file):Boolean;
  146. begin
  147. Connect:=DoConnect(Sock,addr);
  148. If Connect then
  149. Sock2File(Sock,SockIn,SockOut);
  150. end;
  151. Function Accept(Sock:longint;var addr:TInetSockAddr;var SockIn,SockOut:text):Boolean;
  152. var
  153. s : longint;
  154. begin
  155. S:=DoAccept(Sock,addr);
  156. if S>0 then
  157. begin
  158. Sock2Text(S,SockIn,SockOut);
  159. Accept:=true;
  160. end
  161. else
  162. Accept:=false;
  163. end;
  164. Function Accept(Sock:longint;var addr:TInetSockAddr;var SockIn,SockOut:File):Boolean;
  165. var
  166. s : longint;
  167. begin
  168. S:=DoAccept(Sock,addr);
  169. if S>0 then
  170. begin
  171. Sock2File(S,SockIn,SockOut);
  172. Accept:=true;
  173. end
  174. else
  175. Accept:=false;
  176. end;
  177. type thostaddr= packed array[1..4] of byte;
  178. function htonl( host : longint):longint; inline;
  179. begin
  180. {$ifdef FPC_BIG_ENDIAN}
  181. htonl:=host;
  182. {$else}
  183. htonl:=THostAddr(host)[4];
  184. htonl:=htonl or ( (THostAddr(host)[3]) shl 8);
  185. htonl:=htonl or ( (THostAddr(host)[2]) shl 16);
  186. htonl:=htonl or ( (THostAddr(host)[1]) shl 24);
  187. {$endif}
  188. end;
  189. Function NToHl (Net : Longint) : Longint; inline;
  190. begin
  191. {$ifdef FPC_BIG_ENDIAN}
  192. ntohl:=net;
  193. {$else}
  194. ntohl:=THostAddr(Net)[4];
  195. ntohl:=ntohl or ( (THostAddr(Net)[3]) shl 8);
  196. ntohl:=ntohl or ( (THostAddr(Net)[2]) shl 16);
  197. ntohl:=ntohl or ( (THostAddr(Net)[1]) shl 24);
  198. {$endif}
  199. end;
  200. function htons( host : word):word; inline;
  201. begin
  202. {$ifdef FPC_BIG_ENDIAN}
  203. htons:=host;
  204. {$else}
  205. htons:=swap(host);
  206. {$endif}
  207. end;
  208. Function NToHs (Net : word):word; inline;
  209. begin
  210. {$ifdef FPC_BIG_ENDIAN}
  211. ntohs:=net;
  212. {$else}
  213. ntohs:=swap(net);
  214. {$endif}
  215. end;
  216. Type array4int = array[1..4] of byte;
  217. function NetAddrToStr (Entry : in_addr) : AnsiString;
  218. Var Dummy : Ansistring;
  219. i,j : Longint;
  220. begin
  221. NetAddrToStr:='';
  222. j:=entry.s_addr;
  223. For I:=1 to 4 do
  224. begin
  225. Str(array4int(j)[i],Dummy);
  226. NetAddrToStr:=NetAddrToStr+Dummy;
  227. If I<4 Then
  228. NetAddrToStr:=NetAddrToStr+'.';
  229. end;
  230. end;
  231. function HostAddrToStr (Entry : in_addr) : AnsiString;
  232. Var x: in_addr;
  233. begin
  234. x.s_addr:=htonl(entry.s_addr);
  235. HostAddrToStr:=NetAddrToStr(x);
  236. end;
  237. function StrToHostAddr(IP : AnsiString) : in_addr ;
  238. Var
  239. Dummy : AnsiString;
  240. I,j,k : Longint;
  241. Temp : in_addr;
  242. begin
  243. strtohostaddr.s_addr:=0; //:=NoAddress;
  244. For I:=1 to 4 do
  245. begin
  246. If I<4 Then
  247. begin
  248. J:=Pos('.',IP);
  249. If J=0 then
  250. exit;
  251. Dummy:=Copy(IP,1,J-1);
  252. Delete (IP,1,J);
  253. end
  254. else
  255. Dummy:=IP;
  256. Val (Dummy,k,J);
  257. array4int(temp.s_addr)[i]:=k;
  258. If J<>0 then Exit;
  259. end;
  260. strtohostaddr.s_addr:=ntohl(Temp.s_addr);
  261. end;
  262. function StrToNetAddr(IP : AnsiString) : in_addr;
  263. begin
  264. StrToNetAddr.s_addr:=htonl(StrToHostAddr(IP).s_addr);
  265. end;
  266. Function HostToNet (Host : in_addr):in_addr;
  267. begin
  268. HostToNet.s_addr:=htonl(host.s_addr);
  269. end;
  270. Function NetToHost (Net : in_addr) : in_addr;
  271. begin
  272. NetToHost.s_addr:=ntohl(net.s_addr);
  273. end;
  274. Function HostToNet (Host : Longint) : Longint;
  275. begin
  276. HostToNet:=htonl(host);
  277. end;
  278. Function NetToHost (Net : Longint) : Longint;
  279. begin
  280. NetToHost:=ntohl(net);
  281. end;
  282. Function ShortHostToNet (Host : Word) : Word;
  283. begin
  284. ShortHostToNet:=htons(host);
  285. end;
  286. Function ShortNetToHost (Net : Word) : Word;
  287. begin
  288. ShortNEtToHost:=ntohs(net);
  289. end;
  290. const digittab : shortstring = ('0123456789ABCDEF');
  291. function lclinttohex (i:integer;digits:longint): ansistring;
  292. begin
  293. SetLength(lclinttohex,4);
  294. lclinttohex[4]:=digittab[1+(i and 15)];
  295. lclinttohex[3]:=digittab[1+((i shr 4) and 15)];
  296. lclinttohex[2]:=digittab[1+((i shr 8) and 15)];
  297. lclinttohex[1]:=digittab[1+((i shr 12) and 15)];;
  298. end;
  299. function HostAddrToStr6 (Entry : TIn6_Addr) :ansiString;
  300. var
  301. i: byte;
  302. zr1,zr2: set of byte;
  303. zc1,zc2: byte;
  304. have_skipped: boolean;
  305. begin
  306. zr1 := [];
  307. zr2 := [];
  308. zc1 := 0;
  309. zc2 := 0;
  310. for i := 0 to 7 do begin
  311. if Entry.u6_addr16[i] = 0 then begin
  312. include(zr2, i);
  313. inc(zc2);
  314. end else begin
  315. if zc1 < zc2 then begin
  316. zc1 := zc2;
  317. zr1 := zr2;
  318. zc2 := 0; zr2 := [];
  319. end;
  320. end;
  321. end;
  322. if zc1 < zc2 then begin
  323. zc1 := zc2;
  324. zr1 := zr2;
  325. end;
  326. SetLength(HostAddrToStr6, 8*5-1);
  327. SetLength(HostAddrToStr6, 0);
  328. have_skipped := false;
  329. for i := 0 to 7 do begin
  330. if not (i in zr1) then begin
  331. if have_skipped then begin
  332. if HostAddrToStr6 = ''
  333. then HostAddrToStr6 := '::'
  334. else HostAddrToStr6 := HostAddrToStr6 + ':';
  335. have_skipped := false;
  336. end;
  337. // FIXME: is that shortnettohost really proper there? I wouldn't be too sure...
  338. HostAddrToStr6 := HostAddrToStr6 +lclIntToHex(ShortNetToHost(Entry.u6_addr16[i]), 1) + ':';
  339. end else begin
  340. have_skipped := true;
  341. end;
  342. end;
  343. if have_skipped then
  344. if HostAddrToStr6 = ''
  345. then HostAddrToStr6 := '::'
  346. else HostAddrToStr6 := HostAddrToStr6 + ':';
  347. if HostAddrToStr6 = '' then HostAddrToStr6 := '::';
  348. if not (7 in zr1) then
  349. SetLength(HostAddrToStr6, Length(HostAddrToStr6)-1);
  350. end;
  351. function StrToHostAddr6(IP : String) : TIn6_addr;
  352. Var Part : String;
  353. IPv6 : TIn6_addr;
  354. P,J : Integer;
  355. W : Word;
  356. Index : Integer;
  357. ZeroAt : Integer;
  358. Begin
  359. FillChar(IPv6,SizeOf(IPv6),0);
  360. { Every 16-bit block is converted at its own and stored into Result. When }
  361. { the '::' zero-spacer is found, its location is stored. Afterwards the }
  362. { address is shifted and zero-filled. }
  363. Index := 0; ZeroAt := -1;
  364. J := 0;
  365. P := Pos(':',IP);
  366. While (P > 0) and (Length(IP) > 0) and (Index < 8) do
  367. Begin
  368. Part := '$'+Copy(IP,1,P-1);
  369. Delete(IP,1,P);
  370. if Length(Part) > 1 then { is there a digit after the '$'? }
  371. Val(Part,W,J)
  372. else W := 0;
  373. IPv6.u6_addr16[Index] := HtoNS(W);
  374. if J <> 0 then
  375. Begin
  376. FillChar(IPv6,SizeOf(IPv6),0);
  377. Exit;
  378. End;
  379. if IP[1] = ':' then
  380. Begin
  381. ZeroAt := Index;
  382. Delete(IP,1,1);
  383. End;
  384. Inc(Index);
  385. P := Pos(':',IP); if P = 0 then P := Length(IP)+1;
  386. End;
  387. { address a:b:c::f:g:h }
  388. { Result now a : b : c : f : g : h : 0 : 0, ZeroAt = 2, Index = 6 }
  389. { Result after a : b : c : 0 : 0 : f : g : h }
  390. if ZeroAt >= 0 then
  391. Begin
  392. Move(IPv6.u6_addr16[ZeroAt+1],IPv6.u6_addr16[(8-Index)+ZeroAt+1],2*(Index-ZeroAt-1));
  393. FillChar(IPv6.u6_addr16[ZeroAt+1],2*(8-Index),0);
  394. End;
  395. StrToHostAddr6:=IPv6;
  396. End;
  397. function NetAddrToStr6 (Entry : TIn6_Addr) : ansiString;
  398. begin
  399. netaddrtostr6 := HostAddrToStr6((Entry));
  400. end;
  401. function StrToNetAddr6(IP : ansiString) : TIn6_Addr;
  402. begin
  403. StrToNetAddr6 := StrToHostAddr6(IP);
  404. end;