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