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 Classes
Setting 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; } }