Daemon Process

What is a Daemon?

Every multitasking operating system supports a special type of process, a process that is usually kept a lower priority, performing a specific task over and over. Those processes are kept out of sight, performing their function in the background, without any direct intervention by the user. In the Unix operating system terminology, among other operating systems as well, background processes are called daemons.This tutorial will introduce you to daemon programming. You will write a simple daemon in Linux, C/C++ and a Bash Script, just to get a grip on what daemons are, and what they are capable of, only to move on to coding your first daemon in C. Daemons can be easily created under GNU/Linux, they mostly follow a specific convention. To begin coding your first daemon, you will need to find a use for it. Daemons can handle many tasks that could otherwise bother users and affect their productivity, which brings us to the next section. 

Putting Daemons to Use

Daemons usually handle tasks that require no user intervention, and consume low CPU power. CPU-intensive background tasks are not typically termed daemons, as bringing down computers to a sluggish performance can be hardly satisfying for any user, but decreasing the priority of these tasks can qualify them for that without sacrificing their performance, since CPUs are normally idle more than 90% of their time.A daemon usually handles a single task, and accepts commands through means of IPC (Inter-Process Communication), which you will be briefly exposed to in this tutorial. Tasks handled by daemons include serving web pages, transferring emails, caching name service requests, logging, and for the purposes of this site, serving game clients. 

Daemon game servers handle incoming game requests through a network, process these requests, update its persistent storage (database or flat files), and finally sends back responses to the clients. A major issue with game servers, among other servers, is that clients cannot be trusted, since a modified or reverse engineered version of the client can wreck havoc if the server is not ready to handle it. This enforces that clients should not keep a copy of the current game data, they should only send actions, not states, to the server, which would in turn validate those actions, and update the game status.

Structure of a Daemon

Daemons typically have the same structure, regardless of their functionality. A daemon starts off by initializing its variables. It then sets its IPC interface up, which could simply be signal handlers. The daemon then executes its body, which is almost always an infinite loop.Most daemons start off by forking. Forking is a method that allows a process to clone itself, creating an identical child. A daemon, as a parent process, usually forks off and terminates (or dies), while its child is left executing the main loop. The child is usually called an orphan process. In Unixes, orphan processes are automatically adopted by the “init” process, and this action is known as re-parenting. 

For a more practical approach, the following sections dissect the two previously mentioned daemons. Links to their sources are found at the end of the tutorial.

Writing a Daemon in Linux

In this tutorial, you will be introduced to creating daemons in Linux-based operating systems. The tutorial will cover the basic concepts underlying daemons, will guide you through the sample code of a daemon process, and then introduce you to what Inter-Process Communication is and how you could use it.

We need first to define what a daemon is. But then to do that, we would have to go a little farther, as far as source code is from a daemon. When you write a program, let us say in C, and you compile it, the compiler produces what you should probably already know as executable or binary. This created file, although it is executable, is not in fact entirely so. You do not just ask the operating system to start executing the first instruction in that file.

However, what actually happens is that the operating system loads this file into memory, and there it becomes known as a Process. A Process is different from that executable program you had on your disk drive, in that it is associated with information that the operating system uses to maintain running of the program. Without going into much detail, let us take a simple example to illustrate the difference between a program file on your disk and that same program when loaded into memory. Modern Operating Systems all support Multi-tasking; the ability to switch between two or more running processes. In a system with single a processor, the operating system actually switches between running processes, giving each a fraction of a second and thus giving you the illusion of several programs running simultaneously.

So, how does this example make a compiled binary different from processes!? Well, before the operating system switches from one running program to another, it has to save the first program’s state, so that it could return to the next correct instruction after it switches from the second. This is called the Program Counter, it is a counter that specifies which instruction the operating system has to execute next. Before switching to another running program, this Counter must be stored.

So, a process is not only the code contained in your binary program. It contains additional information that allows the operating system to maintain the running of that program. But how does this relate to daemons?

