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