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