A daemon is a process, or more accurately, a background process. A daemon is not associated with any input or output streams, that is to say, you cannot give it input or read output from it interactively. And a daemon, a daemon does not have a parent process.

A parent process you may ask? Yes. In UNIX-like operating systems processes are structured in a tree. No process can actually emerge or come into existence from nowhere, it must be forked from a parent process. We have the “init” process as the root process, and any new process must fork from it or from one of its children.

So, if every process has a parent in that tree, where would our newly created daemon be placed!? Let us try to picture what would happen, by taking syslogd as an example (syslogd is the System Log Daemon. Though it should be apparent from its name, it is irrelevant to us what it actually does).

syslogd is stored on your disk drive as a program. When you start that program from the shell, the operating system loads it as a new process. Till now, it is no different from your standard computer program, it still can read input and produce output, and the shell is its parent process.

Then, syslogd would initiate a few steps to become a daemon: it forks from itself a new child process, and then kills the parent process. Since the parent was killed, and since our mighty Unix and Unix-like systems are too kind and could not leave an orphant process behind, “init” automatically adopts this newly forked process as its child.

Let us now jump into some code. The following code was adapted from syslogd.c:

pid = fork();
if (pid > 0)
 exit(0);
else if (pid == 0) {
       daemon_init(argv);
}

In the first line, our daemon process which we just ran forks itself, thus creating a new process. fork() is a system call that copies a process into another one, and then the former would be called the parent and the later would be called the child. fork()’s return value is different in the child process from the parent one. When the process is forked, the child process, which was just created, will start executing in the line just after the fork() call. Remember above we talked about the Program Counter being part of the Process, so when it is copied, that counter’s value is copied to the child as well.

Hence, we now have both processes, the parent and the child, positioned to execute the instruction after the fork() call. But what would distinguish them!?

In the parent process, fork() returns an Identifier that uniquely identifies the child process among all other processes running in the system, this identifier is known as the Process ID, or as usually abbreviated, PID. Meanwhile, in the child process, fork() returns 0.

Thus, what our daemon does is to check for the value returned by fork(). If this value was greater than 0, then it must have been executing within the parent process. If this value was 0, then we must have been executing within the child process.

Since we want this to be a background process, what we will do next is to exit the parent process. This way, our child process becomes orphan and gets adopted by init. In the shell, since the input and output streams were attached to a process that now exited, then we return to the prompt while the child process is still running in memory.

Or is it!? To go with further demonstration, let us consider the following program, which is basically the same as the one before but in a more complete form:

#include
#include
#include
#include
#include
#include 

void daemon_entry_point()
{
 // Do Nothing
}

int main(int argc, char * argv)
{
 // fork this process and start the daemon
 pid_t pid = fork();

 if (0 > pid)
 {
  // If the child was not succesfully, created,
  // -1 will be returned to the parent.

  printf("Failed to fork. Now exiting...\n");
  exit(EXIT_FAILURE);
 }
 else if (0 < pid)
 {
  // If the return value is larger than 0, then
  // this part of code will only be executed by
  // the parent. We exit the parent.

  printf("Process forked. Parent now exiting...\n");
  exit(EXIT_SUCCESS);
 }

 // Coming here, it must be the child, whose fork() returned 0.
 // What we now do is close the Standard File Descriptors since
 // we won't be reading or writing to them.

 printf("Daemon Starting...\n");

 close(STDIN_FILENO);
 close(STDOUT_FILENO);
 close(STDERR_FILENO);

 // Call daemon_entry_point which would be responsible for
 // further initialization and startup routines for your daemon.

 daemon_entry_point();

 return 0;
}

Now, compile this program

gcc -o my1stdaemon my1stdaemon.c

Run it

./my1stdaemon

It should now have returned you back to the shell. At this point, the parent process have exited after forking the child, to see the child process running, type:

ps -e | grep my1stdaemon

ps is a program that reports a snapshot of information about the currently running processes. A sample output would be:

6894 pts/1    00:00:20 my1stdaemon

