X-Git-Url: http://www.lcore.org/git/lcore.git/blobdiff_plain/6cb6b7ede2d178e03fa817bc28474c175f5a93b9..42a61c59a81b03130f61e805474198eada033cd8:/httpserver_20080306/lcore.pas?ds=inline diff --git a/httpserver_20080306/lcore.pas b/httpserver_20080306/lcore.pas deleted file mode 100755 index 51fbf78..0000000 --- a/httpserver_20080306/lcore.pas +++ /dev/null @@ -1,889 +0,0 @@ -{lsocket.pas} - -{io and timer code by plugwash} - -{ Copyright (C) 2005 Bas Steendijk and Peter Green - For conditions of distribution and use, see copyright notice in zlib_license.txt - which is included in the package - ----------------------------------------------------------------------------- } - -{note: you must use the @ in the last param to tltask.create not doing so will - compile without error but will cause an access violation -pg} - -//note: events after release are normal and are the apps responsibility to deal with safely - -unit lcore; -{$ifdef fpc} - {$mode delphi} -{$endif} -{$ifdef win32} - {$define nosignal} -{$endif} -interface - uses - sysutils, - {$ifndef win32} - {$ifdef VER1_0} - linux, - {$else} - baseunix,unix, - {$endif} - fd_utils, - {$endif} - classes,pgtypes,bfifo; - procedure processtasks; - - - - - - - - const - receivebufsize=1460; - - type - {$ifdef ver1_0} - sigset= array[0..31] of longint; - {$endif} - - ESocketException = class(Exception); - TBgExceptionEvent = procedure (Sender : TObject; - E : Exception; - var CanClose : Boolean) of object; - - // note : tsocketstate is defined in the same way as it is in François PIETTE's twsocket - // however tlsocket currently only uses wsClosed wsConnecting wsconnected and wsListening - TSocketState = (wsInvalidState, - wsOpened, wsBound, - wsConnecting, wsConnected, - wsAccepting, wsListening, - wsClosed); - - TWSocketOption = (wsoNoReceiveLoop, wsoTcpNoDelay); - TWSocketOptions = set of TWSocketOption; - - TSocketevent = procedure(Sender: TObject; Error: word) of object; - //Tdataavailevent = procedure(data : string); - TSendData = procedure (Sender: TObject; BytesSent: Integer) of object; - - tlcomponent = class(tcomponent) - public - released:boolean; - procedure release; virtual; - destructor destroy; override; - end; - - tlasio = class(tlcomponent) - public - state : tsocketstate ; - ComponentOptions : TWSocketOptions; - fdhandlein : Longint ; {file discriptor} - fdhandleout : Longint ; {file discriptor} - - onsessionclosed : tsocketevent ; - ondataAvailable : tsocketevent ; - onsessionAvailable : tsocketevent ; - - onsessionconnected : tsocketevent ; - onsenddata : tsenddata ; - ondatasent : tsocketevent ; - //connected : boolean ; - nextasin : tlasio ; - prevasin : tlasio ; - - recvq : tfifo; - OnBgException : TBgExceptionEvent ; - //connectread : boolean ; - sendq : tfifo; - closehandles : boolean ; - writtenthiscycle : boolean ; - onfdwrite : procedure (Sender: TObject; Error: word) of object; //added for bewarehttpd - lasterror:integer; - destroying:boolean; - function receivestr:string; virtual; - procedure close; - procedure abort; - procedure internalclose(error:word); virtual; - constructor Create(AOwner: TComponent); override; - - destructor destroy; override; - procedure fdcleanup; - procedure HandleBackGroundException(E: Exception); - procedure handlefdtrigger(readtrigger,writetrigger:boolean); virtual; - procedure dup(invalue:longint); - - function sendflush : integer; - procedure sendstr(const str : string);virtual; - procedure putstringinsendbuffer(const newstring : string); - function send(data:pointer;len:integer):integer;virtual; - procedure putdatainsendbuffer(data:pointer;len:integer); virtual; - procedure deletebuffereddata; - - //procedure messageloop; - function Receive(Buf:Pointer;BufSize:integer):integer; virtual; - procedure flush;virtual;{$ifdef win32} abstract;{$endif} - procedure dodatasent(wparam,lparam:longint); - procedure doreceiveloop(wparam,lparam:longint); - procedure sinkdata(sender:tobject;error:word); - - procedure release; override; {test -beware} - - function RealSend(Data : Pointer; Len : Integer) : Integer; //added for bewarehttpd - - procedure myfdclose(fd : integer); virtual;{$ifdef win32}abstract;{$endif} - function myfdwrite(fd: LongInt;const buf;size: LongInt):LongInt; virtual;{$ifdef win32}abstract;{$endif} - function myfdread(fd: LongInt;var buf;size: LongInt):LongInt; virtual;{$ifdef win32}abstract;{$endif} - protected - procedure dupnowatch(invalue:longint); - end; - ttimerwrapperinterface=class(tlcomponent) - public - function createwrappedtimer : tobject;virtual;abstract; -// procedure setinitialevent(wrappedtimer : tobject;newvalue : boolean);virtual;abstract; - procedure setontimer(wrappedtimer : tobject;newvalue:tnotifyevent);virtual;abstract; - procedure setenabled(wrappedtimer : tobject;newvalue : boolean);virtual;abstract; - procedure setinterval(wrappedtimer : tobject;newvalue : integer);virtual;abstract; - end; - - var - timerwrapperinterface : ttimerwrapperinterface; - type - {$ifdef win32} - ttimeval = record - tv_sec : longint; - tv_usec : longint; - end; - {$endif} - tltimer=class(tlcomponent) - protected - - - wrappedtimer : tobject; - - -// finitialevent : boolean ; - fontimer : tnotifyevent ; - fenabled : boolean ; - finterval : integer ; {miliseconds, default 1000} - {$ifndef win32} - procedure resettimes; - {$endif} -// procedure setinitialevent(newvalue : boolean); - procedure setontimer(newvalue:tnotifyevent); - procedure setenabled(newvalue : boolean); - procedure setinterval(newvalue : integer); - public - //making theese public for now, this code should probablly be restructured later though - prevtimer : tltimer ; - nexttimer : tltimer ; - nextts : ttimeval ; - - constructor create(aowner:tcomponent);override; - destructor destroy;override; -// property initialevent : boolean read finitialevent write setinitialevent; - property ontimer : tnotifyevent read fontimer write setontimer; - property enabled : boolean read fenabled write setenabled; - property interval : integer read finterval write setinterval; - - end; - - ttaskevent=procedure(wparam,lparam:longint) of object; - - tltask=class(tobject) - public - handler : ttaskevent; - obj : tobject; - wparam : longint; - lparam : longint; - nexttask : tltask; - constructor create(ahandler:ttaskevent;aobj:tobject;awparam,alparam:longint); - end; - - - - teventcore=class - public - procedure processmessages; virtual;abstract; - procedure messageloop; virtual;abstract; - procedure exitmessageloop; virtual;abstract; - procedure setfdreverse(fd : integer;reverseto : tlasio);virtual;abstract; - procedure rmasterset(fd : integer;islistensocket : boolean); virtual;abstract; - procedure rmasterclr(fd: integer); virtual;abstract; - procedure wmasterset(fd : integer); virtual;abstract; - procedure wmasterclr(fd: integer); virtual;abstract; - end; -var - eventcore : teventcore; - -procedure processmessages; -procedure messageloop; -procedure exitmessageloop; - -var - firstasin : tlasio ; - firsttimer : tltimer ; - firsttask , lasttask , currenttask : tltask ; - - numread : integer ; - mustrefreshfds : boolean ; -{ lcoretestcount:integer;} - - asinreleaseflag:boolean; - - -procedure disconnecttasks(aobj:tobject); -procedure addtask(ahandler:ttaskevent;aobj:tobject;awparam,alparam:longint); -type - tonaddtask = procedure(ahandler:ttaskevent;aobj:tobject;awparam,alparam:longint); -var - onaddtask : tonaddtask; - - -procedure sleep(i:integer); -{$ifndef nosignal} - procedure prepsigpipe;inline; -{$endif} - - -implementation -{$ifndef nosignal} - uses {sockets,}lloopback,lsignal; -{$endif} -{$ifdef win32} - uses windows; -{$endif} -{$ifndef win32} - {$include unixstuff.inc} -{$endif} -{$include ltimevalstuff.inc} - - -{!!! added sleep call -beware} -procedure sleep(i:integer); -var - tv:ttimeval; -begin - {$ifdef win32} - windows.sleep(i); - {$else} - tv.tv_sec := i div 1000; - tv.tv_usec := (i mod 1000) * 1000; - select(0,nil,nil,nil,@tv); - {$endif} -end; - -destructor tlcomponent.destroy; -begin - disconnecttasks(self); - inherited destroy; -end; - - - - -procedure tlcomponent.release; -begin - released := true; -end; - -procedure tlasio.release; -begin - asinreleaseflag := true; - inherited release; -end; - -procedure tlasio.doreceiveloop; -begin - if recvq.size = 0 then exit; - if assigned(ondataavailable) then ondataavailable(self,0); - if not (wsonoreceiveloop in componentoptions) then - if recvq.size > 0 then tltask.create(self.doreceiveloop,self,0,0); -end; - -function tlasio.receivestr; -begin - setlength(result,recvq.size); - receive(@result[1],length(result)); -end; - -function tlasio.receive(Buf:Pointer;BufSize:integer):integer; -var - i,a,b:integer; - p:pointer; -begin - i := bufsize; - if recvq.size < i then i := recvq.size; - a := 0; - while (a < i) do begin - b := recvq.get(p,i-a); - move(p^,buf^,b); - inc(taddrint(buf),b); - recvq.del(b); - inc(a,b); - end; - result := i; - if wsonoreceiveloop in componentoptions then begin - if recvq.size = 0 then eventcore.rmasterset(fdhandlein,false); - end; -end; - -constructor tlasio.create; -begin - inherited create(AOwner); - sendq := tfifo.create; - recvq := tfifo.create; - state := wsclosed; - fdhandlein := -1; - fdhandleout := -1; - nextasin := firstasin; - prevasin := nil; - if assigned(nextasin) then nextasin.prevasin := self; - firstasin := self; - - released := false; -end; - -destructor tlasio.destroy; -begin - destroying := true; - if state <> wsclosed then close; - if prevasin <> nil then begin - prevasin.nextasin := nextasin; - end else begin - firstasin := nextasin; - end; - if nextasin <> nil then begin - nextasin.prevasin := prevasin; - end; - recvq.destroy; - sendq.destroy; - inherited destroy; -end; - -procedure tlasio.close; -begin - internalclose(0); -end; - -procedure tlasio.abort; -begin - close; -end; - -procedure tlasio.fdcleanup; -begin - if fdhandlein <> -1 then begin - eventcore.rmasterclr(fdhandlein); //fd_clr(fdhandlein,fdsrmaster) - end; - if fdhandleout <> -1 then begin - eventcore.wmasterclr(fdhandleout);//fd_clr(fdhandleout,fdswmaster) - end; - if fdhandlein=fdhandleout then begin - if fdhandlein <> -1 then begin - myfdclose(fdhandlein); - end; - end else begin - if fdhandlein <> -1 then begin - myfdclose(fdhandlein); - end; - if fdhandleout <> -1 then begin - myfdclose(fdhandleout); - end; - end; - fdhandlein := -1; - fdhandleout := -1; -end; - -procedure tlasio.internalclose(error:word); -begin - if state<>wsclosed then begin - if (fdhandlein < 0) or (fdhandleout < 0) then raise exception.create('internalclose called with invalid fd handles'); - eventcore.rmasterclr(fdhandlein);//fd_clr(fdhandlein,fdsrmaster); - eventcore.wmasterclr(fdhandleout);//fd_clr(fdhandleout,fdswmaster); - - if closehandles then begin - {$ifndef win32} - //anyone remember why this is here? --plugwash - fcntl(fdhandlein,F_SETFL,0); - {$endif} - myfdclose(fdhandlein); - if fdhandleout <> fdhandlein then begin - {$ifndef win32} - fcntl(fdhandleout,F_SETFL,0); - {$endif} - myfdclose(fdhandleout); - end; - eventcore.setfdreverse(fdhandlein,nil); - eventcore.setfdreverse(fdhandleout,nil); - - fdhandlein := -1; - fdhandleout := -1; - end; - state := wsclosed; - - if assigned(onsessionclosed) then if not destroying then onsessionclosed(self,error); - end; - sendq.del(maxlongint); -end; - - -{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} -{ All exceptions *MUST* be handled. If an exception is not handled, the } -{ application will most likely be shut down ! } -procedure tlasio.HandleBackGroundException(E: Exception); -var - CanAbort : Boolean; -begin - CanAbort := TRUE; - { First call the error event handler, if any } - if Assigned(OnBgException) then begin - try - OnBgException(Self, E, CanAbort); - except - end; - end; - { Then abort the socket } - if CanAbort then begin - try - close; - except - end; - end; -end; - -procedure tlasio.sendstr(const str : string); -begin - putstringinsendbuffer(str); - sendflush; -end; - -procedure tlasio.putstringinsendbuffer(const newstring : string); -begin - if newstring <> '' then putdatainsendbuffer(@newstring[1],length(newstring)); -end; - -function tlasio.send(data:pointer;len:integer):integer; -begin - if state <> wsconnected then begin - result := -1; - exit; - end; - if len < 0 then len := 0; - result := len; - putdatainsendbuffer(data,len); - sendflush; -end; - - -procedure tlasio.putdatainsendbuffer(data:pointer;len:integer); -begin - sendq.add(data,len); -end; - -function tlasio.sendflush : integer; -var - lensent : integer; - data:pointer; -// fdstestr : fdset; -// fdstestw : fdset; -begin - if state <> wsconnected then exit; - - lensent := sendq.get(data,2920); - if assigned(data) then result := myfdwrite(fdhandleout,data^,lensent) else result := 0; - - if result = -1 then lensent := 0 else lensent := result; - - //sendq := copy(sendq,lensent+1,length(sendq)-lensent); - sendq.del(lensent); - - //fd_clr(fdhandleout,fdsw); // this prevents the socket being closed by a write - // that sends nothing because a previous socket has - // slready flushed this socket when the message loop - // reaches it -// if sendq.size > 0 then begin - eventcore.wmasterset(fdhandleout);//fd_set(fdhandleout,fdswmaster); -// end else begin -// wmasterclr(fdhandleout);//fd_clr(fdhandleout,fdswmaster); -// end; - if result > 0 then begin - if assigned(onsenddata) then onsenddata(self,result); -// if sendq.size=0 then if assigned(ondatasent) then begin -// tltask.create(self.dodatasent,self,0,0); -// //begin test code -// fd_zero(fdstestr); -// fd_zero(fdstestw); -// fd_set(fdhandlein,fdstestr); -// fd_set(fdhandleout,fdstestw); -// select(maxs,@fdstestr,@fdstestw,nil,0); -// writeln(fd_isset(fdhandlein,fdstestr),' ',fd_isset(fdhandleout,fdstestw)); -// //end test code -// -// end; - writtenthiscycle := true; - end; -end; - -procedure tlasio.dupnowatch(invalue:longint); -begin - { debugout('invalue='+inttostr(invalue));} - //readln; - if state<> wsclosed then close; - fdhandlein := invalue; - fdhandleout := invalue; - eventcore.setfdreverse(fdhandlein,self); - {$ifndef win32} - fcntl(fdhandlein,F_SETFL,OPEN_NONBLOCK); - {$endif} - state := wsconnected; - -end; - - -procedure tlasio.dup(invalue:longint); -begin - dupnowatch(invalue); - eventcore.rmasterset(fdhandlein,false);//fd_set(fdhandlein,fdsrmaster); - eventcore.wmasterclr(fdhandleout);//fd_clr(fdhandleout,fdswmaster); -end; - - -procedure tlasio.handlefdtrigger(readtrigger,writetrigger:boolean); -var - sendflushresult : integer; - tempbuf:array[0..receivebufsize-1] of byte; -begin - if (state=wsconnected) and writetrigger then begin - //writeln('write trigger'); - - if (sendq.size >0) then begin - - sendflushresult := sendflush; - if (sendflushresult <= 0) and (not writtenthiscycle) then begin - if sendflushresult=0 then begin // linuxerror := 0; - internalclose(0); - - end else begin - internalclose({$ifdef win32}getlasterror{$else}linuxerror{$endif}); - end; - end; - - end else begin - //everything is sent fire off ondatasent event - if fdhandleout >= 0 then eventcore.wmasterclr(fdhandleout);//fd_clr(fdhandleout,fdswmaster); - if assigned(ondatasent) then tltask.create(self.dodatasent,self,0,0); - end; - if assigned(onfdwrite) then onfdwrite(self,0); - end; - writtenthiscycle := false; - if (state =wsconnected) and readtrigger then begin - if recvq.size=0 then begin - numread := myfdread(fdhandlein,tempbuf,sizeof(tempbuf)); - if (numread=0) and (not mustrefreshfds) then begin - {if i remember correctly numread=0 is caused by eof - if this isn't dealt with then you get a cpu eating infinite loop - however if onsessionconencted has called processmessages that could - cause us to drop to here with an empty recvq and nothing left to read - and we don't want that to cause the socket to close} - - internalclose(0); - end else if (numread=-1) then begin - numread := 0; - internalclose({$ifdef win32}getlasterror{$else}linuxerror{$endif}); - end else if numread > 0 then recvq.add(@tempbuf,numread); - end; - - if recvq.size > 0 then begin - if wsonoreceiveloop in componentoptions then eventcore.rmasterclr(fdhandlein); //fd_clr(fdhandlein,fdsrmaster); - if assigned(ondataavailable) then ondataAvailable(self,0); - if not (wsonoreceiveloop in componentoptions) then if recvq.size > 0 then - tltask.create(self.doreceiveloop,self,0,0); - end; - //until (numread = 0) or (currentsocket.state<>wsconnected); -{ debugout('inner loop complete');} - end; -end; - -{$ifndef win32} - procedure tlasio.flush; - var - fds : fdset; - begin - fd_zero(fds); - fd_set(fdhandleout,fds); - while sendq.size>0 do begin - select(fdhandleout+1,nil,@fds,nil,nil); - if sendflush <= 0 then exit; - end; - end; -{$endif} - -procedure tlasio.dodatasent(wparam,lparam:longint); -begin - if assigned(ondatasent) then ondatasent(self,lparam); -end; - -procedure tlasio.deletebuffereddata; -begin - sendq.del(maxlongint); -end; - -procedure tlasio.sinkdata(sender:tobject;error:word); -begin - tlasio(sender).recvq.del(maxlongint); -end; - -{$ifndef win32} - procedure tltimer.resettimes; - begin - gettimeofday(nextts); - {if not initialevent then} tv_add(nextts,interval); - end; -{$endif} - -{procedure tltimer.setinitialevent(newvalue : boolean); -begin - if newvalue <> finitialevent then begin - finitialevent := newvalue; - if assigned(timerwrapperinterface) then begin - timerwrapperinterface.setinitialevent(wrappedtimer,newvalue); - end else begin - resettimes; - end; - end; -end;} - -procedure tltimer.setontimer(newvalue:tnotifyevent); -begin - if @newvalue <> @fontimer then begin - fontimer := newvalue; - if assigned(timerwrapperinterface) then begin - timerwrapperinterface.setontimer(wrappedtimer,newvalue); - end else begin - - end; - end; - -end; - - -procedure tltimer.setenabled(newvalue : boolean); -begin - if newvalue <> fenabled then begin - fenabled := newvalue; - if assigned(timerwrapperinterface) then begin - timerwrapperinterface.setenabled(wrappedtimer,newvalue); - end else begin - {$ifdef win32} - raise exception.create('non wrapper timers are not permitted on windows'); - {$else} - resettimes; - {$endif} - end; - end; -end; - -procedure tltimer.setinterval(newvalue:integer); -begin - if newvalue <> finterval then begin - finterval := newvalue; - if assigned(timerwrapperinterface) then begin - timerwrapperinterface.setinterval(wrappedtimer,newvalue); - end else begin - {$ifdef win32} - raise exception.create('non wrapper timers are not permitted on windows'); - {$else} - resettimes; - {$endif} - end; - end; - -end; - - - - -constructor tltimer.create; -begin - inherited create(AOwner); - if assigned(timerwrapperinterface) then begin - wrappedtimer := timerwrapperinterface.createwrappedtimer; - end else begin - - - nexttimer := firsttimer; - prevtimer := nil; - - if assigned(nexttimer) then nexttimer.prevtimer := self; - firsttimer := self; - end; - interval := 1000; - enabled := true; - released := false; - -end; - -destructor tltimer.destroy; -begin - if assigned(timerwrapperinterface) then begin - wrappedtimer.free; - end else begin - if prevtimer <> nil then begin - prevtimer.nexttimer := nexttimer; - end else begin - firsttimer := nexttimer; - end; - if nexttimer <> nil then begin - nexttimer.prevtimer := prevtimer; - end; - - end; - inherited destroy; -end; - -constructor tltask.create(ahandler:ttaskevent;aobj:tobject;awparam,alparam:longint); -begin - inherited create; - if assigned(onaddtask) then onaddtask(ahandler,aobj,awparam,alparam); - handler := ahandler; - obj := aobj; - wparam := awparam; - lparam := alparam; - {nexttask := firsttask; - firsttask := self;} - if assigned(lasttask) then begin - lasttask.nexttask := self; - end else begin - firsttask := self; - end; - lasttask := self; - //ahandler(wparam,lparam); -end; - -procedure addtask(ahandler:ttaskevent;aobj:tobject;awparam,alparam:longint); -begin - - tltask.create(ahandler,aobj,awparam,alparam); -end; - - - - -{$ifndef nosignal} - procedure prepsigpipe;inline; - begin - starthandlesignal(sigpipe); - if not assigned(signalloopback) then begin - signalloopback := tlloopback.create(nil); - signalloopback.ondataAvailable := signalloopback.sinkdata; - - end; - - end; -{$endif} - -procedure processtasks;//inline; -var - temptask : tltask ; - -begin - - if not assigned(currenttask) then begin - currenttask := firsttask; - firsttask := nil; - lasttask := nil; - end; - while assigned(currenttask) do begin - - if assigned(currenttask.handler) then currenttask.handler(currenttask.wparam,currenttask.lparam); - if assigned(currenttask) then begin - temptask := currenttask; - currenttask := currenttask.nexttask; - temptask.free; - end; - //writeln('processed a task'); - end; - -end; - - - - -procedure disconnecttasks(aobj:tobject); -var - currenttasklocal : tltask ; - counter : byte ; -begin - for counter := 0 to 1 do begin - if counter = 0 then begin - currenttasklocal := firsttask; //main list of tasks - end else begin - currenttasklocal := currenttask; //needed in case called from a task - end; - // note i don't bother to sestroy the links here as that will happen when - // the list of tasks is processed anyway - while assigned(currenttasklocal) do begin - if currenttasklocal.obj = aobj then begin - currenttasklocal.obj := nil; - currenttasklocal.handler := nil; - end; - currenttasklocal := currenttasklocal.nexttask; - end; - end; -end; - - -procedure processmessages; -begin - eventcore.processmessages; -end; -procedure messageloop; -begin - eventcore.messageloop; -end; - -procedure exitmessageloop; -begin - eventcore.exitmessageloop; -end; - -function tlasio.RealSend(Data : Pointer; Len : Integer) : Integer; -begin - result := myfdwrite(fdhandleout,data^,len); - if (result > 0) and assigned(onsenddata) then onsenddata(self,result); - eventcore.wmasterset(fdhandleout); -end; -{$ifndef win32} - procedure tlasio.myfdclose(fd : integer); - begin - fdclose(fd); - end; - function tlasio.myfdwrite(fd: LongInt;const buf;size: LongInt):LongInt; - begin - result := fdwrite(fd,buf,size); - end; - - function tlasio.myfdread(fd: LongInt;var buf;size: LongInt):LongInt; - begin - result := fdread(fd,buf,size); - end; - - -{$endif} - - -begin - firstasin := nil; - firsttask := nil; - - - {$ifndef nosignal} - signalloopback := nil; - {$endif} -end. - - - - -