summaryrefslogtreecommitdiff
path: root/docs/daemon/www_enderunix.org_daemon.html
blob: c86ccff925fa39d517ccaaebbde1f80c630fd62b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
<html><head><!-- 
-->	



<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-9">
<meta http-equiv="Description" content="Unix Daemon Server Programming">
<meta http-equiv="Keywords" content="Levent, Karakaþ, Karakas, Unix, Daemon, Server, Programming"><title>Unix Daemon Server Programming</title>

<style type="text/css">
<!--
BODY, TD {
	background : #FFFFFF;
	color : #000000;
	font-family : normal arial, helvetica;
	font-size: 12px;
	text-align: justify;
}
H1 {
	font-size : 20px;
	text-align : center;
}
H2 {
	font-size : 16px;
	text-align : left;
}
A:link, A:visited {
	color: #0000FF;
	text-decoration: none;
}
//-->
</style></head><body>

<div align="center">

<table border="0" cellpadding="0" cellspacing="0" width="600">
  <tbody><tr>
    <td>

<h1>Unix Daemon Server Programming</h1>

<h2>Introduction</h2>

<p>Unix processes works either in foreground or background. A process
running in foreground interacts with the user in front of the terminal
(makes I/O), whereas a background process runs by itself. The user can
check its status but he doesn't (need to) know what it is doing. The
term 'daemon' is used for processes that performs service in
background. A server is a process that begins execution at startup (not
neccessarily), runs forever, usually do not die or get restarted,
operates in background, waits for requests to arrive and respond to
them and frequently spawn other processes to handle these requests.</p>

<p>Readers are suppossed to know Unix fundamentals and C language. For
further description on any topic use "man" command (I write useful
keywords in brackets), it has always been very useful, trust me :))
Keep in mind that this document does not contain everything, it is just
a guide.</p>


<h2>1) Daemonizing (programming to operate in background) [fork]</h2>

<p>First the fork() system call will be used to create a copy of our
process(child), then let parent exit. Orphaned child will become a
child of init process (this is the initial system process, in other
words the parent of all processes). As a result our process will be
completely detached from its parent and start operating in background.</p>

<pre>	i=fork();
	if (i&lt;0) exit(1); /* fork error */
	if (i&gt;0) exit(0); /* parent exits */
	/* child (daemon) continues */
</pre>

<h2>2) Process Independency [setsid]</h2>

<p>A process receives signals from the terminal that it is connected
to, and each process inherits its parent's controlling tty. A server
should not receive signals from the process that started it, so it must
detach itself from its controlling tty.</p>

<p>In Unix systems, processes operates within a process group, so that
all processes within a group is treated as a single entity. Process
group or session is also inherited. A server should operate
independently from other processes.</p>

<pre>	setsid() /* obtain a new process group */
</pre>

<p>This call will place the server in a new process group and session
and detach its controlling terminal. (setpgrp() is an alternative for
this)</p>

<h2>3) Inherited Descriptors and Standart I/0 Descriptors [gettablesize,fork,open,close,dup,stdio.h]</h2>

<p>Open descriptors are inherited to child process, this may cause the
use of resources unneccessarily. Unneccesarry descriptors should be
closed before fork() system call (so that they are not inherited) or
close all open descriptors as soon as the child process starts running.</p>

<pre>	for (i=getdtablesize();i&gt;=0;--i) close(i); /* close all descriptors */
</pre>

<p>There are three standart I/O descriptors: standart input 'stdin'
(0), standart output 'stdout' (1), standart error 'stderr' (2). A
standard library routine may read or write to standart I/O and it may
occur to a terminal or file. For safety, these descriptors should be
opened and connectedthem to a harmless I/O device (such as /dev/null).</p>

<pre>	i=open("/dev/null",O_RDWR); /* open stdin */
	dup(i); /* stdout */
	dup(i); /* stderr */
</pre>

<p>As Unix assigns descriptors sequentially, fopen call will open stdin and dup calls will provide a copy for stdout and stderr.</p>

<h2>4) File Creation Mask [umask]</h2>

<p>Most servers runs as super-user, for security reasons they should
protect files that they create. Setting user mask will pre vent
unsecure file priviliges that may occur on file creation.</p>

<pre>	umask(027);
</pre>

<p>This will restrict file creation mode to 750 (complement of 027).</p>