The first column shows the Process ID of the daemon. To shut the daemon down, we use that Process ID as follows:

kill -9 6894

This sends a KILL (9) signal to the daemon that forces it to exit.

Now that we have understood, written and tried our first daemon, we need to see how we can communicate with it. If a daemon cannot read or write from stdin, how could we tell it what to do and know what it is doing!?

This brings us to Inter-Process Communication!

Inter-Process Communication (IPC) refers to the set of mechanisms which we could use to make two processes to communicate with each other. There are several Inter-Process Communication methods, each has its own set of advantages and disadvantages. In this tutorial we would guide you throw using a FIFO, also known as a Named Pipe, to send data from one daemon to the other.

FIFOs, or Named Pipes, were created as an extension to Pipes, which later became known as Anonymous Pipes. Anonymous Pipes are an IPC mechanism that allow for uni-directional communication between two processes. Anonymous Pipes are a wildly popular mechanism for communication between processes, and can been seen in pipelines, where a set of processes are chained by their standard streams: the first one writes to its standard output, the second process reads from the first’s standard output and writes to it standard output, and so on. An example of a pipeline is our usage of the command “ps” above to pipe its output to the program “grep” which then outputted the result to the standard output stream.

So, what is a FIFO? A FIFO (First In First Out) is a Pipe that is associated with a file in your file system. Anonymous Pipes are different in that they have no name and do not persist after the process exists. With Named Pipes on the other hand, you have to specifically “unlink” or delete the file after you have no more need for it.

Now, what we want to do is to make my1stdaemon send the text “Hello World!” to a second daemon, my2nddaemon. This second daemon would then write the same text it received into a file /tmp/target.

To do this, we will first modify the function daemon_entry_point in my1stdaemon as follows:

void daemon_entry_point()
{
 // Create a FIFO (Named Pipe) in /tmp/myfifo
 mkfifo("/tmp/myfifo", 0644);

 // A FIFO is accessed exactly like a normal
 // file. Here, we would open it with "open"
 // and write to it with "write"

 int fifofd = open("/tmp/myfifo", O_WRONLY);

 if ( -1 == fifofd )
 {
  exit(EXIT_FAILURE);

  // Since we already closed the standard
  // streams, we cannot print an error
  // message as usual. Before exiting, we
  // should have actually written to a log
  // file, but this has been left out for
  // simplicity.
 }

 // Put some text in the FIFO, and sleep for 6
 // seconds. Repeat this for 10 times.

 char * text = "Hello World!\n";

 int i;
 for (i = 0; i < 10; i++)
 {
  write(fifofd, text, strlen(text));
  sleep(6);
 }

 // Close the FIFO
 close(fifofd);
}

Now, compile my1stdaemon as before and run it. Open another shell window and type

cat /tmp/myfifo

There you would find that cat, which is another process, is in fact reading what we have written by my1stdaemon. One more thing, while you are there, type ls -l /tmp/myfifo, you would get:

prw-r--r--  1 leaf users 0 2006-07-25 22:56 /tmp/myfifo

The first character, ‘p’, indicates that the type of /tmp/myfifo is a Pipe, contrary to standard files which would be ‘-‘, and directories, which would be ‘d’.

Let us make our second daemon, that reads from the FIFO created by the first one. We will start our second daemon from the same code base, but will implement daemon_entry_point differently. Here is the implementation of this function for my2nddaemon

void daemon_entry_point()
{
 // Open the FIFO

 int fifofd = open("/tmp/myfifo", O_RDONLY);

 if ( -1 == fifofd )
 {
  exit(EXIT_FAILURE);
 }

 // Open a target file in which we would write
 // what we have read from the FIFO

 int targetfd = open("/tmp/target", O_WRONLY | O_CREAT, 0644);

 if ( -1 == targetfd )
 {
  exit(EXIT_FAILURE);
 }

 // Pipe the data from the FIFO to the target file.

 char text [50];
 memset(text, '', sizeof(text));

 int i;
 for (i = 0; i < 10; i++)
 {
  read(fifofd, text, sizeof(text));
  write(targetfd, text, strlen(text));
 }

 // Close the file handles
 close(fifofd);
 close(targetfd);
}

