Wednesday, November 19, 2014
Tuesday, June 23, 2009
getting gateway address
getGW()
{
struct nlmsghdr *nlMsg;
struct rtmsg *rtMsg;
struct route_info *rtInfo;
char msgBuf[BUFSIZE];
char mobileIp[20];
int sock, len, msgSeq = 0;
char buff[1024];
if((sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0)
perror("Socket Creation: ");
memset(msgBuf, 0, BUFSIZE);
nlMsg = (struct nlmsghdr *)msgBuf;
rtMsg = (struct rtmsg *)NLMSG_DATA(nlMsg);
nlMsg->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); // Length of message.
nlMsg->nlmsg_type = RTM_GETROUTE; // Get the routes from kernel routing table .
nlMsg->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST; // The message is a request for dump.
nlMsg->nlmsg_seq = msgSeq++; // Sequence of the message packet.
nlMsg->nlmsg_pid = getpid(); // PID of process sending the request.
if(send(sock, nlMsg, nlMsg->nlmsg_len, 0) < 0)
{
printf("Write To Socket Failed...\n");
return -1;
}
if((len = readNlSock(sock, msgBuf, msgSeq, getpid())) < 0)
{
printf("Read From Socket Failed...\n");
return -1;
}
rtInfo = (struct route_info *)malloc(sizeof(struct route_info));
for(;NLMSG_OK(nlMsg,len);nlMsg = NLMSG_NEXT(nlMsg,len))
{
memset(rtInfo, 0, sizeof(struct route_info));
parseRoutes(nlMsg, rtInfo);
}
free(rtInfo);
close(sock);
// printf("%s\n",gateway);
}
{
struct nlmsghdr *nlMsg;
struct rtmsg *rtMsg;
struct route_info *rtInfo;
char msgBuf[BUFSIZE];
char mobileIp[20];
int sock, len, msgSeq = 0;
char buff[1024];
if((sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0)
perror("Socket Creation: ");
memset(msgBuf, 0, BUFSIZE);
nlMsg = (struct nlmsghdr *)msgBuf;
rtMsg = (struct rtmsg *)NLMSG_DATA(nlMsg);
nlMsg->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); // Length of message.
nlMsg->nlmsg_type = RTM_GETROUTE; // Get the routes from kernel routing table .
nlMsg->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST; // The message is a request for dump.
nlMsg->nlmsg_seq = msgSeq++; // Sequence of the message packet.
nlMsg->nlmsg_pid = getpid(); // PID of process sending the request.
if(send(sock, nlMsg, nlMsg->nlmsg_len, 0) < 0)
{
printf("Write To Socket Failed...\n");
return -1;
}
if((len = readNlSock(sock, msgBuf, msgSeq, getpid())) < 0)
{
printf("Read From Socket Failed...\n");
return -1;
}
rtInfo = (struct route_info *)malloc(sizeof(struct route_info));
for(;NLMSG_OK(nlMsg,len);nlMsg = NLMSG_NEXT(nlMsg,len))
{
memset(rtInfo, 0, sizeof(struct route_info));
parseRoutes(nlMsg, rtInfo);
}
free(rtInfo);
close(sock);
// printf("%s\n",gateway);
}
find loca lip
find_local_ip(char *src_ip_addr,char *interface)
{
int tempsfd;
struct ifreq ifr;
struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
memset(&ifr,0,sizeof(ifr));
if((tempsfd = socket(AF_INET,SOCK_STREAM,0))==-1) {
perror("temp socket");
exit(0);
}
strcpy(ifr.ifr_name,interface);
sin->sin_family = AF_INET;
if(ioctl(tempsfd,SIOCGIFADDR,&ifr)==0) {
close(tempsfd);
strcpy(src_ip_addr,inet_ntoa(sin->sin_addr));
return 0;
}
else
perror("ioctl");
close(tempsfd);
return 0;
}
{
int tempsfd;
struct ifreq ifr;
struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
memset(&ifr,0,sizeof(ifr));
if((tempsfd = socket(AF_INET,SOCK_STREAM,0))==-1) {
perror("temp socket");
exit(0);
}
strcpy(ifr.ifr_name,interface);
sin->sin_family = AF_INET;
if(ioctl(tempsfd,SIOCGIFADDR,&ifr)==0) {
close(tempsfd);
strcpy(src_ip_addr,inet_ntoa(sin->sin_addr));
return 0;
}
else
perror("ioctl");
close(tempsfd);
return 0;
}
Monday, June 8, 2009
Unix Daemon Server Programming
Introduction
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.
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.
1) Daemonizing (programming to operate in background) [fork]
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.
i=fork();
if (i<0) exit(1); /* fork error */
if (i>0) exit(0); /* parent exits */
/* child (daemon) continues */
2) Process Independency [setsid]
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.
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.
setsid() /* obtain a new process group */
This call will place the server in a new process group and session and
detach its controlling terminal. (setpgrp() is an alternative for this)
3) Inherited Descriptors and Standart I/0 Descriptors
[gettablesize,fork,open,close,dup,stdio.h]
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.
for (i=getdtablesize();i>=0;--i) close(i); /* close all descriptors
*/
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).
i=open("/dev/null",O_RDWR); /* open stdin */
dup(i); /* stdout */
dup(i); /* stderr */
As Unix assigns descriptors sequentially, fopen call will open stdin and
dup calls will provide a copy for stdout and stderr.
4) File Creation Mask [umask]
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.
umask(027);
This will restrict file creation mode to 750 (complement of 027).
5) Running Directory [chdir]
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.
chdir("/servers/");
The root "/" directory may not be appropriate for every server, it should
be choosen carefully depending on the type of the server.
6) Mutual Exclusion and Running a Single Copy [open,lockf,getpid]
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'
lfp=open("exampled.lock",O_RDWR|O_CREAT,0640);
if (lfp<0) exit(1); /* can not open */
if (lockf(lfp,F_TLOCK,0)<0) exit(0); /* can not lock */
/* only first instance continues */
sprintf(str,"%d\n",getpid());
write(lfp,str,strlen(str)); /* record pid to lockfile */
7) Catching Signals [signal,sys/signal.h]
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.
signal(SIG_IGN,SIGCHLD); /* child terminate signal */
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.
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 */
First we construct a signal handling function and then tie up signals to
that function.
8) Logging [syslogd,syslog.conf,openlog,syslog,closelog]
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.
Redirecting all output to standard I/O : 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).
# mydaemon 2> error.log
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.
Log file method : All messages are logged to files (to different files as
needed). There is a sample logging function below.
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");
Log server method : 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.
openlog("mydaemon",LOG_PID,LOG_DAEMON)
syslog(LOG_INFO, "Connection from host %d", callinghostname);
syslog(LOG_ALERT, "Database Error !");
closelog();
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 :
Message classes : LOG_USER, LOG_DAEMON, LOG_LOCAL0 to LOG_LOCAL7
Log options : LOG_PID, LOG_CONS, LOG_PERROR
Priority levels : LOG_EMERG, LOG_ALERT, LOG_ERR, LOG_WARNING, LOG_INFO
About
This text is written by Levent Karakas
. 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 : exampled.c
. Hope you find this
document useful. We do love Unix.
/*
UNIX Daemon Server Programming Sample Program
Levent Karakas 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
#include
#include
#include
#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<0) exit(1); /* fork error */
if (i>0) exit(0); /* parent exits */
/* child (daemon) continues */
setsid(); /* obtain a new process group */
for (i=getdtablesize();i>=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<0) exit(1); /* can not open */
if (lockf(lfp,F_TLOCK,0)<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 */
}
1.7 How do I get my program to act like a daemon?
A daemon process is usually defined as a background process that does not belong to a terminal session.
Many system services are performed by daemons; network services, printing etc.
Simply invoking a program in the background isn't really adequate for these long-running programs; that
does not correctly detach the process from the terminal session that started it. Also, the conventional way
of starting daemons is simply to issue the command manually or from an rc script; the daemon is expected
to put itself into the background.
Here are the steps to become a daemon:
fork() so the parent can exit, this returns control to the command line or shell invoking your
program. This step is required so that the new process is guaranteed not to be a process group
leader. The next step, setsid(), fails if you're a process group leader.
1.
setsid() to become a process group and session group leader. Since a controlling terminal is
associated with a session, and this new session has not yet acquired a controlling terminal our
process now has no controlling terminal, which is a Good Thing for daemons.
2.
fork() again so the parent, (the session group leader), can exit. This means that we, as a
non-session group leader, can never regain a controlling terminal.
3.
chdir("/") to ensure that our process doesn't keep any directory in use. Failure to do this could
make it so that an administrator couldn't unmount a filesystem, because it was our current directory.
[Equivalently, we could change to any directory containing files important to the daemon's
operation.]
4.
umask(0) so that we have complete control over the permissions of anything we write. We don't
know what umask we may have inherited. [This step is optional]
5.
close() fds 0, 1, and 2. This releases the standard in, out, and error we inherited from our parent
process. We have no way of knowing where these fds might have been redirected to. Note that
many daemons use sysconf() to determine the limit _SC_OPEN_MAX. _SC_OPEN_MAX tells
you the maximun open files/process. Then in a loop, the daemon can close all possible file
descriptors. You have to decide if you need to do this or not. If you think that there might be
file-descriptors open you should close them, since there's a limit on number of concurrent file
descriptors.
6.
Establish new open descriptors for stdin, stdout and stderr. Even if you don't plan to use them, it is
still a good idea to have them open. The precise handling of these is a matter of taste; if you have a
logfile, for example, you might wish to open it as stdout or stderr, and open `/dev/null' as
stdin; alternatively, you could open `/dev/console' as stderr and/or stdout, and
`/dev/null' as stdin, or any other combination that makes sense for your particular daemon.
7.
Almost none of this is necessary (or advisable) if your daemon is being started by inetd. In that case,
stdin, stdout and stderr are all set up for you to refer to the network connection, and the fork()s and
session manipulation should not be done (to avoid confusing inetd). Only the chdir() and umask()
steps remain as useful.
/* EOF */
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.
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.
1) Daemonizing (programming to operate in background) [fork]
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.
i=fork();
if (i<0) exit(1); /* fork error */
if (i>0) exit(0); /* parent exits */
/* child (daemon) continues */
2) Process Independency [setsid]
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.
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.
setsid() /* obtain a new process group */
This call will place the server in a new process group and session and
detach its controlling terminal. (setpgrp() is an alternative for this)
3) Inherited Descriptors and Standart I/0 Descriptors
[gettablesize,fork,open,close,dup,stdio.h]
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.
for (i=getdtablesize();i>=0;--i) close(i); /* close all descriptors
*/
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).
i=open("/dev/null",O_RDWR); /* open stdin */
dup(i); /* stdout */
dup(i); /* stderr */
As Unix assigns descriptors sequentially, fopen call will open stdin and
dup calls will provide a copy for stdout and stderr.
4) File Creation Mask [umask]
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.
umask(027);
This will restrict file creation mode to 750 (complement of 027).
5) Running Directory [chdir]
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.
chdir("/servers/");
The root "/" directory may not be appropriate for every server, it should
be choosen carefully depending on the type of the server.
6) Mutual Exclusion and Running a Single Copy [open,lockf,getpid]
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'
lfp=open("exampled.lock",O_RDWR|O_CREAT,0640);
if (lfp<0) exit(1); /* can not open */
if (lockf(lfp,F_TLOCK,0)<0) exit(0); /* can not lock */
/* only first instance continues */
sprintf(str,"%d\n",getpid());
write(lfp,str,strlen(str)); /* record pid to lockfile */
7) Catching Signals [signal,sys/signal.h]
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.
signal(SIG_IGN,SIGCHLD); /* child terminate signal */
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.
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 */
First we construct a signal handling function and then tie up signals to
that function.
8) Logging [syslogd,syslog.conf,openlog,syslog,closelog]
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.
Redirecting all output to standard I/O : 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).
# mydaemon 2> error.log
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.
Log file method : All messages are logged to files (to different files as
needed). There is a sample logging function below.
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");
Log server method : 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.
openlog("mydaemon",LOG_PID,LOG_DAEMON)
syslog(LOG_INFO, "Connection from host %d", callinghostname);
syslog(LOG_ALERT, "Database Error !");
closelog();
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 :
Message classes : LOG_USER, LOG_DAEMON, LOG_LOCAL0 to LOG_LOCAL7
Log options : LOG_PID, LOG_CONS, LOG_PERROR
Priority levels : LOG_EMERG, LOG_ALERT, LOG_ERR, LOG_WARNING, LOG_INFO
About
This text is written by Levent Karakas
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 : exampled.c
document useful. We do love Unix.
/*
UNIX Daemon Server Programming Sample Program
Levent Karakas
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
#include
#include
#include
#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<0) exit(1); /* fork error */
if (i>0) exit(0); /* parent exits */
/* child (daemon) continues */
setsid(); /* obtain a new process group */
for (i=getdtablesize();i>=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<0) exit(1); /* can not open */
if (lockf(lfp,F_TLOCK,0)<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 */
}
1.7 How do I get my program to act like a daemon?
A daemon process is usually defined as a background process that does not belong to a terminal session.
Many system services are performed by daemons; network services, printing etc.
Simply invoking a program in the background isn't really adequate for these long-running programs; that
does not correctly detach the process from the terminal session that started it. Also, the conventional way
of starting daemons is simply to issue the command manually or from an rc script; the daemon is expected
to put itself into the background.
Here are the steps to become a daemon:
fork() so the parent can exit, this returns control to the command line or shell invoking your
program. This step is required so that the new process is guaranteed not to be a process group
leader. The next step, setsid(), fails if you're a process group leader.
1.
setsid() to become a process group and session group leader. Since a controlling terminal is
associated with a session, and this new session has not yet acquired a controlling terminal our
process now has no controlling terminal, which is a Good Thing for daemons.
2.
fork() again so the parent, (the session group leader), can exit. This means that we, as a
non-session group leader, can never regain a controlling terminal.
3.
chdir("/") to ensure that our process doesn't keep any directory in use. Failure to do this could
make it so that an administrator couldn't unmount a filesystem, because it was our current directory.
[Equivalently, we could change to any directory containing files important to the daemon's
operation.]
4.
umask(0) so that we have complete control over the permissions of anything we write. We don't
know what umask we may have inherited. [This step is optional]
5.
close() fds 0, 1, and 2. This releases the standard in, out, and error we inherited from our parent
process. We have no way of knowing where these fds might have been redirected to. Note that
many daemons use sysconf() to determine the limit _SC_OPEN_MAX. _SC_OPEN_MAX tells
you the maximun open files/process. Then in a loop, the daemon can close all possible file
descriptors. You have to decide if you need to do this or not. If you think that there might be
file-descriptors open you should close them, since there's a limit on number of concurrent file
descriptors.
6.
Establish new open descriptors for stdin, stdout and stderr. Even if you don't plan to use them, it is
still a good idea to have them open. The precise handling of these is a matter of taste; if you have a
logfile, for example, you might wish to open it as stdout or stderr, and open `/dev/null' as
stdin; alternatively, you could open `/dev/console' as stderr and/or stdout, and
`/dev/null' as stdin, or any other combination that makes sense for your particular daemon.
7.
Almost none of this is necessary (or advisable) if your daemon is being started by inetd. In that case,
stdin, stdout and stderr are all set up for you to refer to the network connection, and the fork()s and
session manipulation should not be done (to avoid confusing inetd). Only the chdir() and umask()
steps remain as useful.
/* EOF */
Friday, June 5, 2009
Libraries
In general, there are two types of library files: dynamic libraries and static libraries.
I. Dynamic Libraries
Dynamic libraries (also known as shared libraries) are pieces of compiled code which are loaded by the runtime linker /lib/ld.so when an executable is run. This is analagous to the .dll files of MS Windows. In terms of efficiency, this saves:
* Hard drive space: different executables can share the same code
* RAM: the kernel can store one copy of the library in memory and this can be shared between executables
* Time: upgrading involves compiling less code if you don't have to recompile the libraries.
Dynamic libraries are named, by convention, with the string so, followed by a version number. Examples are:
libc.so.6 The C library. Don't delete it. :)
libcrypt.so.1 The encryption library for shadow systems.
libncurses.so.4.2 The new curses library routines.
II. Static Libraries
Static libraries are bolted into the executable rather than being somewhere else on the system and loaded into the executable by ld.so. The pro is that the executable is self contained; it doesn't depend on code elsewhere on the system, and not subject to missing libraries. You can give this code to anyone else and it's guarenteed to work. The con is that the executable is larger than necessary and you can't share code between different programs.
Static libraries are named, by convention, with the string .a appended to the library name. Some examples are:
libgtk.a Graphics libraries for GIMP and many other X apps.
libcrypt.a The encryption library for shadow systems.
libvga.a. Library for full screen [S]VGA graphics.
III. Comparison Between Dynamic and Static Libraries
Programs that use static libraries that were bolted into them should be slightly faster than programs that have to use ld.so to load in dynamically linked code. I've seen people say that the order of magnitude of startup time difference is abot 5%. However, it has to be kept in mind that one of the benefits of dyanmic libraries is that in a good case scenario, the code is already loaded into memory. In fact, for libc, this is always going to be true. If you tried to load a statically linked netscape, you'd have to wait consderably longer for it to load. The answer to which one is faster is `it depends'. But all in all, it's a safe bet to say that a program will be faster with dynamic libraries since chances are good that the code you need is already in memory.
IV. Important Files/Executables
The program /lib/ld.so is responsible for linking dynamic libraries for an executable. It searches for library files in the following order:
1. In directories listed by the environment variable LD_LIBRARY_PATH unless the executable is setuid/setgid, in which case the environment variable is ignored.
2. In directories listed in the file /etc/ld.so.cache. See below.
3. In /usr/lib
4. In /lib
There's a very good reason why ld.so doesn't search /usr/local/lib for dynamic libraries. I would tell you, but then I'd have to kill you. Some things were just not meant for mere mortals to know...
The file /etc/ld.so.cache contains a compiled list of directories to search for libraries and an ordered list of candidate libraries. It's created by /sbin/ldconfig.
The program /sbin/ldconfig is run automatically (/etc/rc) at boot or manually by the user after compiling libraries (it's a good idea to ALWAYS run ldconfig after installing software). ldconfig generates the file /etc/ld.so.cache. It searches /lib, /usr/lib and all the directories listed by /etc/ld.so.conf.
The configuration file /etc/ld.so.conf lists all the directories that ldconfig is to search for libraries to generate ld.so.cache. If you ever put library files in a non-standard directory (like /home/lib) you should add that directory to the end of ld.so.conf and rerun ldconfig.
V. Cool Utilities
Many programs require dynamic libraries to be present on your system so the library's code can be used by the program. How can you find out which dynamic libraries are required by any given program? There's two ways.
You can use strace. For an example, find xmms, xcalc or xpaint on your system using the locate command. Try the following command:
strace -o LOG /usr/X11R6/bin/xcalc
quit the program and you'll find a file named LOG was left behind. Load up LOG with your favorite text editor and pour through the output, searching for the string so. Can you see which libraries are being called by xcalc (or whichever program you decided to use)? Can you also see some of the files mentioned above like ld.so.cache or libc.so? You also might see some interesting things, like a search for a library in one directory ends up with a "file not found" condition, so the program searches for the same library in another location. Here is what that looks like (for xcalc on my system):
open("/usr/local/rvplayer5.0/libXext.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/X11R6/lib/libXext.so.6", O_RDONLY) = 4
Apparenlty, libXext.so.6 is not located in /usr/local/rvplayer5.0, but ld.so found it in /usr/X11R6/lib. Fortunately, there's an easier way to find this information. Try:
ldd /usr/X11R6/bin/xcalc
(the full pathname is required). ldd will respond with:
libXaw.so.6 => /usr/X11R6/lib/Xaw3d/libXaw.so.6 (0x40020000)
libXmu.so.6 => /usr/X11R6/lib/libXmu.so.6 (0x40077000)
libXt.so.6 => /usr/X11R6/lib/libXt.so.6 (0x40089000)
libSM.so.6 => /usr/X11R6/lib/libSM.so.6 (0x400d3000)
libICE.so.6 => /usr/X11R6/lib/libICE.so.6 (0x400dd000)
libXext.so.6 => /usr/X11R6/lib/libXext.so.6 (0x400f3000)
libX11.so.6 => /usr/X11R6/lib/libX11.so.6 (0x400ff000)
libm.so.6 => /lib/libm.so.6 (0x401a5000)
libc.so.6 => /usr/lib/libc.so.6 (0x401c2000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
Jumpin' Jehosephat! ldd even finds the location of the library file for you! How's that for service?
VI. End Notes
So when you write a hello world program and compile it with gcc, are you using dynanmic or static libraries? gcc uses dynamic libraries, unless you give the -static option to the linker. As an example, here is my hello world program:
% cat try.c
#include
int main(void) {
printf("Hello, world!\n");
return 0; }
after compiling it with:
% gcc try.c
here is what ldd has to say about a.out:
% ldd a.out
libc.so.6 => /usr/lib/libc.so.6 (0x40020000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
Now let's compile it with static libraries:
% gcc -static try.c
and here's what ldd has to say about the new executable:
% ldd a.out
not a dynamic executable
I. Dynamic Libraries
Dynamic libraries (also known as shared libraries) are pieces of compiled code which are loaded by the runtime linker /lib/ld.so when an executable is run. This is analagous to the .dll files of MS Windows. In terms of efficiency, this saves:
* Hard drive space: different executables can share the same code
* RAM: the kernel can store one copy of the library in memory and this can be shared between executables
* Time: upgrading involves compiling less code if you don't have to recompile the libraries.
Dynamic libraries are named, by convention, with the string so, followed by a version number. Examples are:
libc.so.6 The C library. Don't delete it. :)
libcrypt.so.1 The encryption library for shadow systems.
libncurses.so.4.2 The new curses library routines.
II. Static Libraries
Static libraries are bolted into the executable rather than being somewhere else on the system and loaded into the executable by ld.so. The pro is that the executable is self contained; it doesn't depend on code elsewhere on the system, and not subject to missing libraries. You can give this code to anyone else and it's guarenteed to work. The con is that the executable is larger than necessary and you can't share code between different programs.
Static libraries are named, by convention, with the string .a appended to the library name. Some examples are:
libgtk.a Graphics libraries for GIMP and many other X apps.
libcrypt.a The encryption library for shadow systems.
libvga.a. Library for full screen [S]VGA graphics.
III. Comparison Between Dynamic and Static Libraries
Programs that use static libraries that were bolted into them should be slightly faster than programs that have to use ld.so to load in dynamically linked code. I've seen people say that the order of magnitude of startup time difference is abot 5%. However, it has to be kept in mind that one of the benefits of dyanmic libraries is that in a good case scenario, the code is already loaded into memory. In fact, for libc, this is always going to be true. If you tried to load a statically linked netscape, you'd have to wait consderably longer for it to load. The answer to which one is faster is `it depends'. But all in all, it's a safe bet to say that a program will be faster with dynamic libraries since chances are good that the code you need is already in memory.
IV. Important Files/Executables
The program /lib/ld.so is responsible for linking dynamic libraries for an executable. It searches for library files in the following order:
1. In directories listed by the environment variable LD_LIBRARY_PATH unless the executable is setuid/setgid, in which case the environment variable is ignored.
2. In directories listed in the file /etc/ld.so.cache. See below.
3. In /usr/lib
4. In /lib
There's a very good reason why ld.so doesn't search /usr/local/lib for dynamic libraries. I would tell you, but then I'd have to kill you. Some things were just not meant for mere mortals to know...
The file /etc/ld.so.cache contains a compiled list of directories to search for libraries and an ordered list of candidate libraries. It's created by /sbin/ldconfig.
The program /sbin/ldconfig is run automatically (/etc/rc) at boot or manually by the user after compiling libraries (it's a good idea to ALWAYS run ldconfig after installing software). ldconfig generates the file /etc/ld.so.cache. It searches /lib, /usr/lib and all the directories listed by /etc/ld.so.conf.
The configuration file /etc/ld.so.conf lists all the directories that ldconfig is to search for libraries to generate ld.so.cache. If you ever put library files in a non-standard directory (like /home/lib) you should add that directory to the end of ld.so.conf and rerun ldconfig.
V. Cool Utilities
Many programs require dynamic libraries to be present on your system so the library's code can be used by the program. How can you find out which dynamic libraries are required by any given program? There's two ways.
You can use strace. For an example, find xmms, xcalc or xpaint on your system using the locate command. Try the following command:
strace -o LOG /usr/X11R6/bin/xcalc
quit the program and you'll find a file named LOG was left behind. Load up LOG with your favorite text editor and pour through the output, searching for the string so. Can you see which libraries are being called by xcalc (or whichever program you decided to use)? Can you also see some of the files mentioned above like ld.so.cache or libc.so? You also might see some interesting things, like a search for a library in one directory ends up with a "file not found" condition, so the program searches for the same library in another location. Here is what that looks like (for xcalc on my system):
open("/usr/local/rvplayer5.0/libXext.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/X11R6/lib/libXext.so.6", O_RDONLY) = 4
Apparenlty, libXext.so.6 is not located in /usr/local/rvplayer5.0, but ld.so found it in /usr/X11R6/lib. Fortunately, there's an easier way to find this information. Try:
ldd /usr/X11R6/bin/xcalc
(the full pathname is required). ldd will respond with:
libXaw.so.6 => /usr/X11R6/lib/Xaw3d/libXaw.so.6 (0x40020000)
libXmu.so.6 => /usr/X11R6/lib/libXmu.so.6 (0x40077000)
libXt.so.6 => /usr/X11R6/lib/libXt.so.6 (0x40089000)
libSM.so.6 => /usr/X11R6/lib/libSM.so.6 (0x400d3000)
libICE.so.6 => /usr/X11R6/lib/libICE.so.6 (0x400dd000)
libXext.so.6 => /usr/X11R6/lib/libXext.so.6 (0x400f3000)
libX11.so.6 => /usr/X11R6/lib/libX11.so.6 (0x400ff000)
libm.so.6 => /lib/libm.so.6 (0x401a5000)
libc.so.6 => /usr/lib/libc.so.6 (0x401c2000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
Jumpin' Jehosephat! ldd even finds the location of the library file for you! How's that for service?
VI. End Notes
So when you write a hello world program and compile it with gcc, are you using dynanmic or static libraries? gcc uses dynamic libraries, unless you give the -static option to the linker. As an example, here is my hello world program:
% cat try.c
#include
int main(void) {
printf("Hello, world!\n");
return 0; }
after compiling it with:
% gcc try.c
here is what ldd has to say about a.out:
% ldd a.out
libc.so.6 => /usr/lib/libc.so.6 (0x40020000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
Now let's compile it with static libraries:
% gcc -static try.c
and here's what ldd has to say about the new executable:
% ldd a.out
not a dynamic executable
customization of runlevels
The /etc/rc.d/rc File
Customization of runlevels
Suppose you have something that you'd like to run whenever you start your system. Perhaps you installed xfstt or some other truetype font server and you'd like for xfstt to run whenever the system goes up so you don't have to keep typing xfstt --daemon every time you boot up. Let's take a look at the script /etc/rc.d/rc. Here are the first few lines:
#!/bin/bash
#
# rc This file is responsible for starting/stopping services when the
# runlevel changes. It is also responsible for the very first setup of
# basic things, such as setting the hostname.
it's a shell script! Let's look further.
# Source function library.
. /etc/rc.d/init.d/functions
The file `functions' is a shell script with a bunch of useful functions, such as:
daemon(): A function to start a program.
killproc(): A function to stop a program.
pidofproc(): A function to find the pid of a program.
status(): Gives the status of a process (running? not running? locked?)
The rest is a little technical, but here is the nuts and bolts of it.
The scripts to start in runlevel 1 are stored in /etc/rc.d/rc1.d. The scripts to start in runlevel 2 are stored in /etc/rc.d/rc2.d. The scripts to start in runlevel 3 are stored in /etc/rc.d/rc3.d. The scripts to ... well, you get the picture.
First, we create a file called /var/run/runlevel.dir which contains the name of the directory which we're going to start running scripts from. For example, if we enter runlevel 4, the file runlevel.dir will contain the text "/etc/rc.d/rc4.d". This is how programs that run on our system (like linuxconfig) learn what runlevel we're currently in.
Next we check to is if there exists a directory for the runlevel we're about to enter (pedantic yes, but necessary!).
# Is there an rc directory for this new runlevel?
if [ -d /etc/rc.d/rc$runlevel.d ]; then
# First, run the KILL scripts.
for i in /etc/rc.d/rc$runlevel.d/K*; do
# Check if the script is there.
[ ! -f $i ] && continue
# Don't run [KS]??foo.{rpmsave,rpmorig} scripts
[ "${1%.rpmsave}" != "${1}" ] && continue
[ "${1%.rpmorig}" != "${1}" ] && continue
# Check if the subsystem is already up.
subsys=${i#/etc/rc.d/rc$runlevel.d/K??}
[ ! -f /var/lock/subsys/$subsys ] && \
[ ! -f /var/lock/subsys/${subsys}.init ] && continue
# Bring the subsystem down.
$i stop
done
# Now run the START scripts.
for i in /etc/rc.d/rc$runlevel.d/S*; do
# Check if the script is there.
[ ! -f $i ] && continue
# Don't run [KS]??foo.{rpmsave,rpmorig} scripts
[ "${1%.rpmsave}" != "${1}" ] && continue
[ "${1%.rpmorig}" != "${1}" ] && continue
# Check if the subsystem is already up.
subsys=${i#/etc/rc.d/rc$runlevel.d/S??}
[ -f /var/lock/subsys/$subsys ] || \
[ -f /var/lock/subsys/${subsys}.init ] && continue
# Bring the subsystem up.
$i start
done
fi
Customization of runlevels
Suppose you have something that you'd like to run whenever you start your system. Perhaps you installed xfstt or some other truetype font server and you'd like for xfstt to run whenever the system goes up so you don't have to keep typing xfstt --daemon every time you boot up. Let's take a look at the script /etc/rc.d/rc. Here are the first few lines:
#!/bin/bash
#
# rc This file is responsible for starting/stopping services when the
# runlevel changes. It is also responsible for the very first setup of
# basic things, such as setting the hostname.
it's a shell script! Let's look further.
# Source function library.
. /etc/rc.d/init.d/functions
The file `functions' is a shell script with a bunch of useful functions, such as:
daemon(): A function to start a program.
killproc(): A function to stop a program.
pidofproc(): A function to find the pid of a program.
status(): Gives the status of a process (running? not running? locked?)
The rest is a little technical, but here is the nuts and bolts of it.
The scripts to start in runlevel 1 are stored in /etc/rc.d/rc1.d. The scripts to start in runlevel 2 are stored in /etc/rc.d/rc2.d. The scripts to start in runlevel 3 are stored in /etc/rc.d/rc3.d. The scripts to ... well, you get the picture.
First, we create a file called /var/run/runlevel.dir which contains the name of the directory which we're going to start running scripts from. For example, if we enter runlevel 4, the file runlevel.dir will contain the text "/etc/rc.d/rc4.d". This is how programs that run on our system (like linuxconfig) learn what runlevel we're currently in.
Next we check to is if there exists a directory for the runlevel we're about to enter (pedantic yes, but necessary!).
# Is there an rc directory for this new runlevel?
if [ -d /etc/rc.d/rc$runlevel.d ]; then
# First, run the KILL scripts.
for i in /etc/rc.d/rc$runlevel.d/K*; do
# Check if the script is there.
[ ! -f $i ] && continue
# Don't run [KS]??foo.{rpmsave,rpmorig} scripts
[ "${1%.rpmsave}" != "${1}" ] && continue
[ "${1%.rpmorig}" != "${1}" ] && continue
# Check if the subsystem is already up.
subsys=${i#/etc/rc.d/rc$runlevel.d/K??}
[ ! -f /var/lock/subsys/$subsys ] && \
[ ! -f /var/lock/subsys/${subsys}.init ] && continue
# Bring the subsystem down.
$i stop
done
# Now run the START scripts.
for i in /etc/rc.d/rc$runlevel.d/S*; do
# Check if the script is there.
[ ! -f $i ] && continue
# Don't run [KS]??foo.{rpmsave,rpmorig} scripts
[ "${1%.rpmsave}" != "${1}" ] && continue
[ "${1%.rpmorig}" != "${1}" ] && continue
# Check if the subsystem is already up.
subsys=${i#/etc/rc.d/rc$runlevel.d/S??}
[ -f /var/lock/subsys/$subsys ] || \
[ -f /var/lock/subsys/${subsys}.init ] && continue
# Bring the subsystem up.
$i start
done
fi
Wednesday, June 3, 2009
validate ip
#include
#include
#include
#include
int validate_ip (char *a_ipAddr)
{
char *ipByte;
char localIpAddr[20];
int iCounter = 0;
printf("ip address is %s\n",a_ipAddr);
strcpy(localIpAddr,a_ipAddr);
ipByte = strtok (localIpAddr,":");
printf("ip address is %s\n",ipByte);
while (ipByte != NULL)
{
iCounter++;
if(!((atoi(ipByte)>0)&&(atoi(ipByte)<255)))
{
return 0;
}
ipByte = strtok (NULL, ":");
}
if(iCounter!=6)
{
printf("iCounter = %d\n",iCounter);
return 0;
}
else
return 1;
}
main(int argc,char *argv[])
{
if(validate_ip(argv[1]) == 0)
printf("perfect\n");
else
printf("NAAAAAAAAA...\n");
}
~
#include
#include
#include
int validate_ip (char *a_ipAddr)
{
char *ipByte;
char localIpAddr[20];
int iCounter = 0;
printf("ip address is %s\n",a_ipAddr);
strcpy(localIpAddr,a_ipAddr);
ipByte = strtok (localIpAddr,":");
printf("ip address is %s\n",ipByte);
while (ipByte != NULL)
{
iCounter++;
if(!((atoi(ipByte)>0)&&(atoi(ipByte)<255)))
{
return 0;
}
ipByte = strtok (NULL, ":");
}
if(iCounter!=6)
{
printf("iCounter = %d\n",iCounter);
return 0;
}
else
return 1;
}
main(int argc,char *argv[])
{
if(validate_ip(argv[1]) == 0)
printf("perfect\n");
else
printf("NAAAAAAAAA...\n");
}
~
Subscribe to:
Posts (Atom)