<h2>5) Running Directory [chdir]</h2>

<p>A server should run in a known directory. There are many advantages,
in fact the opposite has many disadvantages: suppose that our server is
started in a user's home directory, it will not be able to find some
input and output files.</p>

<pre>	chdir("/servers/");
</pre>

<p>The root "/" directory may not be appropriate for every server, it
should be choosen carefully depending on the type of the server.</p>

<h2>6) Mutual Exclusion and Running a Single Copy [open,lockf,getpid]</h2>

<p>Most services require running only one copy of a server at a time.
File locking method is a good solution for mutual exclusion. The first
instance of the server locks the file so that other instances
understand that an instance is already running. If server terminates
lock will be automatically released so that a new instance can run.
Recording the pid of the running instance is a good idea. It will
surely be efficient to make 'cat mydaamon.lock' instead of 'ps -ef|grep
mydaemon'</p>

<pre>	lfp=open("exampled.lock",O_RDWR|O_CREAT,0640);
	if (lfp&lt;0) exit(1); /* can not open */
	if (lockf(lfp,F_TLOCK,0)&lt;0) exit(0); /* can not lock */
	/* only first instance continues */

	sprintf(str,"%d\n",getpid());
	write(lfp,str,strlen(str)); /* record pid to lockfile */
</pre>

<h2>7) Catching Signals [signal,sys/signal.h]</h2>

<p>A process may receive signal from a user or a process, its best to
catch those signals and behave accordingly. Child processes send
SIGCHLD signal when they terminate, server process must either ignore
or handle these signals. Some servers also use hang-up signal to
restart the server and it is a good idea to rehash with a signal. Note
that 'kill' command sends SIGTERM (15) by default and SIGKILL (9)
signal can not be caught.</p>

<pre>	signal(SIG_IGN,SIGCHLD); /* child terminate signal */
</pre>

<p>The above code ignores the child terminate signal (on BSD systems
parents should wait for their child, so this signal should be caught to
avoid zombie processes), and the one below demonstrates how to catch
the signals.</p>

<pre>	void Signal_Handler(sig) /* signal handler function */
	int sig;
	{
		switch(sig){
			case SIGHUP:
				/* rehash the server */
				break;		
			case SIGTERM:
				/* finalize the server */
				exit(0)
				break;		
		}	
	}

	signal(SIGHUP,Signal_Handler); /* hangup signal */
	signal(SIGTERM,Signal_Handler); /* software termination signal from kill */
</pre>

<p>First we construct a signal handling function and then tie up signals to that function.</p>

<h2>8) Logging [syslogd,syslog.conf,openlog,syslog,closelog]</h2>

<p>A running server creates messages, naturally some are important and
should be logged. A programmer wants to see debug messages or a system
operator wants to see error messages. There are several ways to handle
those messages.</p>

<p><b>Redirecting all output to standard I/O : </b>This is what ancient
servers do, they use stdout and stderr so that messages are written to
console, terminal, file or printed on paper. I/O is redirected when
starting the server. (to change destination, server must be restarted)
In fact this kind of a server is a program running in foreground (not a
daemon).</p>

<pre>	# mydaemon 2&gt; error.log
</pre>

<p>This example is a program that prints output (stdout) messages to
console and error (stderr) messages to a file named "error.log". Note
that this is not a daemon but a normal program.</p>
<p><b>Log file method : </b>All messages are logged to files (to different files as needed). There is a sample logging function below.</p>

<pre>	void log_message(filename,message)
	char *filename;
	char *message;
	{
	FILE *logfile;
		logfile=fopen(filename,"a");
		if(!logfile) return;
		fprintf(logfile,"%s\n",message);
		fclose(logfile);
	}

	log_message("conn.log","connection accepted");
	log_message("error.log","can not open file");
</pre>

<p><b>Log server method : </b>A more flexible logging technique is
using log servers. Unix distributions have system log daemon named
"syslogd". This daemon groups messages into classes (known as facility)
and these classes can be redirected to different places. Syslog uses a
configuration file (/etc/syslog.conf) that those redirection rules
reside in.</p>

<pre>	openlog("mydaemon",LOG_PID,LOG_DAEMON)
	syslog(LOG_INFO, "Connection from host %d", callinghostname);
	syslog(LOG_ALERT, "Database Error !");
	closelog();
