README for circd development
============================

circd is a control daemon for fli4l. Its task are:
	- intitializing interfaces
	- dialing/ hanging up
	- stopping interfaces
	- tracking states of circuits
	- calculating throughput and bytes (per month for volume dependent switching)
	- Least cost routing dependent on a time table (and in future volume or time contingents)
	- providing a user interface for
		- controling interfaces like starting, stopping, dialing hanging up etc.
		- retrieving rates and volumes
		- delivering states about the current circuits
		
A connection controlled by circd is called circuit. In most cases this is equal to an interface
but in cases of channel bundling there can be more than one interface for a circuit.

Keep in mind, that circd should do its work in non-blocking mode so that it can react
even if one client connection or a script call gets stuck. For this reason, most user interface commands
are implemented asynchronously. The protocol needs to be changed for this, because a client
which controls more than one circuit can get answers in different order from circd as the
requests are sent. Commands for one circuit are queued and executed serially. It makes no sense
to try to dial and hangup simultaneously.

All commands which changes the state of a circuit are excluding each other. That means if a dial
command is queued and a stop command arrives, the dial command is thrown away and the stop command
is queued. Here is a matrix of what happens in which state:

possible states:   disabled, starting, offline, dialing, online, paused, hanging-up
possible commands: start, dial, pause, continue, hangup, stop

             start       dial        pause       continue    hangup       stop
----------------------------------------------------------------------------------------
disabled     call start  call start  call start  call start  call start   -
                         call dial   call dial   call dial
			             call pasue
----------------------------------------------------------------------------------------
offline      -           call dial   call dial   call dial   -            -
			             call pasue
----------------------------------------------------------------------------------------
online       -           -           call pasue  call cont   call hangup  call hangup
								          call stop
----------------------------------------------------------------------------------------
paused       -           -           -           call cont   call hangup  call hangup
									  call stop

At the moment there are the following well known circuit types:
	- dsl: pppoe, pptp
	- isdn: ippp, dhcl(raw)
	- ppp
	- Ethernet
	- VPN

Type dependent stuff can be implemented by a control script located in /usr/local/bin. Its name
corresponds to its type: <type>-circuit-ctrl like pppoe-circuit-ctrl for pppoe. Because each call
to this script requires a fork(), some functionality like retrieving state, iobytes etc. can be
implemented in type specific functions which are compiled into circd.

To get a most flexible structure, a function table is used for this. If function is NULL, the
common way is used meaning calling the control script to do something. Here are the prototypes
for functions in this indirection table. In most cases a request_t structure is used to hand over
parameters. It contains two fd fields, one to read reply from script and one to answer to client
connected to telnet port. If client fd is -1, command is queued by the circd itself and does not
need to send any answer to someone.
	
	- void init(void);
		Initialisation for this type. E.g. for isdn, a fd is registered to get noticed when
		interface states change. For other types without such functionality, a timer could be
		started to poll states. This function is only called, if such type occurs in the
		configuration.
	
	- void start(request_t *rp);
		Starting a circuit. e.g. starting a (i)pppd - creating a device setting up routes etc.
		That means this circuit is going online on demand. If a circuit should be dialed in
		manually, there is no need to start up, create interface etc.
	
	- void dial(request_t *rp);
		e.g. ping a well known ip Address
		
	- void hangup(request_t *rp);
		e.g. send a kill -HUP
		
	- void stop(request_t *rp);
		stopping device, removing route
		
	- void pause(request_t *rp);
		leave connection online but suppress data exchange e.g. by setting a rule in iptables
		
	- void cont(request_t *rp);
		remove that iptables rule to continue exchanging data
		
	- void dialmode(request_t *rp, circ_mode_t mode);
		set dialmode of circuit
		
	- void hup_timeout(request_t *rp, time_t timeout);
		set hangup timout
		
	- void status(request_t *rp);
		get state of circuit. It simply returns the contens of its state variable.
		
	- void calc_rates(circuit_t *circ);
		calculate io rates and returns its values.
		
	- void calc_iobytes(circuit_t *circ);
		calculate io bytes and returns its values.
		
	- void read_persistence(circuit_t *circ);
		read account data from disk
		
	- void write_persistence(circuit_t *circ);
		write account data to disk - needed for accounting

It is intended to provide a user command to register for events so that the client does not need
to poll for changes.
This could look like this:

cmd: register CIRCNAME1 CIRCNAME2 ...

An event looks like this:

event CIRCNAME1: offline
event CIRCNAME1: iobytes 1234567 865434543

For rates and iobytes an interval needs to be defined e.g. every second.