Compile this using

gcc -o my2nddaemon my2nddaemon.c

Run both daemons

./my1stdaemon
./my2nddaemon

Now, to see data while it is written to /tmp/target, type:

tail -f /tmp/target

That’s it.

You should now have an understanding of the basics you need to create a daemon in Linux, and how you can make this daemon communicate with other processes.

Fork off and Die: C/C++ Daemons

Prerequisites

You’ll need to have GCC (The GNU Compiler Collection) installed. Enter “gcc –version” at the shell, and it should echo back the current GCC version. You will also need to have glibc, the GNU standard C library. You could try compiling a simple “Hello World” program just to make sure everything is setup properly, which is usually the case, but you should make sure anyway. Also, some hands-on experience with the C programming language will definitely prove useful.

The Code

The following code implements the very same daemon explained in the previous section, but using C. To compile your daemon, you first need to save the file under “uptlogd.c”. At the shell, enter “gcc -o uptlogd uptlogd.c” to compile and link your daemon. You can now use “./uptlogd” to start it.
// uptlogd - A simple C daemon

#include 

#include 

#include 

#include 

#include 

#include 

#define FILENAME_SIZE 15

#define LINE_SIZE_MAX 100

int logfd = -1;

int logging = 1;

char *logfile = NULL;

char *line = NULL;

The file basically has a little more includes than your average “Hello World” program! The header files are “stdio.h”, which defines “printf”, among other standard I/O functions, “unistd.h”, which defines lots of constants and functions, including “getpid”, “fork”, and others, “fcntl.h”, which defines the arguments used by the “open” function, “sys/types.h”, which defines several data types, among which is “pid_t”, “errno.h”, which is responsible for the basic error reporting facilities, and “signal.h” for handling signals.

The global variables are “logfd”, the file descriptor for the log file, “logging”, the logging flag, “logfile”, the name of the log file, and “line”, which temporarily holds the log message before it is written to the log file.

void trigger_logging(int signum)

{

	logging = (logging == 1) ? 0 : 1;

}

void clean_up(int signum)

{

	// Free up the resources

	if (logfd != -1)

		close(logfd);

	if (logfile != NULL)

		free(logfile);

	if (line != NULL)

		free(line);

	exit(0);

}

Those two functions are defined as “callbacks”; they are called automatically when their associated signal is intercepted. The “trigger_logging” function enables/disables logging, while the “clean_up” function closes the file and deallocates the strings before exiting.

int main(int argc, char *argv[])

{

	// Fork off

	pid_t pid = fork();

	if (pid == -1)

	{

		// Out of memory: not likely to happen!

		printf ("Error: not enough memory to initiate!\n");

		return 1;

	}

	else if (pid != 0)

	{

		// ... and die!

		printf("uptlogd PID is %d\n", (int) pid);

		printf("Logging started ...\n");

		return 0;

	}

The main function starts off by forking through calling the “fork” function. “fork” returns -1 on failure, which only happens if not enough memory for cloning the current process is available, which is quite uncommon. “fork” returns the child PID in the parent’s thread, and zero in the child’s thread. Here, the parent outputs the child’s PID and exits, while the child continues to execute the remaining code.

	// Child continues executing here

	// Set the signal handlers up

	signal(SIGUSR1, trigger_logging);

	signal(SIGTERM, clean_up);

The “signal” function sets up a signal handler. The code handles SIGUSR1 by calling “trigger_logging”, and SIGTERM by calling “clean_up”, refer to those functions to get the whole picture.

	// Set the log file up

	pid = getpid();

	logfile = malloc(sizeof (char) * FILENAME_SIZE);

	sprintf(logfile, "LOGFILE_%06d", (int) pid);

	// Open the log file

	logfd = open(logfile, O_CREAT | O_WRONLY, 00644);

	if (logfd == -1)

	{

		printf("%s\n", strerror(errno));

		return 1;

	}

The log filename is allocated, and a unique name is used by concatenating the PID to the string “LOGFILE_”. A handle to the file is acquired using “open”. A defensive programming practice is to make sure the acquired file handles are valid, several problems can cause “open” to return -1.

	// Prepare the loop variables

	int count;

	int timesec = 0;

	line = malloc(sizeof (char) * LINE_SIZE_MAX);

	// Loop forever

	while (1) {

		// Write the log to the file, if logging is enabled

		if (logging == 1)

		{

			sprintf(line, "Uptime: %d seconds\n", timesec);

			count = write(logfd, line, strlen (line));

			if (count == -1)

			{

				printf("%s\n", strerror (errno));

				return 1;

			}

		}

		timesec += 5;

		// Sleep for 5 seconds

		usleep(5000000);

	}

	return 0;

}

