7438c26a00901e070a63d6925e63c2b5664d8a41
[lcore.git] / lsocket.pas
1 {lsocket.pas}\r
2 \r
3 {socket code by plugwash}\r
4 \r
5 { Copyright (C) 2005 Bas Steendijk and Peter Green\r
6   For conditions of distribution and use, see copyright notice in zlib_license.txt\r
7   which is included in the package\r
8   ----------------------------------------------------------------------------- }\r
9 {\r
10 changes by plugwash (20030728)\r
11 * created handlefdtrigger virtual method in tlasio (overridden in tlsocket) and moved a lot of code from messageloop into it\r
12 * changed tlasio to tlasio\r
13 * split fdhandle into fdhandlein and fdhandleout\r
14 * i now use fdsrmaster and fdswmaster instead of rebuilding the lists every loop\r
15 * split lsocket.pas into lsocket.pas and lcore.pas\r
16 \r
17 \r
18 changes by beware (20030903)\r
19 * added getxaddr, getxport (local addr, port, as string)\r
20 * added getpeername, remote addr+port as binary\r
21 * added htons and htonl functions (endian swap, same interface as windows API)\r
22 \r
23 beware (20030905)\r
24 * if connect failed (conn refused) set state to connected and call internalclose, to get closed handler (instead of fdclose)\r
25 * (lcore) if closing the fd's in internalcose, set fd's to -1 because closing an fd makes it invalid\r
26 \r
27 beware (20030927)\r
28 * fixed: on connect failed, tried to close fdhandle's which were already set to -1, added check\r
29 \r
30 beware (20031017)\r
31 * added getpeeraddr, getpeerport, remote addr+port as string\r
32 }\r
33 \r
34 \r
35 unit lsocket;\r
36 {$ifdef fpc}\r
37   {$mode delphi}\r
38 {$endif}\r
39 \r
40 {$include lcoreconfig.inc}\r
41 \r
42 interface\r
43   uses\r
44     sysutils,\r
45     {$ifdef win32}\r
46       windows,winsock,\r
47     {$else}\r
48 \r
49       {$ifdef VER1_0}\r
50         linux,\r
51       {$else}\r
52         baseunix,unix,unixutil,\r
53       {$endif}\r
54       sockets,\r
55     {$endif}\r
56     classes,{pgdebugout,}pgtypes,lcore,fd_utils,binipstuff,dnssync;\r
57 \r
58 {$ifdef ipv6}\r
59 const\r
60   v4listendefault:boolean=false;\r
61 {$endif}\r
62 \r
63 \r
64 type\r
65   sunB = packed record\r
66     s_b1, s_b2, s_b3, s_b4: byte;\r
67   end;\r
68 \r
69   SunW = packed record\r
70     s_w1, s_w2: word;\r
71   end;\r
72 \r
73   TInAddr = packed record\r
74     case integer of\r
75       0: (S_un_b: SunB);\r
76       1: (S_un_w: SunW);\r
77       2: (S_addr: cardinal);\r
78   end;\r
79 \r
80   type\r
81     TLsocket = class(tlasio)\r
82     public\r
83       //a: string;\r
84 \r
85       inAddr             : TInetSockAddrV;\r
86 \r
87       biniplist:tbiniplist;\r
88       trymoreips:boolean;\r
89       currentip:integer;\r
90       connecttimeout:tltimer;\r
91 \r
92 {      inAddrSize:integer;}\r
93 \r
94       //host               : THostentry      ;\r
95 \r
96       //mainthread         : boolean         ; //for debuggin only\r
97       addr:string;\r
98       port:string;\r
99       localaddr:string;\r
100       localport:string;\r
101       proto:string;\r
102       udp:boolean;\r
103       listenqueue:integer;\r
104       {$ifdef secondlistener}\r
105       secondlistener:tlsocket;\r
106       lastsessionfromsecond:boolean;\r
107       procedure secondaccepthandler(sender:tobject;error:word);\r
108       procedure internalclose(error:word);override;\r
109       {$endif}\r
110       procedure connectionfailedhandler(error:word);\r
111       procedure connecttimeouthandler(sender:tobject);\r
112       procedure connectsuccesshandler;\r
113       function getaddrsize:integer;\r
114       procedure connect; virtual;\r
115       procedure realconnect;\r
116       procedure bindsocket;\r
117       procedure listen;\r
118       function accept : longint;\r
119       function sendto(dest:TInetSockAddrV;destlen:integer;data:pointer;len:integer):integer; virtual;\r
120       function receivefrom(data:pointer;len:integer;var src:TInetSockAddrV;var srclen:integer):integer; virtual;\r
121 \r
122       procedure handlefdtrigger(readtrigger,writetrigger:boolean); override;\r
123       function send(data:pointer;len:integer):integer;override;\r
124       procedure sendstr(const str : string);override;\r
125       function Receive(Buf:Pointer;BufSize:integer):integer; override;\r
126       function getpeername(var addr:tsockaddrin;addrlen:integer):integer; virtual;\r
127       procedure getXaddrbin(var binip:tbinip); virtual;\r
128       procedure getpeeraddrbin(var binip:tbinip); virtual;\r
129       function getXaddr:string; virtual;\r
130       function getpeeraddr:string; virtual;\r
131       function getXport:string; virtual;\r
132       function getpeerport:string; virtual;\r
133       constructor Create(AOwner: TComponent); override;\r
134       {$ifdef win32}\r
135         procedure myfdclose(fd : integer); override;\r
136         function myfdwrite(fd: LongInt;const buf;size: LongInt):LongInt; override;\r
137         function myfdread(fd: LongInt;var buf;size: LongInt):LongInt; override;\r
138       {$endif}\r
139     end;\r
140     tsocket=longint; // for compatibility with twsocket\r
141 \r
142   twsocket=tlsocket; {easy}\r
143 \r
144 \r
145 const\r
146   TCP_NODELAY=1;\r
147   IPPROTO_TCP=6;\r
148 \r
149 implementation\r
150 {$include unixstuff.inc}\r
151 \r
152 \r
153 function tlsocket.getaddrsize:integer;\r
154 begin\r
155   result := inaddrsize(inaddr);\r
156 end;\r
157 \r
158 \r
159 procedure tlsocket.realconnect;\r
160 var\r
161   a:integer;\r
162 \r
163 begin\r
164 //  writeln('trying to connect to ',ipbintostr(biniplist_get(biniplist,currentip)),'#',port);\r
165   makeinaddrv(biniplist_get(biniplist,currentip),port,inaddr);\r
166   inc(currentip);\r
167   if (currentip >= biniplist_getcount(biniplist)) then trymoreips := false;\r
168   udp := uppercase(proto) = 'UDP';\r
169   if udp then a := SOCK_DGRAM else a := SOCK_STREAM;\r
170   a := Socket(inaddr.inaddr.family,a,0);\r
171   //writeln(ord(inaddr.inaddr.family));\r
172   if a = -1 then begin\r
173     lasterror := {$ifdef win32}getlasterror{$else}socketerror{$endif};\r
174     raise esocketexception.create('unable to create socket');\r
175   end;\r
176   try\r
177     dup(a);\r
178     bindsocket;\r
179     if udp then begin\r
180       {$ifndef win32}\r
181         SetSocketOptions(fdhandleout, SOL_SOCKET, SO_BROADCAST, 'TRUE', Length('TRUE'));\r
182       {$endif}\r
183       state := wsconnected;\r
184       if assigned(onsessionconnected) then onsessionconnected(self,0);\r
185 \r
186       eventcore.rmasterset(fdhandlein,false);\r
187       eventcore.wmasterclr(fdhandleout);\r
188     end else begin\r
189       state :=wsconnecting;\r
190       {$ifdef win32}\r
191         //writeln(inaddr.inaddr.port);\r
192         winsock.Connect(fdhandlein,winsock.psockaddr(@inADDR)^,getaddrsize);\r
193       {$else}\r
194         sockets.Connect(fdhandlein,inADDR,getaddrsize);\r
195       {$endif}\r
196       eventcore.rmasterset(fdhandlein,false);\r
197       eventcore.wmasterset(fdhandleout);\r
198       if trymoreips then connecttimeout.enabled := true;\r
199     end;\r
200     //sendq := '';\r
201   except\r
202     on e: exception do begin\r
203       fdcleanup;\r
204       raise; //reraise the exception\r
205     end;\r
206   end;\r
207 \r
208 end;\r
209 \r
210 procedure tlsocket.connecttimeouthandler(sender:tobject);\r
211 begin\r
212   connecttimeout.enabled := false;\r
213   destroying := true; //hack to not cause handler to trigger\r
214   internalclose(0);\r
215   destroying := false;\r
216   realconnect;\r
217 end;\r
218 \r
219 procedure tlsocket.connect;\r
220 var\r
221   a:integer;\r
222   ip:tbinip;\r
223 begin\r
224   if state <> wsclosed then close;\r
225   //prevtime := 0;\r
226   if isbiniplist(addr) then biniplist := addr else biniplist := forwardlookuplist(addr,0);\r
227   if biniplist_getcount(biniplist) = 0 then raise exception.create('unable to resolve '+addr);\r
228 \r
229   //makeinaddrv(addr,port,inaddr);\r
230 \r
231   currentip := 0;\r
232   if not assigned(connecttimeout) then begin\r
233     connecttimeout := tltimer.create(self);\r
234     connecttimeout.Tag := integer(self);\r
235     connecttimeout.ontimer := connecttimeouthandler;\r
236     connecttimeout.interval := 2500;\r
237     connecttimeout.enabled := false;\r
238   end;\r
239   realconnect;\r
240 end;\r
241 \r
242 procedure tlsocket.sendstr(const str : string);\r
243 begin\r
244   if udp then begin\r
245     send(@str[1],length(str))\r
246   end else begin\r
247     inherited sendstr(str);\r
248   end;\r
249 end;\r
250 \r
251 function tlsocket.send(data:pointer;len:integer):integer;\r
252 begin\r
253   if udp then begin\r
254 //    writeln('sending to '+ipbintostr(inaddrvtobinip(inaddr)),' ',htons(inaddr.inaddr.port),' ',len,' bytes');\r
255     result := sendto(inaddr,getaddrsize,data,len);\r
256 \r
257 //    writeln('send result ',result);\r
258 //    writeln('errno',errno);\r
259   end else begin\r
260     result := inherited send(data,len);\r
261   end;\r
262 end;\r
263 \r
264 \r
265 function tlsocket.receive(Buf:Pointer;BufSize:integer):integer;\r
266 begin\r
267   if udp then begin\r
268     {$ifdef secondlistener}\r
269     if lastsessionfromsecond then begin\r
270       result := secondlistener.receive(buf,bufsize);\r
271       lastsessionfromsecond := false;\r
272     end else\r
273     {$endif}\r
274       result := myfdread(self.fdhandlein,buf^,bufsize);\r
275   end else begin\r
276     result := inherited receive(buf,bufsize);\r
277   end;\r
278 end;\r
279 \r
280 procedure tlsocket.bindsocket;\r
281 var\r
282   a:integer;\r
283   inAddrtemp:TInetSockAddrV;\r
284   inAddrtempx:{$ifdef win32}winsock.TSockaddr{$else}TInetSockAddrV{$endif} absolute inaddrtemp;\r
285   inaddrtempsize:integer;\r
286 begin\r
287   try\r
288     if (localaddr <> '') or (localport <> '') then begin\r
289       if localaddr = '' then begin\r
290         {$ifdef ipv6}\r
291         if inaddr.inaddr.family = AF_INET6 then localaddr := '::' else\r
292         {$endif}\r
293         localaddr := '0.0.0.0';\r
294       end;\r
295       //gethostbyname(localaddr,host);\r
296 \r
297       inaddrtempsize := makeinaddrv(forwardlookup(localaddr,0),localport,inaddrtemp);\r
298 \r
299       If Bind(fdhandlein,inaddrtempx,inaddrtempsize)<> {$ifdef win32}0{$else}true{$endif} Then begin\r
300         state := wsclosed;\r
301         lasterror := {$ifdef win32}getlasterror{$else}socketerror{$endif};\r
302         raise ESocketException.create('unable to bind, error '+inttostr(lasterror));\r
303       end;\r
304       state := wsbound;\r
305     end;\r
306   except\r
307     on e: exception do begin\r
308       fdcleanup;\r
309       raise; //reraise the exception\r
310     end;\r
311   end;\r
312 end;\r
313 \r
314 procedure tlsocket.listen;\r
315 var\r
316   yes:longint;\r
317   socktype:integer;\r
318   biniptemp:tbinip;\r
319   origaddr:string;\r
320 begin\r
321   if state <> wsclosed then close;\r
322   udp := uppercase(proto) = 'UDP';\r
323   if udp then socktype := SOCK_DGRAM else socktype := SOCK_STREAM;\r
324   origaddr := addr;\r
325 \r
326   if addr = '' then begin\r
327     {$ifdef ipv6}\r
328     if not v4listendefault then begin\r
329       addr := '::';\r
330     end else\r
331     {$endif}\r
332     addr := '0.0.0.0';\r
333   end;\r
334   if isbiniplist(addr) then biniptemp := biniplist_get(addr,0) else biniptemp := forwardlookup(addr,10);\r
335   addr := ipbintostr(biniptemp);\r
336   fdhandlein := socket(biniptemp.family,socktype,0);\r
337   {$ifdef ipv6}\r
338   if (addr = '::') and (origaddr = '') and (fdhandlein < 0) then begin\r
339     addr := '0.0.0.0';\r
340     fdhandlein := socket(AF_INET,socktype,0);\r
341   end;\r
342   {$endif}\r
343 \r
344   if fdhandlein = -1 then raise ESocketException.create('unable to create socket');\r
345   dupnowatch(fdhandlein); // sets up maxs and copies handle to fdhandleout among other things\r
346   //eventcore.setfdreverse(fdhandlein,self); //already taken care of by dup\r
347   state := wsclosed; // then set this back as it was an undesired side effect of dup\r
348 \r
349   try\r
350     yes := $01010101;  {Copied this from existing code. Value is empiric,\r
351                     but works. (yes=true<>0) }\r
352     {$ifndef win32}\r
353       if SetSocketOptions(fdhandlein, SOL_SOCKET, SO_REUSEADDR,yes,sizeof(yes))=-1 then begin\r
354         raise ESocketException.create('unable to set socket options');\r
355       end;\r
356     {$endif}\r
357     localaddr := addr;\r
358     localport := port;\r
359     bindsocket;\r
360 \r
361     if not udp then begin\r
362       {!!! allow custom queue length? default 5}\r
363       if listenqueue = 0 then listenqueue := 5;\r
364       If {$ifdef win32}winsock{$else}sockets{$endif}.Listen(fdhandlein,listenqueue)<>{$ifdef win32}0{$else}true{$endif} Then raise esocketexception.create('unable to listen');\r
365       state := wsListening;\r
366     end else begin\r
367       {$ifndef win32}\r
368         SetSocketOptions(fdhandleout, SOL_SOCKET, SO_BROADCAST, 'TRUE', Length('TRUE'));\r
369       {$endif}\r
370       state := wsconnected;\r
371     end;\r
372 \r
373     {$ifdef secondlistener}\r
374     //listening on ::. try to listen on 0.0.0.0 as well for platforms which don't already do that\r
375     if addr = '::' then begin\r
376       secondlistener := tlsocket.create(nil);\r
377       secondlistener.proto := proto;\r
378       secondlistener.addr := '0.0.0.0';\r
379       secondlistener.port := port;\r
380       if udp then begin\r
381         secondlistener.ondataavailable := secondaccepthandler;\r
382       end else begin\r
383         secondlistener.onsessionAvailable := secondaccepthandler;\r
384       end;\r
385       try\r
386         secondlistener.listen;\r
387       except\r
388         secondlistener.destroy;\r
389         secondlistener := nil;\r
390       end;\r
391     end;\r
392     {$endif}\r
393   finally\r
394     if state = wsclosed then begin\r
395       if fdhandlein >= 0 then begin\r
396         {one *can* get here without fd -beware}\r
397         eventcore.rmasterclr(fdhandlein);\r
398         myfdclose(fdhandlein); // we musnt leak file discriptors\r
399         eventcore.setfdreverse(fdhandlein,nil);\r
400         fdhandlein := -1;\r
401       end;\r
402     end else begin\r
403       eventcore.rmasterset(fdhandlein,not udp);\r
404     end;\r
405     if fdhandleout >= 0 then eventcore.wmasterclr(fdhandleout);\r
406   end;\r
407   //writeln('listened on addr '+addr+':'+port+' '+proto+' using socket number ',fdhandlein);\r
408 end;\r
409 \r
410 {$ifdef secondlistener}\r
411 procedure tlsocket.internalclose(error:word);\r
412 begin\r
413   if assigned(secondlistener) then begin\r
414     secondlistener.destroy;\r
415     secondlistener := nil;\r
416   end;\r
417   inherited internalclose(error);\r
418 end;\r
419 \r
420 procedure tlsocket.secondaccepthandler;\r
421 begin\r
422   lastsessionfromsecond := true;\r
423   if udp then begin\r
424     ondataavailable(self,error);\r
425   end else begin\r
426     if assigned(onsessionavailable) then onsessionavailable(self,error);\r
427   end;\r
428 end;\r
429 {$endif}\r
430 \r
431 function tlsocket.accept : longint;\r
432 var\r
433   FromAddrSize     : LongInt;        // i don't realy know what to do with these at this\r
434   FromAddr         : TInetSockAddrV;  // at this point time will tell :)\r
435   a:integer;\r
436 begin\r
437   {$ifdef secondlistener}\r
438   if (lastsessionfromsecond) then begin\r
439     lastsessionfromsecond := false;\r
440     result := secondlistener.accept;\r
441     exit;\r
442   end;\r
443   {$endif}\r
444 \r
445   FromAddrSize := Sizeof(FromAddr);\r
446   {$ifdef win32}\r
447     result := winsock.accept(fdhandlein,@fromaddr,@fromaddrsize);\r
448   {$else}\r
449     result := sockets.accept(fdhandlein,fromaddr,fromaddrsize);\r
450   {$endif}\r
451   //now we have accepted one request start monitoring for more again\r
452   eventcore.rmasterset(fdhandlein,true);\r
453 \r
454   if result = -1 then begin\r
455     raise esocketexception.create('error '+inttostr({$ifdef win32}getlasterror{$else}socketerror{$endif})+' while accepting');\r
456   end;\r
457   if result > absoloutemaxs then begin\r
458     myfdclose(result);\r
459     a := result;\r
460     result := -1;\r
461     raise esocketexception.create('file discriptor out of range: '+inttostr(a));\r
462   end;\r
463 end;\r
464 \r
465 function tlsocket.sendto(dest:TInetSockAddrV;destlen:integer;data:pointer;len:integer):integer;\r
466 var\r
467   destx : {$ifdef win32}winsock.TSockAddr{$else}TInetSockAddrV{$endif} absolute dest;\r
468 begin\r
469   {$ifdef secondlistener}\r
470   if assigned(secondlistener) then if (dest.inaddr.family = AF_INET) then begin\r
471     result := secondlistener.sendto(dest,destlen,data,len);\r
472     exit;\r
473   end;\r
474   {$endif}\r
475   result := {$ifdef win32}winsock{$else}sockets{$endif}.sendto(self.fdhandleout,data^,len,0,destx,destlen);\r
476 end;\r
477 \r
478 function tlsocket.receivefrom(data:pointer;len:integer;var src:TInetSockAddrV;var srclen:integer):integer;\r
479 var\r
480   srcx : {$ifdef win32}winsock.TSockAddr{$else}TInetSockAddrV{$endif} absolute src;\r
481 begin\r
482   {$ifdef secondlistener}\r
483   if assigned(secondlistener) then if lastsessionfromsecond then begin\r
484     lastsessionfromsecond := false;\r
485     result := secondlistener.receivefrom(data,len,src,srclen);\r
486     exit;\r
487   end;\r
488   {$endif}\r
489   result := {$ifdef win32}winsock{$else}sockets{$endif}.recvfrom(self.fdhandlein,data^,len,0,srcx,srclen);\r
490 end;\r
491 \r
492 procedure tlsocket.connectionfailedhandler(error:word);\r
493 begin\r
494    if trymoreips then begin\r
495 //     writeln('failed with error ',error);\r
496      connecttimeout.enabled := false;\r
497      destroying := true;\r
498      state := wsconnected;\r
499      self.internalclose(0);\r
500      destroying := false;\r
501      realconnect;\r
502    end else begin\r
503      state := wsconnected;\r
504      if assigned(onsessionconnected) then onsessionconnected(self,error);\r
505      self.internalclose(0);\r
506      recvq.del(maxlongint);\r
507    end;\r
508 end;\r
509 \r
510 procedure tlsocket.connectsuccesshandler;\r
511 begin\r
512    trymoreips := false;\r
513    connecttimeout.enabled := false;\r
514    if assigned(onsessionconnected) then onsessionconnected(self,0);\r
515 end;\r
516 \r
517 \r
518 procedure tlsocket.handlefdtrigger(readtrigger,writetrigger:boolean);\r
519 var\r
520   tempbuf:array[0..receivebufsize-1] of byte;\r
521 begin\r
522 //  writeln('got a fd trigger, readtrigger=',readtrigger,' writetrigger=',writetrigger,' state=',integer(state));\r
523   if (state =wslistening) and readtrigger then begin\r
524 {    debugout('listening socket triggered on read');}\r
525     eventcore.rmasterclr(fdhandlein);\r
526     if assigned(onsessionAvailable) then onsessionAvailable(self,0);\r
527   end;\r
528   if udp and readtrigger then begin\r
529     if assigned(ondataAvailable) then ondataAvailable(self,0);\r
530     {!!!test}\r
531     exit;\r
532   end;\r
533   if (state =wsconnecting) and writetrigger then begin\r
534     // code for dealing with the reults of a non-blocking connect is\r
535     // rather complex\r
536     // if just write is triggered it means connect suceeded\r
537     // if both read and write are triggered it can mean 2 things\r
538     // 1: connect ok and data availible\r
539     // 2: connect fail\r
540     // to find out which you must read from the socket and look for errors\r
541     // there if we read successfully we drop through into the code for fireing\r
542     // the read event\r
543     if not readtrigger then begin\r
544       state := wsconnected;\r
545       connectsuccesshandler;\r
546     end else begin\r
547       numread := myfdread(fdhandlein,tempbuf,sizeof(tempbuf));\r
548       if numread <> -1 then begin\r
549         state := wsconnected;\r
550         connectsuccesshandler;\r
551         //connectread := true;\r
552         recvq.add(@tempbuf,numread);\r
553       end else begin\r
554         connectionfailedhandler({$ifdef win32}wsagetlasterror{$else}linuxerror{$endif});\r
555         exit;\r
556       end;\r
557       // if things went well here we are now in the state wsconnected with data sitting in our receive buffer\r
558       // so we drop down into the processing for data availible\r
559     end;\r
560     if fdhandlein >= 0 then begin\r
561       if state = wsconnected then begin\r
562         eventcore.rmasterset(fdhandlein,false);\r
563       end else begin\r
564         eventcore.rmasterclr(fdhandlein);\r
565       end;\r
566     end;\r
567     if fdhandleout >= 0 then begin\r
568       if sendq.size = 0 then begin\r
569         //don't clear the bit in fdswmaster if data is in the sendq\r
570         eventcore.wmasterclr(fdhandleout);\r
571       end;\r
572     end;\r
573 \r
574   end;\r
575   inherited handlefdtrigger(readtrigger,writetrigger);\r
576 end;\r
577 \r
578 constructor tlsocket.Create(AOwner: TComponent);\r
579 begin\r
580   inherited create(aowner);\r
581   closehandles := true;\r
582   trymoreips := true;\r
583 end;\r
584 \r
585 \r
586 function tlsocket.getpeername(var addr:tsockaddrin;addrlen:integer):integer;\r
587 var\r
588   addrx : {$ifdef win32}winsock.tsockaddr{$else}tsockaddrin{$endif} absolute addr;\r
589 begin\r
590   result := {$ifdef win32}winsock{$else}sockets{$endif}.getpeername(self.fdhandlein,addrx,addrlen);\r
591 end;\r
592 \r
593 procedure tlsocket.getxaddrbin(var binip:tbinip);\r
594 var\r
595   addr:tinetsockaddrv;\r
596   i:integer;\r
597 begin\r
598   i := sizeof(addr);\r
599   fillchar(addr,sizeof(addr),0);\r
600 \r
601   {$ifdef win32}\r
602     winsock.getsockname(self.fdhandlein,psockaddr(@addr)^,i);\r
603   {$else}\r
604     sockets.getsocketname(self.fdhandlein,addr,i);\r
605   {$endif}\r
606   binip.family := addr.inaddr.family;\r
607   {$ifdef ipv6}\r
608   if addr.inaddr6.sin6_family = AF_INET6 then begin\r
609     binip.ip6 := addr.inaddr6.sin6_addr;\r
610   end else\r
611   {$endif}\r
612   begin\r
613     binip.ip := addr.inaddr.addr;\r
614   end;\r
615   converttov4(binip);\r
616 end;\r
617 \r
618 procedure tlsocket.getpeeraddrbin(var binip:tbinip);\r
619 var\r
620   addr:tinetsockaddrv;\r
621   i:integer;\r
622 begin\r
623   i := sizeof(addr);\r
624   fillchar(addr,sizeof(addr),0);\r
625   {$ifdef win32}\r
626     winsock.getpeername(self.fdhandlein,psockaddr(@addr)^,i);\r
627   {$else}\r
628     sockets.getpeername(self.fdhandlein,addr,i);\r
629   {$endif}\r
630 \r
631   binip.family := addr.inaddr.family;\r
632   {$ifdef ipv6}\r
633   if addr.inaddr6.sin6_family = AF_INET6 then begin\r
634     binip.ip6 := addr.inaddr6.sin6_addr;\r
635   end else\r
636   {$endif}\r
637   begin\r
638     binip.ip := addr.inaddr.addr;\r
639   end;\r
640   converttov4(binip);\r
641 end;\r
642 \r
643 function tlsocket.getXaddr:string;\r
644 var\r
645   biniptemp:tbinip;\r
646 begin\r
647   getxaddrbin(biniptemp);\r
648   result := ipbintostr(biniptemp);\r
649   if result = '' then result := 'error';\r
650 end;\r
651 \r
652 function tlsocket.getpeeraddr:string;\r
653 var\r
654   biniptemp:tbinip;\r
655 begin\r
656   getpeeraddrbin(biniptemp);\r
657   result := ipbintostr(biniptemp);\r
658   if result = '' then result := 'error';\r
659 end;\r
660 \r
661 function tlsocket.getXport:string;\r
662 var\r
663   addr:tinetsockaddrv;\r
664   i:integer;\r
665 begin\r
666   i := sizeof(addr);\r
667   {$ifdef win32}\r
668     winsock.getsockname(self.fdhandlein,psockaddrin(@addr)^,i);\r
669 \r
670   {$else}\r
671     sockets.getsocketname(self.fdhandlein,addr,i);\r
672 \r
673   {$endif}\r
674   result := inttostr(htons(addr.InAddr.port));\r
675 end;\r
676 \r
677 function tlsocket.getpeerport:string;\r
678 var\r
679   addr:tinetsockaddrv;\r
680   i:integer;\r
681 begin\r
682   i := sizeof(addr);\r
683   {$ifdef win32}\r
684     winsock.getpeername(self.fdhandlein,psockaddrin(@addr)^,i);\r
685 \r
686   {$else}\r
687     sockets.getpeername(self.fdhandlein,addr,i);\r
688 \r
689   {$endif}\r
690   result := inttostr(htons(addr.InAddr.port));\r
691 end;\r
692 \r
693 {$ifdef win32}\r
694   procedure tlsocket.myfdclose(fd : integer);\r
695   begin\r
696     closesocket(fd);\r
697   end;\r
698   function tlsocket.myfdwrite(fd: LongInt;const buf;size: LongInt):LongInt;\r
699   begin\r
700     result := winsock.send(fd,(@buf)^,size,0);\r
701   end;\r
702   function tlsocket.myfdread(fd: LongInt;var buf;size: LongInt):LongInt;\r
703   begin\r
704     result := winsock.recv(fd,buf,size,0);\r
705   end;\r
706 {$endif}\r
707
708 end.\r
709 \r