You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

lsocket.pas 22KB

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