The daemon now executes its main loop. The loop starts by writing the log message, formatted in the “line” variable, to the log file. Another good programming practice is to check the length of the written message, which is the return value of “write”, compare with it the expected size, and act accordingly, but for simplicity purposes, the code only checks if the function failed. The daemon then updates its uptime, and sleeps for five seconds, only to repeat the loop all over again.

A Simple BASH Script Daemon

Prerequisites

You will need to have BASH, which is the current default shell for most, if not all, Unixes. You also could use some basic BASH programming knowledge.

The Code

The following BASH code simply logs its uptime every five seconds to a file. As a quick introduction to signal trapping, the logging can be disabled and enabled while the daemon is running. To run the following script, you first need to save it under “uptlogd.sh”. Now, from the shell, type “chmod 755 uptlogd.sh” to make the file executable, and “./uptlogd.sh &” to run the file in the background.
#!/bin/bash

# uptlogd - A simple BASH script daemon

# Daemon initialization

echo "uptlogd PID is $$"

echo "Logging started ..."

logfile="LOGFILE_$$"

# Set the variables up

logging=true

timesec=0

The daemon starts by printing its PID ($$). It then uses a unique name for its log file using its PID. Variable initializations follow, where logging is on, and the uptime is zero initially.

# Set the signal handler up

trap 'if [$logging==true]; then logging=false; else logging=true; fi' SIGUSR1

The trap command allows the daemon to intercept a signal and handle it. The daemon handles “SIGUSR1” by triggering the logging, enabling it if it is disabled, and vice versa.

# Loop forever

while true

do

	# Log the currently logged-in users if logging is enabled

	if [ $logging == true ]

	then

		echo "Uptime: $timesec" >> $logfile

	fi

	timesec=`expr $timesec + 5`

	# Sleep for 5 seconds

	sleep 5

done

The daemon moves on to the main loop. It echoes the uptime to the log file if logging is enabled, updates its uptime, sleeps five seconds, and repeats. To interact with the daemon, you can use the “kill” command from the shell, which sends a signal to a running process. Using the PID reported by the daemon, use “kill ” to terminate the daemon by sending the default signal SIGTERM. You can also use “kill -SIGUSR1 ” to enable/disable logging.

The code is very simple, but who uses BASH to code daemons anyway..

