P09 lab code added

This commit is contained in:
Andreas Gieriet
2020-04-26 15:02:50 +02:00
parent 94945069e3
commit f4c374887c
45 changed files with 2116 additions and 0 deletions
@@ -0,0 +1,178 @@
/******************************************************************************
* File: Daemonizer.c
* Original Autor: M. Thaler (Modul BSY)
* Aufgabe: Einen Daemon-Prozess erzeugen
******************************************************************************/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
//*****************************************************************************
// Macro to write out all the PIDs...
#define OutPutPIDs() /*printf("\nPID %d, PPID %d, GRP-ID %d\n", \
getpid(), getppid(), getpgrp())*/
//*****************************************************************************
// Function: Locks file with file descriptor fd
// Returns: 0 on success, -1 of file is already locked
// Exits: on fatal errors
//*****************************************************************************
int lock(int fd) {
int retval, len;
struct flock lock; // data structure for file lock
char buffer[16];
// prepare lockfile
lock.l_type = F_WRLCK;
lock.l_start = 0;
lock.l_whence = SEEK_SET;
lock.l_len = 0;
retval = fcntl(fd, F_SETLK, &lock); // set file lock
if (retval < 0) {
if ((errno == EACCES) || (errno == EAGAIN)) {
return(-1); // Daemon already runs
}
else {
perror("fatal error when locking file");
exit(-1);
}
}
// empty the lockfile
retval = ftruncate(fd, 0);
if (retval < 0) {
perror("fatal error when emptying lockfile");
exit(-1);
}
// write process ID to lockfile
sprintf(buffer, "%d\n", getpid());
len = strlen(buffer);
retval = write(fd, buffer, len) < len;
if (retval < 0) {
perror("fatal error when writing pid to lockfile");
exit(-1);
}
// set lockfile to close on exec
retval = fcntl(fd, F_GETFD, 0);
if (retval < 0) {
perror("fatal error when reading lockfile flags");
exit(-1);
}
retval = retval | FD_CLOEXEC;
retval = fcntl(fd, F_SETFD, retval);
if (retval < 0) {
perror("fatal error when setting lockfile flags");
exit(-1);
}
return(0);
}
//*****************************************************************************
// Function: Makes a deamon process and runs a daemon function
// Parameter: Daemon function
// data pointer to data to be passed to Daemonfunction
// LogFile, path of logfile, if NULL, no logfile is created
// LivDir, path, where daemon will live
// Returns: should not return
// Exits: if daemon is already runnung or on fatal errors
//*****************************************************************************
int Daemonizer(void Daemon(void *), void *data,
const char *LockFile, const char *LogFile, const char *LivDir) {
pid_t PID;
int fd, dummyfd, retval;
// create a prozess and terminate parents -> parent is init
OutPutPIDs();
PID = fork();
if (PID < 0) {
perror("could not fork()");
exit(-1);
}
else if (PID > 0) {
exit(0); // I have done my work an can exit
}
// ----------------------------------------------------------------------
// now I am a process detached from the parent
// an make the process -> a daemon process
signal(SIGINT, SIG_IGN); // ignore CTRL-C
signal(SIGQUIT, SIG_IGN); // ignore quit
signal(SIGHUP, SIG_IGN); // ignore hangup of terminal
OutPutPIDs();
setsid(); // make process session leader
// and processgroup leader
// no control terminal with pocess
OutPutPIDs();
chdir(LivDir); // change to secure directory
umask(0); // allow all access rights for files
// set up lockfile, if required
if (LockFile != NULL) {
fd = open(LockFile, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR |
S_IRGRP | S_IROTH);
if (fd < 0) {
perror("fatal error when opening lockfile");
exit(-1);
}
retval = lock(fd);
if (retval < 0) {
printf("\n*** daemon is already running ***\n");
exit(0);
}
}
// last message from daemon
printf("\n*** daemon starts with process id: %d ***\n",getpid());
// close "communication" to outer world and set up logging, if required
close(1); // close stdout
close(2); // close stderr
if (LogFile != NULL) { // open log file on stdout
enum {UserWrite=0644};
dummyfd = open(LogFile, O_CREAT | O_APPEND | O_WRONLY,UserWrite);
if (dummyfd < 0) {
perror("could not open log file");
exit(-1);
}
dup(1); // connect stderr to logfile
}
close(0); // now close stdin
// now start the daemon funktion
Daemon(data);
// should not come here
return(0);
}
//*****************************************************************************
@@ -0,0 +1,15 @@
/*********************************************************************
* File: Daemonizer.h
* Original Autor: M. Thaler (Modul BSY)
* Aufgabe: einen Daemon-Prozess erzeugen
*********************************************************************/
#ifndef DAEMONIZER_H
#define DAEMONIZER_H
int Daemonizer(void Daemon(void *), void *data,
const char *LockFile, const char *LogFile, const char *LivDir);
#endif
//------------------------------------------------------------------------
@@ -0,0 +1,188 @@
//*****************************************************************************
// ipCom.c IP Socket Functions
// Original Author: M. Thaler, M. Pellaton (Modul BSY)
//*****************************************************************************
//*****************************************************************************
// system includes
//*****************************************************************************
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netdb.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <net/if.h>
//*****************************************************************************
// local definitions
//*****************************************************************************
#include "IPsockCom.h"
//*****************************************************************************
// Function: send data buffer to host "host" with port "port"
// Parameter: hostname or IP address in dot format
// port number
// buffer
// size of buffer
// Returns: number of characters read on success, -1 if connection failed
// buffer: time data
//
//*****************************************************************************
int getTimeFromServer(char *host, int port, char *buffer, int bufferLen) {
int sfd, sysRet, timeOut, retval;
char stringPort[8];
struct addrinfo hints, *aiList, *aiPtr = NULL;
if (strcmp(host, "") == 0) {
printf("Need hostname or IP address\n");
return(-1);
}
sprintf(stringPort, "%d", port);
memset(&hints, '\0', sizeof(hints));
//hints.ai_flags = AI_CANONNAME;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
sysRet = getaddrinfo(host, stringPort, &hints, &aiList);
if (sysRet != 0) {
printf("error getting network address for %s (%s)\n",
host, gai_strerror(sysRet));
exit(-1);
}
aiPtr = aiList; // search through list
while (aiPtr != 0) {
sfd = socket(aiPtr->ai_family, aiPtr->ai_socktype, aiPtr->ai_protocol);
if (sfd >= 0) {
timeOut = 100;
sysRet = 1;
while ((timeOut != 0) && (sysRet != 0)) {
sysRet = connect(sfd, aiPtr->ai_addr, aiPtr->ai_addrlen);
usleep(1000);
timeOut--;
}
if (sysRet == 0)
break; // connect successful
else
close(sfd);
}
aiPtr = aiPtr->ai_next;
}
freeaddrinfo(aiList);
if (aiPtr == NULL) {
printf("could not connect to %s\n", host);
retval = -1;
}
else
retval = 0;
if (retval == 0) {
if (write(sfd, buffer, bufferLen) < 0) {
printf("error sending request to timer serveer\n");
retval = -1;
}
else
retval = read(sfd, buffer, COM_BUF_SIZE);
}
close(sfd);
return(retval);
}
//*****************************************************************************
// Function: starts "time" socket server
// Parameter: port number to listen to
// Returns: socket file descriptor if ok, -1 if error
// Exits:
//*****************************************************************************
int StartTimeServer(int portNumber) {
int sfd, sysRet, j;
char stringPort[8];
struct addrinfo hints, *aiList, *aiPtr = NULL;
sprintf(stringPort, "%d", portNumber); // portnumber to string
memset(&hints, '\0', sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = 0;
hints.ai_flags = AI_PASSIVE;
sysRet = getaddrinfo(NULL, stringPort, &hints, &aiList);
if (sysRet != 0) {
printf("error getting network address (%s)\n", gai_strerror(sysRet));
exit(-1);
}
aiPtr = aiList; // search through list
while (aiPtr != 0) {
sfd = socket(aiPtr->ai_family, aiPtr->ai_socktype, aiPtr->ai_protocol);
if (sfd >= 0) {
j = 1;
sysRet = setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &j, sizeof(j));
if (sysRet < 0)
perror("cannot set socket options");
if (bind(sfd, aiPtr->ai_addr, aiPtr->ai_addrlen) < 0) {
perror("bind failed ");
close(sfd);
exit(-1);
}
if (listen(sfd, 5) < 0) {
close(sfd);
perror("listen failed ");
exit(-1);
}
else
break;
}
aiPtr = aiPtr->ai_next;
}
freeaddrinfo(aiList);
if (aiPtr == NULL) {
printf("could not set up a socket server\n");
exit(-1);
}
return(sfd);
}
//*****************************************************************************
// Function: Reads data from client
// Parameter: socket file descriptor
// buffer to place data
// Returns: current socket descriptor on success, < 0 on failure
// Exits: none
//*****************************************************************************
int WaitForClient(int sfd, char *buffer) {
int cfd, retval, addrlen;
struct sockaddr_in addr;
addrlen = sizeof(struct sockaddr_in);
cfd = accept(sfd,(struct sockaddr *)&addr,(socklen_t *)&addrlen);
if (cfd >= 0) {
retval = read(cfd, buffer, COM_BUF_SIZE);
retval = cfd;
}
else
retval = cfd;
return(retval);
}
//*****************************************************************************
@@ -0,0 +1,20 @@
//*****************************************************************************
// ipCom.c IP Socket Functions
// Original Autor: M. Thaler, M. Pellaton (Modul BSY)
//*****************************************************************************
#ifndef IP_COM_SOCKETS
#define IP_COM_SOCKETS
#define COM_BUF_SIZE 512
#define PIDperror()\
fprintf(stderr,"fatal error, daemon with PID %d: ",getpid());
int getTimeFromServer(char *host, int port, char *buffer, int bufferLen);
int StartTimeServer(int PortNumber);
int WaitForClient(int sfd, char *buffer);
#endif
//***************************************************************************
@@ -0,0 +1,44 @@
/*********************************************************************
* File: MrTimeDaemon.c
* Original Autor: M. Thaler (Modul BSY)
* Aufgabe: einen Daemon-Prozess erzeugen
*********************************************************************/
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include "Daemonizer.h"
#include "TimeDaemon.h"
#define STRING_LENGTH 128
//--------------------------------------------------------------------
int main(void) {
pid_t pid;
int status;
const char *lockfilePath = "/tmp/timeDaemon.lock";
//const char *lockfilePath = NULL;
const char *logfilePath = "/tmp/timeDaemon.log";
const char *livingPath = "/tmp";
const char *myName = "I am Mr. Time Daemon on \n";
if ((pid = fork()) == 0)
Daemonizer(TimeDaemon, (void *)myName,
lockfilePath, logfilePath, livingPath);
else {
assert(pid > 0);
wait(&status); // wait for Daemonizer to exit
// after having forked the "Daemon"
if (WEXITSTATUS(status) != 0)
printf("*** Daemonizer failed ***\n");
}
}
//--------------------------------------------------------------------
@@ -0,0 +1,21 @@
/*********************************************************************
* File: PlapperMaul.c
* Original Autor: M. Thaler (Modul BSY)
* Aufgabe: plappern
*********************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
//--------------------------------------------------------------------
int main(void) {
while (1) {
printf("Hallo, ich bins.... Pidi %d\n", getpid());
usleep(500000);
}
}
//--------------------------------------------------------------------
@@ -0,0 +1,75 @@
/******************************************************************************
* File: TimeDaemon.c
* Original Autor: M. Thaler (Modul BSY)
* Aufgabe: the daemon code
******************************************************************************/
//*****************************************************************************
// system includes
//*****************************************************************************
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/un.h>
#include <netdb.h>
#include <time.h>
//*****************************************************************************
// local includes
//*****************************************************************************
#include "TimeDaemon.h"
#include "TimeDaemonDefs.h"
#include "IPsockCom.h"
//*****************************************************************************
// Function: TimeDeamon
// Parameter: data: expects here pointer to string
//*****************************************************************************
void TimeDaemon(void *data) {
TimeData tData;
char buffer[COM_BUF_SIZE];
struct tm MyTime;
time_t ActualTime;
int sfd, cfd;
printf("%s\n", (char *)data);
// start server
sfd = StartTimeServer(TIME_PORT);
if (sfd < 0) {
perror("could not start socket server");
exit(-1);
}
while (1) {
cfd = WaitForClient(sfd, buffer);
if ((strcmp(buffer, REQUEST_STRING) == 0) && (cfd >= 0)) {
time(&ActualTime);
MyTime = *localtime(&ActualTime);
tData.hours = MyTime.tm_hour;
tData.minutes = MyTime.tm_min;
tData.seconds = MyTime.tm_sec;
tData.day = MyTime.tm_mday;
tData.month = MyTime.tm_mon + 1;
tData.year = MyTime.tm_year + 1900;
gethostname(tData.servername, HOST_NAM_LEN);
write(cfd, (char *)(&tData), sizeof(tData));
}
}
// if we should somehow come here (how ?)
close(sfd);
exit(0);
}
//*****************************************************************************
@@ -0,0 +1,14 @@
/******************************************************************************
* File: TimeDaemon.h
* Original Autor: M. Thaler (Modul BSY)
* Aufgabe: function prototype of time daemon
******************************************************************************/
#ifndef TIME_DAEMON
#define TIME_DAEMON
void TimeDaemon(void *);
#endif
//*****************************************************************************
@@ -0,0 +1,30 @@
/******************************************************************************
* File: TimeDaemonDefs.h
* Original Autor: M. Thaler (Modul BSY)
* Aufgabe: Data Definitions for TimeDaemon
******************************************************************************/
#ifndef TIME_DAEMON_DEFS
#define TIME_DAEMON_DEFS
#define HOST_NAM_LEN 32
#define TIME_PORT 65534
#define REQUEST_STRING "requestTimeFromServer"
// data structure receiving from time daemon
typedef struct {
int hours;
int minutes;
int seconds;
int day;
int month;
int year;
char servername[HOST_NAM_LEN];
} TimeData, *TimeDataPtr;
#endif
//*****************************************************************************
@@ -0,0 +1,66 @@
/******************************************************************************
* File: WhatsTheTimeMr.c
* Original Autor: M. Thaler (Modul BSY)
* Aufgabe: Ask MrTimeDaemon for the time
******************************************************************************/
//*****************************************************************************
// system includes
//*****************************************************************************
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/un.h>
#include <netdb.h>
#include <arpa/inet.h> // required by inet_aton
//*****************************************************************************
// local includes
//*****************************************************************************
#include "TimeDaemon.h"
#include "TimeDaemonDefs.h"
#include "IPsockCom.h"
//*****************************************************************************
// Function: main()
// Parameter: hostname or IP address in dot format
//*****************************************************************************
int main(int argc, char *argv[]) {
char buffer[COM_BUF_SIZE];
char hostname[64];
TimeDataPtr tDataPtr;
int j;
if (argc < 2) {
printf("*** no hostname or IP-address -> using localhost ***\n");
strcpy(hostname, "localhost");
} else {
strcpy(hostname, argv[1]);
}
strcpy(buffer,REQUEST_STRING);
j = getTimeFromServer(hostname, TIME_PORT, buffer, sizeof(buffer));
if (j < 0)
printf("no response from %s\n", argv[1]);
else {
tDataPtr = (TimeDataPtr)(buffer);
printf("\nIt's ");
printf("%02d:%02d:%02d",
tDataPtr->hours, tDataPtr->minutes,tDataPtr->seconds);
printf(" the %d.%d.%d on \"%s\"\n\n",
tDataPtr->day, tDataPtr->month,
tDataPtr->year, tDataPtr->servername);
}
exit(0);
}
//*****************************************************************************
@@ -0,0 +1,35 @@
# *************************************************************
# Original Autor: M. Thaler (Modul BSY)
# *************************************************************
CMP= gcc
CMPFLAGS= -Wall -g -std=gnu99
EXENAMES= MrTimeDaemon.e
EXENAMEC= WhatsTheTimeMr.e
EXENAMEP= PlapperMaul.e
LIBNAME=
compile: $(EXENAMES) $(EXENAMEC) $(EXENAMEP)
$(EXENAMES): MrTimeDaemon.o IPsockCom.o Daemonizer.o TimeDaemon.o
$(CMP) $(CMPFLAGS) MrTimeDaemon.o IPsockCom.o Daemonizer.o TimeDaemon.o $(LIBNAME) -o $(EXENAMES)
$(EXENAMEC): WhatsTheTimeMr.o IPsockCom.o
$(CMP) $(CMPFLAGS) WhatsTheTimeMr.o IPsockCom.o $(LIBNAME) -o $(EXENAMEC)
$(EXENAMEP): PlapperMaul.o
$(CMP) $(CMPFLAGS) PlapperMaul.o $(LIBNAME) -o $(EXENAMEP)
.c.o:
$(CMP) -c $(CMPFLAGS) $<
.cc.o:
$(CMP) -c $(CMPFLAGS) $<
clean:
rm -f $(EXENAMEC) $(EXENAMES) $(EXENAMEP)
rm -f *.o
all:
@make clean
@make