The Perl Cfengine Daemon

[Cfengine Homepage] [News] [Description] [Design Goals] [Documentation] [Protocol]


December 21, 2000 18:01:01

Users on the mailing list have reported that perl-cfd appears to work fine with cfengine 1.6.

January 08, 2000 17:23:01

Perl-cfd 1.0.1 fixes the following bugs:

November 26, 1999 11:26:43

Perl-cfd has been released to the public. The silly NASA release forms have finally made it through (after 6+ weeks of waiting).

You can also visit the perl-cfd CVS repository.

October 15, 1999

I (Gregory P. Smith) have started work at another company. Perl-cfd's NASA release form is in the works; I'll see that it gets released within the next couple of weeks. Mark has expressed interest in including perl-cfd with future versions of cfengine.

Updates to perl-cfd will be posted my new non-NASA perl-cfd updates page if nobody else picks up the task (hint hint!). My new job will not leave me with much time to work on it.


Perl-cfd is an alternate implementation of the cfengine server daemon. It has been tested with cfengine v1.4.17 and v1.5.2 clients. It should work with older v1.4.x and other v1.5.x clients but we have not verified this.

Yes, that's right. Perl-cfd supports v1.4 and v1.5 clients at the same time!

It is written in Perl 5 using a preforked server approach (similar to most http daemons). The first prototype was written using perl threads but I ran into difficulties as important parts of the perl internals are not yet thread safe. Perl 5.004 or later is required, although all development and testing has been done on 5.005.

"Perl is interpreted, what does this do to performance?" you ask. Perl-cfd performs very well. We have perl-cfd running on a Sun Ultra 2 running Solaris 2.6 serving approximately 40k client requests an hour (mostly v1.4 clients at the time of this writing; v1.5 should cause less load). Perl-cfd adds 0.1-0.2 to the load average on the machine depending upon the number and nature of the requests happening at the time.

History & Design Goals

We found that cfd included with cfengine 1.4.x and 1.5.0-1.5.2 was not stable when tons of clients were connecting to it at once on our server. Looking at the code, it had many global variables and called many non-threadsafe functions yet it was a threaded program. Due to this I didn't feel that the cfd distributed with cfengine was easily fixable for what we needed it to do.

We needed a cfengine server that did not hang or crash. We have about 400 client machines that run a cfengine script once during each hour, potentially making 100 requests from the server during a each clients run. (Ed: I also wrote this daemon because I thought something much simpler could do the job better and safer. -greg)

Another major goal was to have a cfengine server support both v1.4 and v1.5 clients at the same time. While not too useful in the long run, this makes upgrading between current incompatible client versions easy (in fact, cfengine itself can be used to do its own upgrade in our environment :).

Reading the current cfd and cfengine code so closely to figure out how the protocol -really- works has revealed problems with the current protocol (both 1.4 and 1.5). A description of the problems and suggested fixes for future cfengine versions are below.


It uses the same format config file as cfd. The following perl-cfd settings are supported in the control section. Variable names are not case sensitive in perl-cfd config files.

OptionMeaning, (allowable values), [default]
MaxThreads How many child processes perl-cfd maintains. (1-40) [25]
MaxConnections How many connections allowed to queue up when all children are busy. (4-200) [40]
MaxPerChild How many client connections each child process handles before dying and being restarted. (50-50,000) [1000]
Port The TCP port the server should run on. This may be specified as text, a number or both using the same syntax as the default. If the text name is not found in /etc/services the numeber will be used. [cfengine(5308)]
ClockDrift Set the maximum allowable clock differece between clients and the server in seconds. (60+) [180]
DenyBadClocks Disable all clock drift checking. [false]
Debug Turn on debugging and/or set the debug level. (on, 0-3) [0]
Timeout The maximum time in seconds to wait for a request on an open connection from a client. This is to limit the impact hung clients or denial of service attacks on the server. (15-900) [180]

In an admit or deny section of the config file you can list multiple IP address or domain name wildcards on a line with a pathname. Just seperate them by a space. I don't know if the original cfd allowed this.

Run perl-cfd with the -h command line option for a list of command line options similar to this:

Perl cfengine daemon (perl-cfd) v0.15.10-nas

  -f F  Use configuration file F [default: /etc/cfd.conf]
  -p p  Start the server on port p [default: cfengine(5308)]
  -v    Verbose operation
  -d n  Enable debug output at level n (1-4)
  -V    Display version information
  -h    Display this help message

  Signals (to the parent process):
    HUP        Rereads the config file (errors go to syslog)
    TERM, INT  Terminates all children and exits cleanly
    USR1       Syslogs the running configuration

Perl-cfd does not support the "EXEC" request or the ability to spawn off processes itself that are found in the original cfd server. (We don't use those features so I didn't write support for them). None of the SSL features found in v1.5 are implemented in this version. I leave that as an exercise for someone not living under stupid crypto laws.

Protocol Problems and Proposal

The 1.4/1.5 protocol sends everything over the network in 4096 byte chunks, no matter how little there usually is to send or receive. This is highly inefficient. The 1.4/1.5 protocol also leaves no room for distinction between error messages and actual data. For example: if a file, or a block in a file, starts with the text string BAD: it will cause the client to abort that file transfer with an error containing the data after it. In some cases, v1.4 clients even end up writing the error message to the file (this was fixed in v1.5) without knowing there was a problem.

Here are some possible ways to fix the protocol while making it possible to easily extend perl-cfd to support 1.4, 1.5 and the new protocol all at once:


Gregory P. Smith - greg at users dot sourceforge dot net