Work in msg.
[brdnet.git] / Controll.pas
blob168c40e7861561c541357084c3c94e6f5e9bc512
1 unit Controll;
2 (* Communication between applications and running brodnet daemon. *)
4 INTERFACE
6 uses SocketUtil
7 ,NetAddr
8 ,Classes
9 {$IFDEF MSWINDOWS}
10 ,WinSockAliases
11 {$ELSE}
12 ,BaseUnix
13 {$ENDIF}
14 ,Sockets
15 ,SysUtils
16 ,sSockets
17 ,Eventlog
18 ,Peers
19 ,Transfer
20 ,Neighb
23 {Hooks for main loop}
24 procedure SetSelectFDS(var FDS : BaseUnix.tFDSet);
25 procedure HandleConnect(const ls:tListeningSocket);
26 procedure Receive(const FDS : BaseUnix.tFDSet);
28 {hooks for hooks in daemon}
29 procedure NotifyPeerStateChange( event: byte; info:Peers.tInfo );
30 procedure NotifyTransfer( id :tFID; done,total:longword; by: tBys );
31 procedure NotifyQuit( unexcepted:boolean );
32 procedure NotifyNeighbState( pid:tPID; addr:netaddr.t; hop:word );
34 var Log:tEventLog;
35 var OnTerminateRequest:procedure;
36 const cTransferBy:Transfer.tBy=24;
38 type eFull=class(Exception) end;
40 {todo:
41 - Aby sa upratal trochu loop v daemone:
42 - poskytne proceduru co modifikuje select-set
43 - ohandluje si callback z daemona z vysledkyu zo selectu
44 - Chceme abstrahovať socket, aby sa to dalo spustit aj bez daemona?
45 - naco, aj tak to bez neho nejde
46 - manažuje si pripojenych sam
47 - handluje peerstatechange, terminate, a vsetko
50 IMPLEMENTATION
51 uses CtrlIface;
53 type tDCFlag=(cfPeerStates,cfPeerStates0);
55 type tDaemonController=class (tObject)
56 public
57 id: byte;
58 io: tStream;
59 cmd:byte;
60 flags:set of tDCFlag;
61 finished:boolean;
62 procedure Run;
63 constructor Create(asocket:tStream; from:NetAddr.t);
64 destructor Destroy; override;
65 procedure NotifyPeerStateChange( event: byte; info:Peers.tInfo );
66 procedure CmdAddPeer;
67 procedure NotifyQuit( unexcepted:boolean );
68 procedure CmdInvalid;
69 procedure NotifyTransfer( aid :tFID; done,total:longword; by: tBys );
70 procedure CmdRequestTransfer;
71 procedure CmdQueryTransfer(op:byte);
72 procedure NotifyNeighb( pid:Neighb.tPID; addr: netaddr.t; hopcount: word );
73 procedure CmdGetNeighb;
74 procedure CmdGetNeighbPID;
75 end;
77 var Clients : array [1..8] of tDaemonController;
79 procedure tDaemonController.Run;
80 begin
81 try
82 cmd:=io.ReadByte;
83 log.debug('CMD/#'+IntToStr(id)+' Command: #'+IntToStr(cmd));
84 case cmd of
85 13,10:;
86 ccPeerStates: flags:=flags><[cfPeerStates];
87 //ccPeerStatesOff: flags:= flags -[cfPeerStates,ccPeerStates];
88 ccTerminate: if assigned(OnTerminateRequest) then OnTerminateRequest;
89 ccQuit: Finished:=true;
90 ccAddPeer:CmdAddPeer;
91 ccTransferRequest:CmdRequestTransfer;
92 ccTransferProgress:CmdQueryTransfer(0);
93 ccTransferAbort:CmdQueryTransfer(1);
94 ccGetNeighb:CmdGetNeighb;
95 ccGetNeighbPID:CmdGetNeighbPID;
96 //ccGetNeighbAddr:CmdGetNeighbAddr;
97 else CmdInvalid;
98 end;
99 except on e:EReadError do begin
100 log.debug('Command errored '+e.classname);
101 finished:=true;
102 exit;
103 end; end;
104 end;
106 {peer controll}
107 procedure tDaemonController.NotifyPeerStateChange( event: byte; info:Peers.tInfo );
108 var w:netaddr.word2;
109 begin
110 if not (cfPeerStates in flags) then exit;
111 if (event=0) and ( not (cfPeerStates0 in flags)) then exit;
112 io.WriteByte(cePeerState);
113 io.WriteByte(event);
114 io.WriteBuffer(info.addr,sizeof(info.addr));
115 w:=trunc(info.delta*MSecsPerDay);
116 io.WriteBuffer(w,2);
117 end;
118 procedure tDaemonController.CmdAddPeer;
119 var addr:netaddr.t;
120 begin
121 io.ReadBuffer(addr,sizeof(addr));
122 if addr.IsNil then log.error('Addr is nil') else Peers.Add(addr);
123 end;
125 {daemon controll}
126 procedure tDaemonController.CmdInvalid;
127 begin
128 io.WriteByte(ceInvalid);
129 Finished:=true;
130 log.error('Invalid command');
131 end;
132 procedure tDaemonController.NotifyQuit( unexcepted:boolean );
133 var exp:byte;
134 begin
135 io.WriteByte(ceQuit);
136 if unexcepted then exp:=1 else exp:=0;
137 io.WriteByte(exp);
138 end;
140 {Transfer controll}
141 procedure tDaemonController.NotifyTransfer( aid :tFID; done,total:longword; by: tBys );
142 var w:netaddr.word4;
143 begin
144 if not (cTransferBy in by) then exit;
145 io.WriteByte(ceTransfer);
146 io.WriteBuffer(aid,sizeof(aid));
147 w:=done; io.WriteBuffer(w,4);
148 w:=total; io.WriteBuffer(w,4);
149 (*io.WriteByte(by);*)
150 end;
151 procedure tDaemonController.CmdRequestTransfer;
152 var a:Transfer.tFID;
153 var addr:netaddr.t;
154 begin
155 io.ReadBuffer(a,sizeof(a));
156 io.ReadBuffer(addr,sizeof(addr));
157 Transfer.RequestFile( addr, a, cTransferBy );
158 end;
159 procedure tDaemonController.CmdQueryTransfer(op:byte);
160 var done,total:longword;
161 var fid:Transfer.tFID;
162 begin
163 io.ReadBuffer(fid,sizeof(fid));
164 case op of
165 0: begin
166 Transfer.Query(fid,done,total);
167 NotifyTransfer(fid,done,total,[cTransferBy]);
168 end;
169 1: Transfer.RecvFileAbort(fid);
170 end;
171 end;
173 procedure tDaemonController.NotifyNeighb( pid:Neighb.tPID; addr: netaddr.t; hopcount: word );
174 var n:tNeighbInfo;
175 begin
176 if not (cfPeerStates in flags) then exit;
177 n.pid:=pid;
178 n.addr:=addr;
179 n.hop:=hopcount;
180 io.WriteByte(ceNeighbState);
181 io.WriteBuffer(n,sizeof(n));
182 end;
183 procedure NotifyNeighbState( pid:tPID; addr:netaddr.t; hop:word );
184 var i:word;
185 begin
186 for i:=1 to high(Clients) do if assigned(Clients[i]) then Clients[i].NotifyNeighb(pid,addr,hop);
187 end;
189 procedure tDaemonController.CmdGetNeighb;
190 var n:tNeighbInfo;
191 var i:Neighb.tInfo;
192 begin
193 i.Init(65535);
194 while i.Next do begin
195 n.pid:=i.pid;
196 n.addr:=i.addr;
197 n.hop:=i.hop;
198 io.WriteByte(ceNeighbs);
199 io.WriteBuffer(n,sizeof(n));
200 end;
201 io.WriteByte(ceNeighbsEnd);
202 end;
204 procedure tDaemonController.CmdGetNeighbPID;
205 var n:tNeighbInfo;
206 var i:pointer=nil;
207 var wo:word;
208 var pid:Neighb.tPID;
209 begin
210 io.ReadBuffer(pid,sizeof(pid));
211 n.pid:=pid;
212 Neighb.GetRoute(pid,n.addr,wo,i);
213 n.hop:=wo;
214 while assigned(i) do begin
215 io.WriteByte(ceNeighbs);
216 io.WriteBuffer(n,sizeof(n));
217 Neighb.GetRoute(pid,n.addr,wo,i);
218 n.hop:=wo;
219 end;
220 io.WriteByte(ceNeighbsEnd);
221 end;
223 constructor tDaemonController.Create(asocket:tStream; from:NetAddr.t);
224 begin
225 finished:=false;
226 io:=asocket;
227 flags:=[];
228 end;
230 destructor tDaemonController.Destroy;
231 begin
232 end;
234 procedure SetSelectFDS(var FDS : BaseUnix.tFDSet);
235 var i:word;
236 begin
237 for i:=1 to high(Clients) do if assigned(Clients[i]) then BaseUnix.fpfd_set((Clients[i].io as tSocketStream).Handle,FDS);
238 end;
240 procedure HandleConnect(const ls:tListeningSocket);
241 var stream:tSocketStream;
242 var ci:word;
243 var addr:netaddr.t;
244 var consocket:tSocket;
245 begin
246 ci:=1; while true do begin
247 if ci>high(Clients) then break;
248 if not assigned(Clients[ci]) then break;
249 inc(ci);
250 end;
251 ls.Accept(consocket,addr);
252 stream:=tSocketStream.Create(consocket);
253 if ci>high(Clients) then begin
254 log.error('Too many clients on command port'); //raise eFull.Create('Too many clients on command port');
255 stream.free;
256 end else begin
257 log.info('CMD/#'+IntToStr(ci)+' connect from '+String(addr));
258 Clients[ci]:=tDaemonController.Create(stream,addr);
259 Clients[ci].id:=ci;
260 end;
261 end;
263 procedure Receive(const FDS : BaseUnix.tFDSet);
264 var i:word;
265 begin
266 for i:=1 to high(Clients) do if assigned(Clients[i]) and (BaseUnix.fpfd_isset((Clients[i].io as tSocketStream).Handle,FDS)=1) then begin
267 Clients[i].Run;
268 if Clients[i].Finished then begin
269 log.info('CMD/#'+IntToStr(i)+ ' disconnect');
270 Clients[i].io.free;
271 freeandnil(Clients[i]);
273 end;
274 end;
276 procedure NotifyPeerStateChange( event: byte; info:Peers.tInfo );
277 var i:word;
278 begin
279 for i:=1 to high(Clients) do if assigned(Clients[i]) then Clients[i].NotifyPeerStateChange(event,info);
280 end;
282 procedure NotifyQuit( unexcepted:boolean );
283 var i:word;
284 begin
285 for i:=1 to high(Clients) do if assigned(Clients[i]) then begin
286 Clients[i].NotifyQuit(unexcepted);
287 Clients[i].io.free;
288 freeandnil(Clients[i]);
289 end;
290 end;
292 procedure NotifyTransfer( id :tFID; done,total:longword; by: tBys );
293 var i:word;
294 begin
295 for i:=1 to high(Clients) do if assigned(Clients[i]) then Clients[i].NotifyTransfer(id,done,total,by);
296 end;
298 procedure Init;
299 var i:word;
300 begin
301 for i:=1 to high(Clients) do Clients[i]:=nil;
302 end;
304 INITIALIZATION
305 Init;
306 END.