Here is some sample code for a daemon process that writes "hello" every 2 seconds. Most daemons don't write anything to the console, but this one does for purposes of demonstration.
// Copyright (c) 2001 David Muse
// See the file COPYING for more information
#include <rudiments/daemonprocess.h>
#include <rudiments/permissions.h>
#include <rudiments/process.h>
#include <rudiments/file.h>
#include <rudiments/snooze.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#ifdef RUDIMENTS_NAMESPACE
using namespace rudiments;
#endif
daemonprocess *dmn;
// define a function to shut down the process cleanly
RETSIGTYPE shutDown() {
printf("%d: shutting down\n",process::getProcessId());
// clean up
delete dmn;
file::remove("/tmp/dmn.pidfile");
exit(0);
}
int main(int argc, const char **argv) {
dmn=new daemonprocess();
// set up signal handlers for clean shutdown
dmn->handleShutDown((RETSIGTYPE *)shutDown);
dmn->handleCrash((RETSIGTYPE *)shutDown);
// change the user/group that the daemon is running as
dmn->runAsUser("nobody");
dmn->runAsGroup("nobody");
// make sure that only one instance is running
int pid=dmn->checkForPidFile("/tmp/dmn.pidfile");
if (pid>-1) {
printf("Sorry, an instance of this daemon is already running with process id: %d\n",pid);
delete dmn;
exit(0);
}
// detach from the controlling terminal
dmn->detach();
// create a pid file which is used to make sure that only one instance
// is running and can also be used to kill the process
dmn->createPidFile("/tmp/dmn.pidfile",permissions::ownerReadWrite());
if (!fork()) {
for (;;) {
printf("%d: child looping...\n",
process::getProcessId());
snooze::macrosnooze(1);
}
}
// loop, printing "looping..." once per second
for (;;) {
printf("%d: parent looping...\n",
process::getProcessId());
snooze::macrosnooze(1);
}
}
Using the file Class...
// Copyright (c) 2003 David Muse
// See the file COPYING for more information
#include <rudiments/groupentry.h>
#include <rudiments/passwdentry.h>
#include <rudiments/file.h>
#include <rudiments/permissions.h>
#include <rudiments/datetime.h>
#include <stdio.h>
#ifdef RUDIMENTS_NAMESPACE
using namespace rudiments;
#endif
int main(int argc, const char **argv) {
// remove the file (in case it already exists)
file::remove("testfile");
// create a new file called "testfile" with rw-rw---- permissions
// and initial contents "hello"
file fl;
fl.create("testfile",permissions::evalPermString("rw-rw----"),"hello");
printf("testfile:\n");
// check for existence
if (file::exists("testfile")) {
printf(" exists\n");
} else {
printf(" does not exist\n");
}
// display the permissions of the file
mode_t mode=fl.getPermissions();
printf(" permissions: %s\n",permissions::evalPermOctal(mode));
// display the name of the user that owns the file
uid_t uid=fl.getOwnerUserId();
char *username;
passwdentry::getName(uid,&username);
printf(" user : %s\n",username);
delete[] username;
// display the name of the group that owns the file
gid_t gid=fl.getOwnerGroupId();
char *groupname;
groupentry::getName(gid,&groupname);
printf(" group : %s\n",groupname);
delete[] groupname;
// display the size of the file in bytes
off64_t size=fl.getSize();
printf(" size : %ld\n",size);
// display the size of the file in blocks
blkcnt_t blocks=fl.getBlockCount();
printf(" blocks : %ld\n",blocks);
// display the file type
printf(" is a socket: %d\n",fl.isSocket());
printf(" is a symlink: %d\n",fl.isSymbolicLink());
printf(" is a regular file: %d\n",fl.isRegularFile());
printf(" is a block device: %d\n",fl.isBlockDevice());
printf(" is a directory: %d\n",fl.isDirectory());
printf(" is a character device: %d\n",fl.isCharacterDevice());
printf(" is a fifo: %d\n",fl.isFifo());
// display the last time the file was accessed
time_t atime=fl.getLastAccessTime();
char *atimestr=datetime::getString(atime);
printf(" last access : %s\n",atimestr);
delete[] atimestr;
// display the last time the file was modified
time_t mtime=fl.getLastModificationTime();
char *mtimestr=datetime::getString(mtime);
printf(" last modification: %s\n",mtimestr);
delete[] mtimestr;
// display the last time the file was changed
time_t ctime=fl.getLastChangeTime();
char *ctimestr=datetime::getString(ctime);
printf(" last change : %s\n",ctimestr);
delete[] ctimestr;
// display the device that the file resides on
dev_t dev=fl.getDevice();
printf(" device : %d\n",dev);
// display the type of the device that the file resides on
dev_t devtype=fl.getDeviceType();
printf(" device type : %d\n",devtype);
// display the file's first inode
ino_t inode=fl.getInode();
printf(" inode : %d\n",inode);
// display the number of hard links to the file
nlink_t nlink=fl.getNumberOfHardLinks();
printf(" hard links : %ld\n",nlink);
char *path="/usr/local/firstworks/include/rudiments/file.h";
char *dirname=file::dirname(path);
printf("dirname(%s)=%s\n",path,dirname);
delete[] dirname;
char *basename=file::basename(path);
printf("basename(%s)=%s\n",path,basename);
delete[] basename;
basename=file::basename(path,".h");
printf("basename(%s,\".h\")=%s\n",path,basename);
delete[] basename;
printf("key=%d\n",file::generateKey("/",1));
printf("maxLinks(%s)=%d\n",path,file::maxLinks(path));
printf("canChangeOwner(%s)=%d\n",path,file::canChangeOwner(path));
}
Using the device Class...
// Copyright (c) 2003 David Muse
// See the file COPYING for more information
#include <stdio.h>
#ifdef RUDIMENTS_NAMESPACE
using namespace rudiments;
#endif
int main(int argc, const char **argv) {
// FIXME: implement this...
}
Using the serialport Class...
// Copyright (c) 2003 David Muse
// See the file COPYING for more information
#include <stdio.h>
#ifdef RUDIMENTS_NAMESPACE
using namespace rudiments;
#endif
int main(int argc, const char **argv) {
// FIXME: implement this...
}
Using the shmfile Class...
// Copyright (c) 2003 David Muse
// See the file COPYING for more information
#include <stdio.h>
#ifdef RUDIMENTS_NAMESPACE
using namespace rudiments;
#endif
int main(int argc, const char **argv) {
// FIXME: implement this...
}
Using the Server ClassesDaemons are commonly used to serve data to clients on the same machine or over a network. Below is an example combining the daemon and listener classes. This server listens on unix and inet sockets for a client connection, receives a string from the client and writes the same string back to the client.
// Copyright (c) 2001 David Muse
// See the file COPYING for more information
#include <rudiments/daemonprocess.h>
#include <rudiments/permissions.h>
#include <rudiments/inetserversocket.h>
#include <rudiments/file.h>
#include <stdio.h>
#ifdef RUDIMENTS_NAMESPACE
using namespace rudiments;
#endif
class myserver : public daemonprocess, public inetserversocket {
public:
myserver() : daemonprocess(), inetserversocket() {}
void listen();
};
void myserver::listen() {
// make sure that only one instance is running
int pid=checkForPidFile("/tmp/svr.pidfile");
if (pid>-1) {
printf("Sorry, an instance of this server is already running with process id: %d\n",pid);
return;
}
// detach from the controlling terminal
//detach();
// create a pid file which is used to make sure that only one instance
// is running and can also be used to kill the process
createPidFile("/tmp/svr.pidfile",permissions::ownerReadWrite());
// listen on inet socket port 8000
if (!inetserversocket::listen(NULL,8000,15)) {
printf("couldn't listen on port 8000\n");
}
// loop...
for (;;) {
// accept a client connection
filedescriptor *clientsock=accept();
// read 5 bytes from the client and display it
char buffer[6];
buffer[5]=(char)NULL;
clientsock->read((char *)buffer,5);
printf("%s\n",buffer);
// write "hello" back to the client
clientsock->write("hello",5);
// close the socket and clean up
clientsock->close();
delete clientsock;
}
}
myserver *mysvr;
// define a function to shut down the process cleanly
RETSIGTYPE shutDown() {
printf("shutting down\n");
mysvr->close();
delete mysvr;
file::remove("/tmp/svr.pidfile");
exit(0);
}
int main(int argc, const char **argv) {
mysvr=new myserver();
// set up signal handlers for clean shutdown
mysvr->handleShutDown((RETSIGTYPE *)shutDown);
mysvr->handleCrash((RETSIGTYPE *)shutDown);
mysvr->listen();
}
Notice that this server listens on both inet and unix ports. Inet ports allow clients and servers to talk across a network. Unix ports allow clients and servers on the same machine to talk through a pipe. Though clients and servers on the same machine could talk over inet ports, unix ports are much faster and use fewer system resources.
Using the Client ClassesHere's the code for a client that can talk to the server above. This client sends a string to the server, reads what the server sends back and prints it out. It does this once over an inet port and once over a unix port.
// Copyright (c) 2001 David Muse
// See the file COPYING for more information
#include <rudiments/inetclientsocket.h>
#include <rudiments/error.h>
#include <stdio.h>
#ifdef RUDIMENTS_NAMESPACE
using namespace rudiments;
#endif
int main(int argc, const char **argv) {
// create an inet socket client
inetclientsocket clnt;
// connect to a server on localhost, listening on port 8000
if (clnt.connect("localhost",8000,-1,-1,1,1)<0) {
printf("connect failed: %s\n",error::getErrorString());
exit(1);
}
// write "hello" to the server
clnt.write("hello",5);
// read 10 bytes from the server and display them
char buffer[11];
int sizeread=clnt.read(buffer,10);
buffer[sizeread]=(char)NULL;
printf("%s\n",buffer);
// close the connection to the server
clnt.close();
}
// Copyright (c) 2001 David Muse
// See the file COPYING for more information
#include <rudiments/unixclientsocket.h>
#include <rudiments/error.h>
#ifdef RUDIMENTS_NAMESPACE
using namespace rudiments;
#endif
int main(int argc, const char **argv) {
// create a unix socket client
unixclientsocket clnt;
// connect to a server listening on /tmp/lsnr.socket
if (clnt.connect("/tmp/lsnr.socket",-1,-1,1,1)<0) {
printf("connect failed: %s\n",error::getErrorString());
exit(0);
}
// write "hello" to the server
clnt.write("hello",5);
// read 10 bytes from the server and display them
char buffer[11];
int sizeread=clnt.read(buffer,10);
buffer[sizeread]=(char)NULL;
printf("%s\n",buffer);
// close the connection to the server
clnt.close();
}
Using the Complex Initialization methods of the
Server ClassesSetting up a server to listen on a socket is actually a multi-step process. The listen() methods simplify this process but some applications may require a more flexible interface. If you need to set socket options or perform additional actions between the steps of socket initialization, you can use the Complex Inititalization methods of the server classes.
Below is an alternative implementation of the myserver constructor in which some socket options are set.
myserver::myserver() : daemonprocess(), listener() {
// run as a different user/group
runAsUser("nobody");
runAsGroup("nobody");
// detach from the controlling tty
detach();
// initialize the ports
inetsocket.initialize(NULL,8040);
unixsocket.initialize("/tmp/mysocket",S_IRUSR|S_IWUSR);
// set some socket options
inetsocket.lingerOnClose(10);
inetsocket.reuseAddresses();
unixsocket.lingerOnClose(10);
// bind to the ports
inetsocket.bind();
unixsocket.bind();
// listen on the ports
inetsocket.listen(15);
unixsocket.listen(15);
// add sockets to the pool
addFileDescriptor(&inetsocket);
addFileDescriptor(&unixsocket);
}
Using the listener Class...
// Copyright (c) 2001 David Muse
// See the file COPYING for more information
#include <rudiments/listener.h>
#include <rudiments/inetserversocket.h>
#include <rudiments/unixserversocket.h>
#include <rudiments/permissions.h>
#include <stdio.h>
#ifdef RUDIMENTS_NAMESPACE
using namespace rudiments;
#endif
int main(int argc, const char **argv) {
// listen on inet socket port 1800
inetserversocket inetsock;
if (!inetsock.listen(NULL,8000,15)) {
printf("couldn't listen on inet socket\n");
}
// listen on unix socket "/tmp/lsnr.socket"
unixserversocket unixsock;
if (!unixsock.listen("/tmp/lsnr.socket",0000,15)) {
printf("couldn't listen on unix socket\n");
}
// create a listener and add the 2 sockets to it
listener pool;
pool.addFileDescriptor(&inetsock);
pool.addFileDescriptor(&unixsock);
// loop...
for (;;) {
// wait for a client to connect to one of the sockets
pool.waitForNonBlockingRead(-1,-1);
filedescriptor *fd=NULL;
pool.getReadyList()->getDataByIndex(0,&fd);
// figure out which socket the client connected to
filedescriptor *clientsock;
if (fd==&inetsock) {
clientsock=inetsock.accept();
printf("inetsock: ");
} else if (fd==&unixsock) {
clientsock=unixsock.accept();
printf("unixsock: ");
} else {
printf("error or timeout waiting...\n");
continue;
}
// read 5 bytes from the client and display it
char buffer[6];
buffer[5]=(char)NULL;
clientsock->read(buffer,5);
printf("%s\n",buffer);
// write "hello" back to the client
clientsock->write("hello",5);
// close the socket and clean up
clientsock->close();
delete clientsock;
}
}