</pre>

<p>In openlog call "mydaemon" is a string that identifies our daemon,
LOG_PID makes syslogd log the process id with each message and
LOG_DAEMON is the message class. When calling syslog call first
parameter is the priority and the rest works like printf/sprintf. There
are several message classes (or facility names), log options and
priority levels. Here are some examples :</p>

<dl>
<dd>Message classes : LOG_USER, LOG_DAEMON, LOG_LOCAL0 to LOG_LOCAL7</dd>
<dd>Log options : LOG_PID, LOG_CONS, LOG_PERROR</dd>
<dd>Priority levels : LOG_EMERG, LOG_ALERT, LOG_ERR, LOG_WARNING, LOG_INFO</dd>
</dl>

<h2>About</h2>

<p>This text is written by Levent Karakas <a href="mailto:levent%20at%20mektup%20dot%20at">&lt;levent at mektup dot at &gt;</a>.
Several books, sources and manual pages are used. This text includes a
sample daemon program (compiles on Linux 2.4.2, OpenBSD 2.7, SunOS 5.8,
SCO-Unix 3.2 and probably on your flavor of Unix). You can also
download plain source file : <a href="http://www.enderunix.org/documents/eng/exampled.c">exampled.c</a>. Hope you find this document useful. We do love Unix.</p>

<pre>
/*
UNIX Daemon Server Programming Sample Program
Levent Karakas &lt;levent at mektup dot at&gt; May 2001

To compile:	cc -o exampled examped.c
To run:		./exampled
To test daemon:	ps -ef|grep exampled (or ps -aux on BSD systems)
To test log:	tail -f /tmp/exampled.log
To test signal:	kill -HUP `cat /tmp/exampled.lock`
To terminate:	kill `cat /tmp/exampled.lock`
*/

#include &lt;stdio.h&gt;
#include &lt;fcntl.h&gt;
#include &lt;signal.h&gt;
#include &lt;unistd.h&gt;

#define RUNNING_DIR	"/tmp"
#define LOCK_FILE	"exampled.lock"
#define LOG_FILE	"exampled.log"

void log_message(filename,message)
char *filename;
char *message;
{
FILE *logfile;
	logfile=fopen(filename,"a");
	if(!logfile) return;
	fprintf(logfile,"%s\n",message);
	fclose(logfile);
}

void signal_handler(sig)
int sig;
{
	switch(sig) {
	case SIGHUP:
		log_message(LOG_FILE,"hangup signal catched");
		break;
	case SIGTERM:
		log_message(LOG_FILE,"terminate signal catched");
		exit(0);
		break;
	}
}

void daemonize()
{
int i,lfp;
char str[10];
	if(getppid()==1) return; /* already a daemon */
	i=fork();
	if (i&lt;0) exit(1); /* fork error */
	if (i&gt;0) exit(0); /* parent exits */
	/* child (daemon) continues */
	setsid(); /* obtain a new process group */
	for (i=getdtablesize();i&gt;=0;--i) close(i); /* close all descriptors */
	i=open("/dev/null",O_RDWR); dup(i); dup(i); /* handle standart I/O */
	umask(027); /* set newly created file permissions */
	chdir(RUNNING_DIR); /* change running directory */
	lfp=open(LOCK_FILE,O_RDWR|O_CREAT,0640);
	if (lfp&lt;0) exit(1); /* can not open */
	if (lockf(lfp,F_TLOCK,0)&lt;0) exit(0); /* can not lock */
	/* first instance continues */
	sprintf(str,"%d\n",getpid());
	write(lfp,str,strlen(str)); /* record pid to lockfile */
	signal(SIGCHLD,SIG_IGN); /* ignore child */
	signal(SIGTSTP,SIG_IGN); /* ignore tty signals */
	signal(SIGTTOU,SIG_IGN);
	signal(SIGTTIN,SIG_IGN);
	signal(SIGHUP,signal_handler); /* catch hangup signal */
	signal(SIGTERM,signal_handler); /* catch kill signal */
}

main()
{
	daemonize();
	while(1) sleep(1); /* run */
}

/* EOF */

</pre>

<p>&nbsp;</p>
<p>Last Update : 16.05.2001</p>
<p>&nbsp;</p>


    </td>
  </tr>
</tbody></table><br>

</div>


</body></html>