Advertisements
  1. i like it

  2. I actually loved this brilliant article. Please continue this awesome work.

  3. hi, solid web log, just I don’t see how to add your website in my rss reader. Could are Assist me please?

  4. I loved as much as you will receive carried out right here. The sketch is attractive, your authored material stylish. nonetheless, you command get bought an impatience over that you wish be delivering the following. unwell unquestionably come further formerly again since exactly the same nearly very often inside case you shield this hike.

  5. Hey this is somewhat of off topic but I was wondering if blogs use WYSIWYG editors or if you have to manually code with HTML. I’m starting a blog soon but have no coding experience so I wanted to get advice from someone with experience. Any help would be greatly appreciated!

  6. Purely to follow up on the update of this theme on your web site and would want to let you know just how much I prized the time you took to produce this helpful post. Within the post, you spoke of how to truly handle this concern with all convenience. It would be my pleasure to get together some more concepts from your website and come up to offer some others what I learned from you. Many thanks for your usual good effort.

  7. Wow, superb blog layout! How long have you been blogging for? you made blogging look easy. The overall look of your website is excellent, let alone the content!

  8. I have been surfing online more than 3 hours today, yet I never found any interesting article like yours. It is pretty worth enough for me. In my view, if all web owners and bloggers made good content as you did, the net will be much more useful than ever before.

  9. I am usually hunting for notice. This article really peaks my interest. keep an eye onhttp://www.secretenhancers.com/human-growth-agent-review.php

  10. I was reading through some of your blog posts on this internet site and I think this internet site is really instructive! Continue posting .

  11. Hi. I needed to drop you a fast notice to precise my thanks. Ive been following your blog for a month or so and have picked up a ton of fine information and loved the strategy youve structured your site. I am attempting to run my very personal blog nonetheless I believe its too basic and I must concentrate on numerous smaller topics. Being all issues to all of us will not be all that its cracked up to be

  12. Hmmm…good to know, there were definitely two or three things which I hadn’t thought of before.

  13. Hello there, just became alert to your blog through Google, and found that it is really informative. I am gonna watch out for brussels. I’ll be grateful if you continue this in future. Numerous people will be benefited from your writing. Cheers!

  14. Hey I discovered this website to be really interesting! Bookmarked! http://newsbabble.info/verizoniphone427.html

  15. You actually wrote about some curious things in this posting. I found this by searching Bing and I’ve got to confess that I am currently subscribed to your site, it is very decent 🙂

  16. hello there and thank you for your info ? I have certainly picked up anything new from right here. I did however expertise some technical issues using this site, since I experienced to reload the site lots of times previous to I could get it to load properly. I had been wondering if your web hosting is OK? Not that I am complaining, but slow loading instances times will sometimes affect your placement in google and could damage your quality score if ads and marketing with Adwords. Anyway I am adding this RSS to my e-mail and could look out for a lot more of your respective exciting content. Ensure that you update this again very soon..

  17. I merely wanted to let you know how much my partner and i appreciate anything you’ve discussed to help enhance the lives of folks in this theme. Through your current articles, I’ve gone through just a newbie to a pro in the area. It truly is truly a tribute to your good work. Thanks

  18. The same as someone else had said what a wonderful blog this is. Generally I dont take the time with a remark though for your time and effort you merit one. Congratulations are in order

  19. Hello.This post was really motivating, especially since i have was seeking ideas on this subject last Tuesday.

  20. Hey I absolutely enjoy this write-up and it was too excellent hence I am gonna tweet it. I Have to say the Indepth analysis this article has is trully extraordinary . Who goes that extra mile these days? Hats off to You . Just one more advise you definetlyintroduce a Translator for your Worldwide Readers !

  21. Hey I definetly dig your editorial and it is too admirable hence I am going to bookmark it. One thing to say the Wonderful research this article has is definetly remarkable !!! Who does that additional research now days? Hats off to You !!! Also another tip to you is that you canget any Translator Application for your Global Audience …

  22. I’ve been exploring for a little bit for any high quality articles or blog posts on this sort of area . Exploring in Yahoo I at last stumbled upon this website. A href=”http://www.ifundacja.pl”>1 procent Reading this info So i am happy to convey that I’ve a very good uncanny feeling I discovered just what I needed. I most certainly will make certain to do not forget this web site and give it a look on a constant basis.<

  23. I would like to consider the chance of saying thanks to you for your professional assistance I have constantly enjoyed viewing your site. I will be looking forward to the actual commencement of my school research and the complete groundwork would never have been complete without consulting this site. If I might be of any assistance to others, I would be glad to help through what I have learned from here.

  24. Great beat ! I wish to apprentice while you amend your web site, how could i subscribe for a weblog site? The account aided me a appropriate deal. I have been tiny bit acquainted of this your broadcast offered brilliant clear concept

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: