From 96aa8e66aa85641a09c22a58d484dcdb73de3088 Mon Sep 17 00:00:00 2001 From: Tomas Brod Date: Fri, 21 Aug 2015 20:20:30 +0200 Subject: [PATCH] Watch other fds in server loop. --- ServerLoop.pas | 119 ++++++++++++++++++++++++++++++++++++++++++--------------- TestWatch.pas | 33 ++++++++++++++++ brodnetd.pas | 4 ++ 3 files changed, 125 insertions(+), 31 deletions(-) create mode 100644 TestWatch.pas diff --git a/ServerLoop.pas b/ServerLoop.pas index 8c4f865..fc9fea8 100644 --- a/ServerLoop.pas +++ b/ServerLoop.pas @@ -3,7 +3,7 @@ UNIT ServerLoop; INTERFACE uses MemStream,NetAddr; -procedure Loop; +procedure Main; type tSMsg=object Source: ^tNetAddr; @@ -15,9 +15,12 @@ type tSMsg=object type tMessageHandler=procedure(msg:tSMsg); -procedure SetOpcodeMsgHandler(OpCode:byte; handler:tMessageHandler); +procedure SetMsgHandler(OpCode:byte; handler:tMessageHandler); procedure SetHiMsgHandler(handler:tMessageHandler); +type tFDEventHandler=procedure(ev:Word) of object; +procedure WatchFD(fd:tHandle; h:tFDEventHandler); + IMPLEMENTATION USES SysUtils,Sockets,UnixType,BaseUnix @@ -25,8 +28,19 @@ USES SysUtils,Sockets,UnixType,BaseUnix {aim for most simple implementation, since could be extended anytime} +type tPollTop=0..7; var s_inet:tSocket; -var pollArr: array [0..0] of tPollFd; +var pollArr: packed array [tPollTop] of tPollFd; +var hnd: array [1..36] of tMessageHandler; +var HiHnd: tMessageHandler; +type tFdHndDsc=record + cb: tFDEventHandler; {proc+object} + end; +var pollHnd: array [tPollTop] of tFdHndDsc; +var pollTop: tPollTop; + +procedure IdleStuff; +begin write('.'); end; procedure SC(fn:pointer; retval:cint); begin @@ -48,7 +62,7 @@ procedure s_SetupInet; SC(@fpBind,fpBind(s_inet,@bind_addr,sizeof(bind_addr))); with PollArr[0] do begin fd:=s_inet; - events:=pollIN or pollERR; + events:=pollIN; revents:=0; end; end; @@ -61,22 +75,6 @@ procedure SendMessage(const data; len:word; const rcpt:tSockAddr ); SC(@fpsendto,fpsendto(s_inet,@data,len,0,@rcpt,sizeof(sockaddr_in))); end; -procedure HandleMsg(s:tSocket; const buffer; len:LongWord; from:tSockAddr); - begin - writeln; - write('HandleMsg: '); - if len<1 then exit; - case char((@buffer+0)^) of - 'b':writeln('Brod-Net'); - 'd':begin - writeln('Mainline DHT'); - RPC.SendMessage:=@SendMessage; - RPC.ReceiveMessage(buffer,len,from); - end; - else writeln('Unknown'); - end; - end; - procedure SignalHandler(sig:cint);CDecl; begin writeln; @@ -85,35 +83,94 @@ procedure SignalHandler(sig:cint);CDecl; writeln('Shutdown requested'); end; -procedure Loop; +{do not waste stack on statics} var EventsCount:integer; var Buffer:array [1..1024] of byte; var pkLen:LongWord; - var From:tSockAddr; + var From:tSockAddrL; {use larger struct so everything fits} var FromLen:LongWord; + var FromG:tNetAddr; + var curhnd:tMessageHandler; + var Msg:tSMsg; + var tp:tPollTop; + +procedure PrepareHandler; begin - EventsCount:=fpPoll(@PollArr[0],1,5000); - if eventscount=0 then write('.') else begin + FromG.FromSocket(from); + if Buffer[1]>128 then curhnd:=HiHnd else curhnd:=hnd[Buffer[1]]; + if not assigned(curhnd) then raise eXception.Create('No handler for opcode '+IntToStr(Buffer[1])); + Msg.Source:=@FromG; {!thread} + Msg.Length:=pkLen; + Msg.Data:=@Buffer; {!thread} + Msg.stream.Init(@Buffer,pkLen,sizeof(Buffer)); + Msg.channel:=0; {!multisocket} +end; + +procedure Main; + begin + s_setupInet; + while not terminated do begin + EventsCount:=fpPoll(@PollArr[0],PollTop,5000); + if (eventscount=-1)and terminated then break; + if eventscount=-1 then break; {fixme: print error} + if eventscount=0 then IdleStuff else begin {INET socket} with PollArr[0] do begin if (revents and pollIN)>0 then begin FromLen:=sizeof(From); pkLen:=fprecvfrom(s_inet,@Buffer,sizeof(Buffer),0,@from,@fromlen); - SC(@fprecvfrom,fromlen); - HandleMsg(s_inet,Buffer,pkLen,from); + SC(@fprecvfrom,pkLen); + PrepareHandler; + curhnd(Msg); revents:=0; end; end; {INET6...} + {Generic} + for tp:=1 to pollTop do if PollArr[tp].revents>0 then begin + PollHnd[tp].CB(PollArr[tp].rEvents); + PollArr[tp].revents:=0; + end; + end; + end; + write('Loop broken ['); + CloseSocket(s_inet); + writeln(']'); +end; + +procedure SetMsgHandler(OpCode:byte; handler:tMessageHandler); +begin hnd[OpCode]:=handler; end; +procedure SetHiMsgHandler(handler:tMessageHandler); +begin Hihnd:=handler; end; + +procedure WatchFD(fd:tHandle; h:tFDEventHandler); + var opt: tPollTop; +begin + if assigned(h) then begin + PollHnd[pollTop].CB:=h; + PollArr[pollTop].fd:=fd; + PollArr[pollTop].events:=POLLERR or POLLHUP or POLLIN or POLLPRI or + POLLRDBAND or POLLRDNORM; + PollArr[pollTop].revents:=0; + //writeln('Add watch ',pollTop,' on ',fd,' to ',IntToHex(qword(@h),8)); + Inc(PollTop); + end else for opt:=0 to high(opt) do if PollArr[opt].fd=fd then begin + if (pollTop-1)>opt then begin + PollArr[opt]:=PollArr[pollTop-1]; + PollHnd[opt]:=PollHnd[pollTop-1]; end; + dec(pollTop); + PollArr[pollTop].fd:=-1; + PollArr[pollTop].events:=0; + PollArr[pollTop].revents:=0; + break; end; +end; +var i:byte; BEGIN - s_setupInet; fpSignal(SigInt,@SignalHandler); fpSignal(SigTerm,@SignalHandler); - repeat Loop until Terminated; - write('Standard terminate ['); - CloseSocket(s_inet); - writeln(']'); + for i:=1 to high(hnd) do hnd[i]:=nil; + pollTop:=1; {1 for basic listen} END. \ No newline at end of file diff --git a/TestWatch.pas b/TestWatch.pas new file mode 100644 index 0000000..979ef2d --- /dev/null +++ b/TestWatch.pas @@ -0,0 +1,33 @@ +unit TestWatch; + +INTERFACE +IMPLEMENTATION +uses ServerLoop,SysUtils; + +type tObj=object + var f:text; + var h:tHandle; + procedure Event1(ev:Word); + procedure Init; +end; + +procedure tObj.Init; + begin + assign(f,''); + reset(f); + h:=GetFileHandle(f); + writeln('Input handle ',h); + WatchFD(h,@Event1); +end; + +procedure tObj.Event1(ev:Word); + begin + writeln('Event1 ',IntToHex(ev,4)); + readln; + WatchFD(h,nil); +end; + +var o:tObj; +BEGIN + o.Init; +END. \ No newline at end of file diff --git a/brodnetd.pas b/brodnetd.pas index 18d2f5d..dbc3d4a 100644 --- a/brodnetd.pas +++ b/brodnetd.pas @@ -1,6 +1,10 @@ PROGRAM brodnetd; { Poll loop. Read message, get handler, exec handler. } +uses ServerLoop + ,TestWatch + ; BEGIN + ServerLoop.Main; END. \ No newline at end of file -- 2.11.4.GIT