Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ cmake_install.cmake

# binaries
forker
client

# diff
*.orig
Expand Down
4 changes: 3 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ set(CMAKE_CXX_FLAGS_RELEASE "${warning_flags} \

set(target forker)

add_executable(${target} forker.c)
add_executable(${target} forker.cc mmaper.c child.c ChildSignalHandler.cc ParentSignalHandler.cc Parent.cc InotifyHandler.cc EchoServerHandler.cc)

add_executable(client client.c)

target_link_libraries(${target}
pthread
Expand Down
39 changes: 39 additions & 0 deletions ChildSignalHandler.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#include "ChildSignalHandler.hh"
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <sys/signalfd.h>
#include <stdlib.h>
#include "common.h"
#include "child.h"

void ChildSignalHandler::handle_exit()
{
write_child_exit_info();
exit(EXIT_SUCCESS);
}

void ChildSignalHandler::handle()
{
struct signalfd_siginfo fdsi;
ssize_t sz;

sz = read(fd, &fdsi, sizeof(struct signalfd_siginfo));
if (sz != sizeof(struct signalfd_siginfo))
handle_error("read child signal handler");

if (fdsi.ssi_signo == SIGINT) {
fprintf(stderr, "%d: Got SIGINT from %d\n", getpid(), fdsi.ssi_pid);
handle_exit();
} else if (fdsi.ssi_signo == SIGQUIT) {
fprintf(stderr, "%d: Got SIGQUIT from %d\n", getpid(), fdsi.ssi_pid);
handle_exit();
} else if (fdsi.ssi_signo == SIGTERM) {
fprintf(stderr, "%d: Got SIGTERM from %d\n", getpid(), fdsi.ssi_pid);
handle_exit();
} else {
fprintf(stderr, "%d: Read unexpected signal from %d\n", getpid(), fdsi.ssi_pid);
}
}

17 changes: 17 additions & 0 deletions ChildSignalHandler.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#pragma once

#include "Handler.hh"

class ChildSignalHandler: public Handler
{
public:
ChildSignalHandler(int fd)
: Handler(fd)
{}

virtual void handle();

protected:
void handle_exit();
};

114 changes: 114 additions & 0 deletions EchoServerHandler.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
#include "EchoServerHandler.hh"
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <arpa/inet.h>
#include "common.h"

#define PORT "3490" // the port users will be connecting to

#define BACKLOG 10 // how many pending connections queue will hold

// get sockaddr, IPv4 or IPv6:
static void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}

return &(((struct sockaddr_in6*)sa)->sin6_addr);
}

EchoServerHandler::EchoServerHandler()
: Handler(-1), accept_fd(-1)
{
}

int EchoServerHandler::init()
{
int sockfd; // listen on sock_fd
struct addrinfo hints, *servinfo, *p;
int yes = 1;
int rv;

memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; // use my IP

if ((rv = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
exit(1);
}

// loop through all the results and bind to the first we can
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
handle_error("socket");
continue;
}

if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
sizeof(int)) == -1) {
handle_error("setsockopt reuse addr");
}

if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &yes,
sizeof(int)) == -1) {
handle_error("setsockopt reuse port");
}

if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
handle_error("server: bind");
continue;
}

break;
}

freeaddrinfo(servinfo); // all done with this structure

if (p == NULL) {
handle_error("server: failed to bind");
}

if (listen(sockfd, BACKLOG) == -1) {
handle_error("listen");
}

printf("server: waiting for connections... (pid: %u)\n", getpid());

accept_fd = sockfd;

return accept_fd;
}

void EchoServerHandler::handle()
{
int new_fd; // new connection on new_fd
struct sockaddr_storage their_addr; // connector's address information
socklen_t sin_size;
char s[INET6_ADDRSTRLEN];

sin_size = sizeof their_addr;
new_fd = accept(accept_fd, (struct sockaddr *)&their_addr, &sin_size);
if (new_fd == -1) {
handle_error("accept");
}

inet_ntop(their_addr.ss_family,
get_in_addr((struct sockaddr *)&their_addr),
s, sizeof s);
printf("server: got connection from %s (pid: %u)\n", s, getpid());

if (send(new_fd, "Hello, world!", 13, 0) == -1)
perror("send");
close(new_fd);
}

