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.

lcore.pas 25KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906
  1. {lsocket.pas}
  2. {io and timer 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. {note: you must use the @ in the last param to tltask.create not doing so will
  8. compile without error but will cause an access violation -pg}
  9. //note: events after release are normal and are the apps responsibility to deal with safely
  10. unit lcore;
  11. {$ifdef fpc}
  12. {$mode delphi}
  13. {$endif}
  14. {$ifdef win32}
  15. {$define nosignal}
  16. {$endif}
  17. interface
  18. uses
  19. sysutils,
  20. {$ifndef win32}
  21. {$ifdef VER1_0}
  22. linux,
  23. {$else}
  24. baseunix,unix,unixutil,
  25. {$endif}
  26. fd_utils,
  27. {$endif}
  28. classes,pgtypes,bfifo;
  29. procedure processtasks;
  30. const
  31. {how this number is made up:
  32. - ethernet: MTU 1500
  33. - be safe for either "ethernet v1" or "PPPoE", both take 8 bytes
  34. - IPv6 header: 40 bytes (IPv4 is 20)
  35. - TCP/UDP header: 20 bytes
  36. }
  37. packetbasesize = 1432;
  38. receivebufsize=packetbasesize*8;
  39. var
  40. absoloutemaxs:integer=0;
  41. type
  42. {$ifdef ver1_0}
  43. sigset= array[0..31] of longint;
  44. {$endif}
  45. ESocketException = class(Exception);
  46. TBgExceptionEvent = procedure (Sender : TObject;
  47. E : Exception;
  48. var CanClose : Boolean) of object;
  49. // note : tsocketstate is defined in the same way as it is in François PIETTE's twsocket
  50. // however tlsocket currently only uses wsClosed wsConnecting wsconnected and wsListening
  51. TSocketState = (wsInvalidState,
  52. wsOpened, wsBound,
  53. wsConnecting, wsConnected,
  54. wsAccepting, wsListening,
  55. wsClosed);
  56. TWSocketOption = (wsoNoReceiveLoop, wsoTcpNoDelay);
  57. TWSocketOptions = set of TWSocketOption;
  58. TSocketevent = procedure(Sender: TObject; Error: word) of object;
  59. //Tdataavailevent = procedure(data : string);
  60. TSendData = procedure (Sender: TObject; BytesSent: Integer) of object;
  61. tlcomponent = class(tcomponent)
  62. private
  63. procedure releasetaskhandler(wparam,lparam:longint);
  64. public
  65. procedure release; virtual;
  66. destructor destroy; override;
  67. end;
  68. tlasio = class(tlcomponent)
  69. public
  70. state : tsocketstate ;
  71. ComponentOptions : TWSocketOptions;
  72. fdhandlein : Longint ; {file discriptor}
  73. fdhandleout : Longint ; {file discriptor}
  74. onsessionclosed : tsocketevent ;
  75. ondataAvailable : tsocketevent ;
  76. onsessionAvailable : tsocketevent ;
  77. onsessionconnected : tsocketevent ;
  78. onsenddata : tsenddata ;
  79. ondatasent : tsocketevent ;
  80. //connected : boolean ;
  81. recvq : tfifo;
  82. OnBgException : TBgExceptionEvent ;
  83. //connectread : boolean ;
  84. sendq : tfifo;
  85. closehandles : boolean ;
  86. writtenthiscycle : boolean ;
  87. onfdwrite : procedure (Sender: TObject; Error: word) of object; //added for bewarehttpd
  88. lasterror:integer;
  89. destroying:boolean;
  90. recvbufsize:integer;
  91. function receivestr:string; virtual;
  92. procedure close;
  93. procedure abort;
  94. procedure internalclose(error:word); virtual;
  95. constructor Create(AOwner: TComponent); override;
  96. destructor destroy; override;
  97. procedure fdcleanup;
  98. procedure HandleBackGroundException(E: Exception);
  99. procedure handlefdtrigger(readtrigger,writetrigger:boolean); virtual;
  100. procedure dup(invalue:longint);
  101. function sendflush : integer;
  102. procedure sendstr(const str : string);virtual;
  103. procedure putstringinsendbuffer(const newstring : string);
  104. function send(data:pointer;len:integer):integer;virtual;
  105. procedure putdatainsendbuffer(data:pointer;len:integer); virtual;
  106. procedure deletebuffereddata;
  107. //procedure messageloop;
  108. function Receive(Buf:Pointer;BufSize:integer):integer; virtual;
  109. procedure flush;virtual;
  110. procedure dodatasent(wparam,lparam:longint);
  111. procedure doreceiveloop(wparam,lparam:longint);
  112. procedure sinkdata(sender:tobject;error:word);
  113. procedure release; override; {test -beware}
  114. function RealSend(Data : Pointer; Len : Integer) : Integer; //added for bewarehttpd
  115. procedure myfdclose(fd : integer); virtual;{$ifdef win32}abstract;{$endif}
  116. function myfdwrite(fd: LongInt;const buf;size: LongInt):LongInt; virtual;{$ifdef win32}abstract;{$endif}
  117. function myfdread(fd: LongInt;var buf;size: LongInt):LongInt; virtual;{$ifdef win32}abstract;{$endif}
  118. protected
  119. procedure dupnowatch(invalue:longint);
  120. end;
  121. ttimerwrapperinterface=class(tlcomponent)
  122. public
  123. function createwrappedtimer : tobject;virtual;abstract;
  124. // procedure setinitialevent(wrappedtimer : tobject;newvalue : boolean);virtual;abstract;
  125. procedure setontimer(wrappedtimer : tobject;newvalue:tnotifyevent);virtual;abstract;
  126. procedure setenabled(wrappedtimer : tobject;newvalue : boolean);virtual;abstract;
  127. procedure setinterval(wrappedtimer : tobject;newvalue : integer);virtual;abstract;
  128. end;
  129. var
  130. timerwrapperinterface : ttimerwrapperinterface;
  131. type
  132. {$ifdef win32}
  133. ttimeval = record
  134. tv_sec : longint;
  135. tv_usec : longint;
  136. end;
  137. {$endif}
  138. tltimer=class(tlcomponent)
  139. protected
  140. wrappedtimer : tobject;
  141. // finitialevent : boolean ;
  142. fontimer : tnotifyevent ;
  143. fenabled : boolean ;
  144. finterval : integer ; {miliseconds, default 1000}
  145. {$ifndef win32}
  146. procedure resettimes;
  147. {$endif}
  148. // procedure setinitialevent(newvalue : boolean);
  149. procedure setontimer(newvalue:tnotifyevent);
  150. procedure setenabled(newvalue : boolean);
  151. procedure setinterval(newvalue : integer);
  152. public
  153. //making theese public for now, this code should probablly be restructured later though
  154. prevtimer : tltimer ;
  155. nexttimer : tltimer ;
  156. nextts : ttimeval ;
  157. constructor create(aowner:tcomponent);override;
  158. destructor destroy;override;
  159. // property initialevent : boolean read finitialevent write setinitialevent;
  160. property ontimer : tnotifyevent read fontimer write setontimer;
  161. property enabled : boolean read fenabled write setenabled;
  162. property interval : integer read finterval write setinterval;
  163. end;
  164. ttaskevent=procedure(wparam,lparam:longint) of object;
  165. tltask=class(tobject)
  166. public
  167. handler : ttaskevent;
  168. obj : tobject;
  169. wparam : longint;
  170. lparam : longint;
  171. nexttask : tltask;
  172. constructor create(ahandler:ttaskevent;aobj:tobject;awparam,alparam:longint);
  173. end;
  174. teventcore=class
  175. public
  176. procedure processmessages; virtual;abstract;
  177. procedure messageloop; virtual;abstract;
  178. procedure exitmessageloop; virtual;abstract;
  179. procedure setfdreverse(fd : integer;reverseto : tlasio);virtual;abstract;
  180. procedure rmasterset(fd : integer;islistensocket : boolean); virtual;abstract;
  181. procedure rmasterclr(fd: integer); virtual;abstract;
  182. procedure wmasterset(fd : integer); virtual;abstract;
  183. procedure wmasterclr(fd: integer); virtual;abstract;
  184. end;
  185. var
  186. eventcore : teventcore;
  187. procedure processmessages;
  188. procedure messageloop;
  189. procedure exitmessageloop;
  190. var
  191. firsttimer : tltimer ;
  192. firsttask , lasttask , currenttask : tltask ;
  193. numread : integer ;
  194. mustrefreshfds : boolean ;
  195. { lcoretestcount:integer;}
  196. asinreleaseflag:boolean;
  197. procedure disconnecttasks(aobj:tobject);
  198. procedure addtask(ahandler:ttaskevent;aobj:tobject;awparam,alparam:longint);
  199. type
  200. tonaddtask = procedure(ahandler:ttaskevent;aobj:tobject;awparam,alparam:longint);
  201. var
  202. onaddtask : tonaddtask;
  203. procedure sleep(i:integer);
  204. {$ifndef nosignal}
  205. procedure prepsigpipe;{$ifndef ver1_0}inline;{$endif}
  206. {$endif}
  207. implementation
  208. {$ifndef nosignal}
  209. uses {sockets,}lloopback,lsignal;
  210. {$endif}
  211. {$ifdef win32}
  212. uses windows,winsock;
  213. {$endif}
  214. {$ifndef win32}
  215. {$include unixstuff.inc}
  216. {$endif}
  217. {$include ltimevalstuff.inc}
  218. {!!! added sleep call -beware}
  219. procedure sleep(i:integer);
  220. var
  221. tv:ttimeval;
  222. begin
  223. {$ifdef win32}
  224. windows.sleep(i);
  225. {$else}
  226. tv.tv_sec := i div 1000;
  227. tv.tv_usec := (i mod 1000) * 1000;
  228. select(0,nil,nil,nil,@tv);
  229. {$endif}
  230. end;
  231. destructor tlcomponent.destroy;
  232. begin
  233. disconnecttasks(self);
  234. inherited destroy;
  235. end;
  236. procedure tlcomponent.releasetaskhandler(wparam,lparam:longint);
  237. begin
  238. free;
  239. end;
  240. procedure tlcomponent.release;
  241. begin
  242. addtask(releasetaskhandler,self,0,0);
  243. end;
  244. procedure tlasio.release;
  245. begin
  246. asinreleaseflag := true;
  247. inherited release;
  248. end;
  249. procedure tlasio.doreceiveloop;
  250. begin
  251. if recvq.size = 0 then exit;
  252. if assigned(ondataavailable) then ondataavailable(self,0);
  253. if not (wsonoreceiveloop in componentoptions) then
  254. if recvq.size > 0 then tltask.create(self.doreceiveloop,self,0,0);
  255. end;
  256. function tlasio.receivestr;
  257. begin
  258. setlength(result,recvq.size);
  259. receive(@result[1],length(result));
  260. end;
  261. function tlasio.receive(Buf:Pointer;BufSize:integer):integer;
  262. var
  263. i,a,b:integer;
  264. p:pointer;
  265. begin
  266. i := bufsize;
  267. if recvq.size < i then i := recvq.size;
  268. a := 0;
  269. while (a < i) do begin
  270. b := recvq.get(p,i-a);
  271. move(p^,buf^,b);
  272. inc(taddrint(buf),b);
  273. recvq.del(b);
  274. inc(a,b);
  275. end;
  276. result := i;
  277. if wsonoreceiveloop in componentoptions then begin
  278. if recvq.size = 0 then eventcore.rmasterset(fdhandlein,false);
  279. end;
  280. end;
  281. constructor tlasio.create;
  282. begin
  283. inherited create(AOwner);
  284. if not assigned(eventcore) then raise exception.create('no event core');
  285. sendq := tfifo.create;
  286. recvq := tfifo.create;
  287. state := wsclosed;
  288. fdhandlein := -1;
  289. fdhandleout := -1;
  290. end;
  291. destructor tlasio.destroy;
  292. begin
  293. destroying := true;
  294. if state <> wsclosed then close;
  295. recvq.free;
  296. sendq.free;
  297. inherited destroy;
  298. end;
  299. procedure tlasio.close;
  300. begin
  301. internalclose(0);
  302. end;
  303. procedure tlasio.abort;
  304. begin
  305. close;
  306. end;
  307. procedure tlasio.fdcleanup;
  308. begin
  309. if fdhandlein <> -1 then begin
  310. eventcore.rmasterclr(fdhandlein); //fd_clr(fdhandlein,fdsrmaster)
  311. end;
  312. if fdhandleout <> -1 then begin
  313. eventcore.wmasterclr(fdhandleout);//fd_clr(fdhandleout,fdswmaster)
  314. end;
  315. if fdhandlein=fdhandleout then begin
  316. if fdhandlein <> -1 then begin
  317. myfdclose(fdhandlein);
  318. end;
  319. end else begin
  320. if fdhandlein <> -1 then begin
  321. myfdclose(fdhandlein);
  322. end;
  323. if fdhandleout <> -1 then begin
  324. myfdclose(fdhandleout);
  325. end;
  326. end;
  327. fdhandlein := -1;
  328. fdhandleout := -1;
  329. end;
  330. procedure tlasio.internalclose(error:word);
  331. begin
  332. if (state<>wsclosed) and (state<>wsinvalidstate) then begin
  333. // -2 is a special indication that we should just exist silently
  334. // (used for connect failure handling when socket creation fails)
  335. if (fdhandlein = -2) and (fdhandleout = -2) then exit;
  336. if (fdhandlein < 0) or (fdhandleout < 0) then raise exception.create('internalclose called with invalid fd handles');
  337. eventcore.rmasterclr(fdhandlein);//fd_clr(fdhandlein,fdsrmaster);
  338. eventcore.wmasterclr(fdhandleout);//fd_clr(fdhandleout,fdswmaster);
  339. if closehandles then begin
  340. {$ifndef win32}
  341. //anyone remember why this is here? --plugwash
  342. fcntl(fdhandlein,F_SETFL,0);
  343. {$endif}
  344. myfdclose(fdhandlein);
  345. if fdhandleout <> fdhandlein then begin
  346. {$ifndef win32}
  347. fcntl(fdhandleout,F_SETFL,0);
  348. {$endif}
  349. myfdclose(fdhandleout);
  350. end;
  351. eventcore.setfdreverse(fdhandlein,nil);
  352. eventcore.setfdreverse(fdhandleout,nil);
  353. fdhandlein := -1;
  354. fdhandleout := -1;
  355. end;
  356. state := wsclosed;
  357. if assigned(onsessionclosed) then if not destroying then onsessionclosed(self,error);
  358. end;
  359. if assigned(sendq) then sendq.del(maxlongint);
  360. end;
  361. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  362. { All exceptions *MUST* be handled. If an exception is not handled, the }
  363. { application will most likely be shut down ! }
  364. procedure tlasio.HandleBackGroundException(E: Exception);
  365. var
  366. CanAbort : Boolean;
  367. begin
  368. CanAbort := TRUE;
  369. { First call the error event handler, if any }
  370. if Assigned(OnBgException) then begin
  371. try
  372. OnBgException(Self, E, CanAbort);
  373. except
  374. end;
  375. end;
  376. { Then abort the socket }
  377. if CanAbort then begin
  378. try
  379. close;
  380. except
  381. end;
  382. end;
  383. end;
  384. procedure tlasio.sendstr(const str : string);
  385. begin
  386. putstringinsendbuffer(str);
  387. sendflush;
  388. end;
  389. procedure tlasio.putstringinsendbuffer(const newstring : string);
  390. begin
  391. if newstring <> '' then putdatainsendbuffer(@newstring[1],length(newstring));
  392. end;
  393. function tlasio.send(data:pointer;len:integer):integer;
  394. begin
  395. if state <> wsconnected then begin
  396. result := -1;
  397. exit;
  398. end;
  399. if len < 0 then len := 0;
  400. result := len;
  401. putdatainsendbuffer(data,len);
  402. sendflush;
  403. end;
  404. procedure tlasio.putdatainsendbuffer(data:pointer;len:integer);
  405. begin
  406. sendq.add(data,len);
  407. end;
  408. function tlasio.sendflush : integer;
  409. var
  410. lensent : integer;
  411. data:pointer;
  412. // fdstestr : fdset;
  413. // fdstestw : fdset;
  414. begin
  415. if state <> wsconnected then begin
  416. result := -1;
  417. exit;
  418. end;
  419. lensent := sendq.get(data,packetbasesize*2);
  420. if assigned(data) then result := myfdwrite(fdhandleout,data^,lensent) else result := 0;
  421. if result = -1 then lensent := 0 else lensent := result;
  422. //sendq := copy(sendq,lensent+1,length(sendq)-lensent);
  423. sendq.del(lensent);
  424. //fd_clr(fdhandleout,fdsw); // this prevents the socket being closed by a write
  425. // that sends nothing because a previous socket has
  426. // slready flushed this socket when the message loop
  427. // reaches it
  428. // if sendq.size > 0 then begin
  429. eventcore.wmasterset(fdhandleout);//fd_set(fdhandleout,fdswmaster);
  430. // end else begin
  431. // wmasterclr(fdhandleout);//fd_clr(fdhandleout,fdswmaster);
  432. // end;
  433. if result > 0 then begin
  434. if assigned(onsenddata) then onsenddata(self,result);
  435. // if sendq.size=0 then if assigned(ondatasent) then begin
  436. // tltask.create(self.dodatasent,self,0,0);
  437. // //begin test code
  438. // fd_zero(fdstestr);
  439. // fd_zero(fdstestw);
  440. // fd_set(fdhandlein,fdstestr);
  441. // fd_set(fdhandleout,fdstestw);
  442. // select(maxs,@fdstestr,@fdstestw,nil,0);
  443. // writeln(fd_isset(fdhandlein,fdstestr),' ',fd_isset(fdhandleout,fdstestw));
  444. // //end test code
  445. //
  446. // end;
  447. writtenthiscycle := true;
  448. end;
  449. end;
  450. procedure tlasio.dupnowatch(invalue:longint);
  451. begin
  452. { debugout('invalue='+inttostr(invalue));}
  453. //readln;
  454. if state<> wsclosed then close;
  455. fdhandlein := invalue;
  456. fdhandleout := invalue;
  457. eventcore.setfdreverse(fdhandlein,self);
  458. {$ifndef win32}
  459. fcntl(fdhandlein,F_SETFL,OPEN_NONBLOCK);
  460. {$endif}
  461. state := wsconnected;
  462. end;
  463. procedure tlasio.dup(invalue:longint);
  464. begin
  465. dupnowatch(invalue);
  466. eventcore.rmasterset(fdhandlein,false);//fd_set(fdhandlein,fdsrmaster);
  467. eventcore.wmasterclr(fdhandleout);//fd_clr(fdhandleout,fdswmaster);
  468. end;
  469. procedure tlasio.handlefdtrigger(readtrigger,writetrigger:boolean);
  470. var
  471. sendflushresult : integer;
  472. tempbuf:array[0..receivebufsize-1] of byte;
  473. a:integer;
  474. begin
  475. if (state=wsconnected) and writetrigger then begin
  476. //writeln('write trigger');
  477. if (sendq.size >0) then begin
  478. sendflushresult := sendflush;
  479. if (sendflushresult <= 0) and (not writtenthiscycle) then begin
  480. if sendflushresult=0 then begin // linuxerror := 0;
  481. internalclose(0);
  482. end else begin
  483. {$ifdef win32}
  484. if getlasterror=WSAEWOULDBLOCK then begin
  485. //the asynchronous nature of windows messages means we sometimes
  486. //get here with the buffer full
  487. //so do nothing in that case
  488. end else
  489. {$endif}
  490. begin
  491. internalclose({$ifdef win32}getlasterror{$else}linuxerror{$endif});
  492. end
  493. end;
  494. end;
  495. end else begin
  496. //everything is sent fire off ondatasent event
  497. if fdhandleout >= 0 then eventcore.wmasterclr(fdhandleout);//fd_clr(fdhandleout,fdswmaster);
  498. if assigned(ondatasent) then tltask.create(self.dodatasent,self,0,0);
  499. end;
  500. if assigned(onfdwrite) then onfdwrite(self,0);
  501. end;
  502. writtenthiscycle := false;
  503. if (state =wsconnected) and readtrigger then begin
  504. if recvq.size=0 then begin
  505. a := recvbufsize;
  506. if (a <= 0) or (a > sizeof(tempbuf)) then a := sizeof(tempbuf);
  507. numread := myfdread(fdhandlein,tempbuf,a);
  508. if (numread=0) and (not mustrefreshfds) then begin
  509. {if i remember correctly numread=0 is caused by eof
  510. if this isn't dealt with then you get a cpu eating infinite loop
  511. however if onsessionconencted has called processmessages that could
  512. cause us to drop to here with an empty recvq and nothing left to read
  513. and we don't want that to cause the socket to close}
  514. internalclose(0);
  515. end else if (numread=-1) then begin
  516. {$ifdef win32}
  517. //sometimes on windows we get stale messages due to the inherent delays
  518. //in the windows message queue
  519. if WSAGetLastError = wsaewouldblock then begin
  520. //do nothing
  521. end else
  522. {$endif}
  523. begin
  524. numread := 0;
  525. internalclose({$ifdef win32}wsagetlasterror{$else}linuxerror{$endif});
  526. end;
  527. end else if numread > 0 then recvq.add(@tempbuf,numread);
  528. end;
  529. if recvq.size > 0 then begin
  530. if wsonoreceiveloop in componentoptions then eventcore.rmasterclr(fdhandlein); //fd_clr(fdhandlein,fdsrmaster);
  531. if assigned(ondataavailable) then ondataAvailable(self,0);
  532. if not (wsonoreceiveloop in componentoptions) then if recvq.size > 0 then
  533. tltask.create(self.doreceiveloop,self,0,0);
  534. end;
  535. //until (numread = 0) or (currentsocket.state<>wsconnected);
  536. { debugout('inner loop complete');}
  537. end;
  538. end;
  539. procedure tlasio.flush;
  540. {$ifdef win32}
  541. type fdset = tfdset;
  542. {$endif}
  543. var
  544. fds : fdset;
  545. begin
  546. fd_zero(fds);
  547. fd_set(fdhandleout,fds);
  548. while sendq.size>0 do begin
  549. select(fdhandleout+1,nil,@fds,nil,nil);
  550. if sendflush <= 0 then exit;
  551. end;
  552. end;
  553. procedure tlasio.dodatasent(wparam,lparam:longint);
  554. begin
  555. if assigned(ondatasent) then ondatasent(self,lparam);
  556. end;
  557. procedure tlasio.deletebuffereddata;
  558. begin
  559. sendq.del(maxlongint);
  560. end;
  561. procedure tlasio.sinkdata(sender:tobject;error:word);
  562. begin
  563. tlasio(sender).recvq.del(maxlongint);
  564. end;
  565. {$ifndef win32}
  566. procedure tltimer.resettimes;
  567. begin
  568. gettimeofday(nextts);
  569. {if not initialevent then} tv_add(nextts,interval);
  570. end;
  571. {$endif}
  572. {procedure tltimer.setinitialevent(newvalue : boolean);
  573. begin
  574. if newvalue <> finitialevent then begin
  575. finitialevent := newvalue;
  576. if assigned(timerwrapperinterface) then begin
  577. timerwrapperinterface.setinitialevent(wrappedtimer,newvalue);
  578. end else begin
  579. resettimes;
  580. end;
  581. end;
  582. end;}
  583. procedure tltimer.setontimer(newvalue:tnotifyevent);
  584. begin
  585. if @newvalue <> @fontimer then begin
  586. fontimer := newvalue;
  587. if assigned(timerwrapperinterface) then begin
  588. timerwrapperinterface.setontimer(wrappedtimer,newvalue);
  589. end else begin
  590. end;
  591. end;
  592. end;
  593. procedure tltimer.setenabled(newvalue : boolean);
  594. begin
  595. if newvalue <> fenabled then begin
  596. fenabled := newvalue;
  597. if assigned(timerwrapperinterface) then begin
  598. timerwrapperinterface.setenabled(wrappedtimer,newvalue);
  599. end else begin
  600. {$ifdef win32}
  601. raise exception.create('non wrapper timers are not permitted on windows');
  602. {$else}
  603. resettimes;
  604. {$endif}
  605. end;
  606. end;
  607. end;
  608. procedure tltimer.setinterval(newvalue:integer);
  609. begin
  610. if newvalue <> finterval then begin
  611. finterval := newvalue;
  612. if assigned(timerwrapperinterface) then begin
  613. timerwrapperinterface.setinterval(wrappedtimer,newvalue);
  614. end else begin
  615. {$ifdef win32}
  616. raise exception.create('non wrapper timers are not permitted on windows');
  617. {$else}
  618. resettimes;
  619. {$endif}
  620. end;
  621. end;
  622. end;
  623. constructor tltimer.create;
  624. begin
  625. inherited create(AOwner);
  626. if assigned(timerwrapperinterface) then begin
  627. wrappedtimer := timerwrapperinterface.createwrappedtimer;
  628. end else begin
  629. nexttimer := firsttimer;
  630. prevtimer := nil;
  631. if assigned(nexttimer) then nexttimer.prevtimer := self;
  632. firsttimer := self;
  633. end;
  634. interval := 1000;
  635. enabled := true;
  636. end;
  637. destructor tltimer.destroy;
  638. begin
  639. if assigned(timerwrapperinterface) then begin
  640. wrappedtimer.free;
  641. end else begin
  642. if prevtimer <> nil then begin
  643. prevtimer.nexttimer := nexttimer;
  644. end else begin
  645. firsttimer := nexttimer;
  646. end;
  647. if nexttimer <> nil then begin
  648. nexttimer.prevtimer := prevtimer;
  649. end;
  650. end;
  651. inherited destroy;
  652. end;
  653. constructor tltask.create(ahandler:ttaskevent;aobj:tobject;awparam,alparam:longint);
  654. begin
  655. inherited create;
  656. if assigned(onaddtask) then onaddtask(ahandler,aobj,awparam,alparam);
  657. handler := ahandler;
  658. obj := aobj;
  659. wparam := awparam;
  660. lparam := alparam;
  661. {nexttask := firsttask;
  662. firsttask := self;}
  663. if assigned(lasttask) then begin
  664. lasttask.nexttask := self;
  665. end else begin
  666. firsttask := self;
  667. end;
  668. lasttask := self;
  669. //ahandler(wparam,lparam);
  670. end;
  671. procedure addtask(ahandler:ttaskevent;aobj:tobject;awparam,alparam:longint);
  672. begin
  673. tltask.create(ahandler,aobj,awparam,alparam);
  674. end;
  675. {$ifndef nosignal}
  676. procedure prepsigpipe;{$ifndef ver1_0}inline;
  677. {$endif}
  678. begin
  679. starthandlesignal(sigpipe);
  680. if not assigned(signalloopback) then begin
  681. signalloopback := tlloopback.create(nil);
  682. signalloopback.ondataAvailable := signalloopback.sinkdata;
  683. end;
  684. end;
  685. {$endif}
  686. procedure processtasks;//inline;
  687. var
  688. temptask : tltask ;
  689. begin
  690. if not assigned(currenttask) then begin
  691. currenttask := firsttask;
  692. firsttask := nil;
  693. lasttask := nil;
  694. end;
  695. while assigned(currenttask) do begin
  696. if assigned(currenttask.handler) then currenttask.handler(currenttask.wparam,currenttask.lparam);
  697. if assigned(currenttask) then begin
  698. temptask := currenttask;
  699. currenttask := currenttask.nexttask;
  700. temptask.free;
  701. end;
  702. //writeln('processed a task');
  703. end;
  704. end;
  705. procedure disconnecttasks(aobj:tobject);
  706. var
  707. currenttasklocal : tltask ;
  708. counter : byte ;
  709. begin
  710. for counter := 0 to 1 do begin
  711. if counter = 0 then begin
  712. currenttasklocal := firsttask; //main list of tasks
  713. end else begin
  714. currenttasklocal := currenttask; //needed in case called from a task
  715. end;
  716. // note i don't bother to sestroy the links here as that will happen when
  717. // the list of tasks is processed anyway
  718. while assigned(currenttasklocal) do begin
  719. if currenttasklocal.obj = aobj then begin
  720. currenttasklocal.obj := nil;
  721. currenttasklocal.handler := nil;
  722. end;
  723. currenttasklocal := currenttasklocal.nexttask;
  724. end;
  725. end;
  726. end;
  727. procedure processmessages;
  728. begin
  729. eventcore.processmessages;
  730. end;
  731. procedure messageloop;
  732. begin
  733. eventcore.messageloop;
  734. end;
  735. procedure exitmessageloop;
  736. begin
  737. eventcore.exitmessageloop;
  738. end;
  739. function tlasio.RealSend(Data : Pointer; Len : Integer) : Integer;
  740. begin
  741. result := myfdwrite(fdhandleout,data^,len);
  742. if (result > 0) and assigned(onsenddata) then onsenddata(self,result);
  743. eventcore.wmasterset(fdhandleout);
  744. end;
  745. {$ifndef win32}
  746. procedure tlasio.myfdclose(fd : integer);
  747. begin
  748. fdclose(fd);
  749. end;
  750. function tlasio.myfdwrite(fd: LongInt;const buf;size: LongInt):LongInt;
  751. begin
  752. result := fdwrite(fd,buf,size);
  753. end;
  754. function tlasio.myfdread(fd: LongInt;var buf;size: LongInt):LongInt;
  755. begin
  756. result := fdread(fd,buf,size);
  757. end;
  758. {$endif}
  759. begin
  760. firsttask := nil;
  761. {$ifndef nosignal}
  762. signalloopback := nil;
  763. {$endif}
  764. end.