17 changes: 17 additions & 0 deletions EchoServerHandler.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#pragma once

#include "Handler.hh"

class EchoServerHandler: public Handler
{
public:
EchoServerHandler();

int init();

virtual void handle();

protected:
int accept_fd;
};

15 changes: 15 additions & 0 deletions Handler.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#pragma once

class Handler
{
public:
Handler(int fd)
: fd(fd)
{}

virtual void handle() = 0;

protected:
int fd;
};

124 changes: 124 additions & 0 deletions InotifyHandler.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
#include "InotifyHandler.hh"
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/inotify.h>
#include <time.h>
#include <fcntl.h>

#include "common.h"

InotifyHandler::InotifyHandler(Parent* parent)
: Handler(-1), inotify_fd(-1), path(NULL), parent(parent), watched_dir_fd(-1), watched_dir(NULL)
{
}

int InotifyHandler::init(const char* path)
{
inotify_fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
if (inotify_fd == -1)
handle_error("inotify_init1");

watch_descriptor = inotify_add_watch(inotify_fd, path, IN_CREATE | IN_ISDIR);
if (watch_descriptor == -1)
handle_error("inotify_add_watch");

watched_dir = opendir(path);
if (watched_dir == NULL)
handle_error("opendir");

watched_dir_fd = dirfd(watched_dir);
if (watched_dir_fd < 0)
handle_error("open watched dir");

this->path = path;

return inotify_fd;
}

void InotifyHandler::handle()
{
/* Some systems cannot read integer variables if they are not
properly aligned. On other systems, incorrect alignment may
decrease performance. Hence, the buffer used for reading from
the inotify file descriptor should have the same alignment as
struct inotify_event. */

char buf[8192]
__attribute__ ((aligned(__alignof__(struct inotify_event))));
const struct inotify_event *event;
ssize_t len;
char *ptr;

/* Loop while events can be read from inotify file descriptor. */

for (;;) {

/* Read some events. */

len = read(inotify_fd, buf, sizeof buf);
if (len == -1 && errno != EAGAIN) {
handle_error("inotify read");
}

/* If the nonblocking read() found no events to read, then
it returns -1 with errno set to EAGAIN. In that case,
we exit the loop. */

if (len <= 0)
break;

/* Loop over all events in the buffer */

for (ptr = buf; ptr < buf + len;
ptr += sizeof(struct inotify_event) + event->len) {

event = (const struct inotify_event *) ptr;

/* Print event type */

if (event->mask & IN_OPEN)
printf("IN_OPEN: ");
if (event->mask & IN_CLOSE_NOWRITE)
printf("IN_CLOSE_NOWRITE: ");
if (event->mask & IN_CLOSE_WRITE)
printf("IN_CLOSE_WRITE: ");

/* Print the name of the watched directory */
printf("%s/", path);

/* Print the name of the file */

if (event->len)
printf("%s", event->name);


/* Print type of filesystem object */

if (event->mask & IN_ISDIR)
printf(" [directory]\n");
else
printf(" [file]\n");

{
pid_t pid = 0;
int idx = 0;
int n_vals = sscanf(event->name, "child_%d_%d", &pid, &idx);
fprintf(stderr, "file: %s, n_vals:%d, pid: %d, idx:%d\n", event->name, n_vals, pid, idx);
if (n_vals == 2 && pid != 0 && idx != 0) {
time_t t = time(NULL);
struct tm *tm = localtime(&t);
printf("Child idx %d pid %d is dying: %s", idx, pid, asctime(tm));

unlinkat(watched_dir_fd, event->name, 0);

parent->clear_child(pid);
if (!parent->is_exiting()) {
parent->respawn(idx);
}
}
}
}
}
}

25 changes: 25 additions & 0 deletions InotifyHandler.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#pragma once

#include "Handler.hh"
#include "Parent.hh"

#include <dirent.h>

class InotifyHandler: public Handler
{
public:
InotifyHandler(Parent* parent);

int init(const char* path);

virtual void handle();

protected:
int inotify_fd;
int watch_descriptor;
const char* path;
Parent* parent;
int watched_dir_fd;
DIR* watched_dir;
};

Loading