The unified diff between revisions [c49ffbac..] and [f14eeb09..] is displayed below. It can also be downloaded as a raw diff.

#
#
# patch "CMakeLists.txt"
#  from [18636ea3906b9ed2f5f5a743e4f56de17dd5527c]
#    to [78742225b5b8ab63006a5fba774babcc9621f217]
#
# patch "fritz.cc"
#  from [233ddad13ebbc258c71edd11ef663d61fb8e1f4a]
#    to [2d49a74e4937692d814a6a833af55df52f1af0f9]
#
# patch "fritz.hh"
#  from [8e3312ac5309aafc33e25d03671eea7ed1db4a5c]
#    to [0a09a9981868e04ed9e93bab0af8a66c79f87559]
#
============================================================
--- CMakeLists.txt	18636ea3906b9ed2f5f5a743e4f56de17dd5527c
+++ CMakeLists.txt	78742225b5b8ab63006a5fba774babcc9621f217
@@ -1,4 +1,10 @@

 project (fritz.it)

+add_executable (fritz_server fritz.cc fritz_server.cc)
+target_link_libraries (fritz_server rt dl)
+
+add_library (fritz_client SHARED fritz_client.cc fritz.cc)
+target_link_libraries (fritz_client rt dl)
+
+add_executable (fritz_this fritz_this.cc)
-add_executable (fritz.it fritz.cc)
============================================================
--- fritz.cc	233ddad13ebbc258c71edd11ef663d61fb8e1f4a
+++ fritz.cc	2d49a74e4937692d814a6a833af55df52f1af0f9
@@ -7,134 +7,282 @@
  * All rights reserved.
  */

-#include <sys/errno.h>
-#include <sys/types.h>
-#include <sys/mman.h>
-#include <semaphore.h>
-#include <fcntl.h>
-#include <unistd.h>
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <iostream>
 #include <exception>
+#include <dlfcn.h>

+/* some general design notes:
+ * data is exchanged via a shared memory page
+ * a pair of semaphores are used to hand control of the page between
+ * the client and the server; a normal sequence is
+ *
+ *    client            server
+ ******************************************
+ *                      [ create semaphores, shared memory ]
+ *                      sem_wait (client)
+ *    sem_post (client)
+ *    sem_wait (server)
+ *                      sem_post (server)
+ *    [ copy data into shm ]
+ */
+
+
 #include "fritz.hh"

-class fritz_exception: public std::exception
+/*** Fritzer ***/
+
+Fritzer::Fritzer (void)
 {
-private:
-    const char *err;
-
-public:
-    fritz_exception (const char *e)
-    {
-        err = e;
+    client_sem = server_sem = NULL;
+    initialise_from_environ ();
+}
+
+void
+Fritzer::initialise_from_environ (void)
+{
+    my_pid = getpid ();
+    shm_name = getenv ("FRITZ_SHM");
+    client_sem_name = getenv ("FRITZ_CLIENT_SEM");
+    server_sem_name = getenv ("FRITZ_SERVER_SEM");
+    if (!shm_name || !server_sem_name || !client_sem_name ) {
+        throw fritz_exception ("FRITZ_SHM, FRITZ_CLIENT)SEM and FRITZ_SERVER_SEM must be set.");
     }
-    virtual const char* what() const throw()
-    {
-        char *s_err;
-
-        s_err = strerror (errno);
-        std::cout << "from errno: " << s_err << std::endl;
-        return err;
+}
+
+void
+Fritzer::map_the_shm (void)
+{
+    shm_mem = mmap ((void *)NULL, shm_size, PROT_READ|PROT_WRITE, MAP_SHARED, shm_fd, (off_t)0);
+    if (shm_mem <= 0) {
+        throw fritz_exception("Unable to map shared memory.");
     }
-};
+    fritz_params = (struct fritz_params *)shm_mem;
+}

-class FritzServer {
-private:
-    static const int shm_size=(1024*16);
-    const char *shm_name;
-    int shm_fd;
-    void *shm_mem;
-    struct fritz_params *fritz_params;
-    pid_t my_pid;
+void
+Fritzer::update_params (void)
+{
+    fritz_params->buffer_size = shm_size;
+    fritz_params->pid = my_pid;
+}
+
+sem_t *
+Fritzer::open_semaphore (const char *name)
+{
+    sem_t *rv;

-    const char *sem_name;
-    sem_t *sem;
+    rv = sem_open (name, 0);
+    if ((rv == SEM_FAILED) || (!rv)) {
+        throw fritz_exception ("Unable top open semaphore.");
+    }
+    return rv;
+}

-    void wait_for_request ();
+sem_t *
+Fritzer::create_semaphore (const char *name)
+{
+    sem_t *rv;
+
+    /* a bit brutal */
+    sem_unlink (name);
+    rv = sem_open (name, O_CREAT|O_EXCL, 0600, 0);
+    if ((rv == SEM_FAILED) || (!rv)) {
+        throw fritz_exception ("Unable to create semaphore.");
+    }
+    return rv;
+}

-public:
-    FritzServer (const char *, const char *);
-    ~FritzServer (void);
-    void run (void);
-};
+void
+Fritzer::close_semaphores (void)
+{
+    sem_close (client_sem);
+    sem_close (server_sem);
+    client_sem = server_sem = NULL;
+}

-FritzServer::FritzServer (const char *a_shm_name, const char *a_sem_name)
+size_t
+Fritzer::get_message_id (void)
 {
-    std::cout << "Fritz starting up." << std::endl;
-
-    my_pid = getpid ();
-    shm_name = a_shm_name;
-    /* the fruncate will fail if we're not creating the file from scratch */
+    return fritz_params->message_id;
+}
+
+/*** FritzServer ***/
+
+void
+FritzServer::create_shared_memory (void)
+{
     shm_fd = 0;
-    for (int i=0;i<2;i++) {
-        shm_fd = shm_open (shm_name, O_RDWR|O_CREAT|O_EXCL, 0600);
-        if (shm_fd < 0) {
-            std::cout << "Unlinking old shared memory segment." << std::endl;
-            shm_unlink (shm_name);
-        } else {
-            break;
-        }
-    }
+    /* a bit brutal */
+    shm_unlink (shm_name);
+    shm_fd = shm_open (shm_name, O_RDWR|O_CREAT|O_EXCL, 0600);
     if (shm_fd < 0) {
         throw fritz_exception ("Unable to open shared memory segment.");
     }
     if (ftruncate (shm_fd, shm_size) == -1) {
         throw fritz_exception ("Unable to truncate shared memory segment.");
     }
-    shm_mem = mmap ((void *)NULL, shm_size, PROT_READ|PROT_WRITE, MAP_SHARED, shm_fd, (off_t)0);
-    if (shm_mem <= 0) {
-        throw fritz_exception("Unable to map shared memory.");
+}
+
+void
+FritzServer::wait_for_client (void)
+{
+    if (sem_wait (client_sem) == -1) {
+        throw fritz_exception ("Error waiting on semaphore for control.");
     }
-    fritz_params = (struct fritz_params *)shm_mem;
-    memset (fritz_params, 0, sizeof (struct fritz_params));
-    sem_name = a_sem_name;
-    sem = sem_open (sem_name, O_CREAT, 0600, 0);
-    if ((int)sem == SEM_FAILED) {
-        throw fritz_exception ("Unable to open semaphore.");
-    }
 }

+void
+FritzServer::create_semaphores (void)
+{
+    server_sem = create_semaphore (server_sem_name);
+    client_sem = create_semaphore (client_sem_name);
+}
+
+FritzServer::FritzServer (void)
+{
+    mode = "server";
+    create_semaphores ();
+    create_shared_memory ();
+    map_the_shm ();
+    fritz_params->message_id = 0;
+}
+
 FritzServer::~FritzServer (void)
 {
-    std::cout << "Fritz is terminating." << std::endl;
     shm_unlink (shm_name);
-    sem_close (sem);
-    sem_unlink (sem_name);
+    close_semaphores ();
+    sem_unlink (client_sem_name);
+    sem_unlink (server_sem_name);
 }

 void
-FritzServer::wait_for_request (void)
+FritzServer::signal_client (void)
 {
-    fritz_params->buffer_size = shm_size;
-    fritz_params->pid = my_pid;
-    fritz_params->message_id++;
-    std::cout << "Waiting to acquire semaphore." << std::endl;
-    if (sem_wait (sem) == -1) {
-        throw fritz_exception ("Error waiting on semaphore.");
+   if (sem_post (server_sem) == -1) {
+       throw fritz_exception ("Unable to sem_post");
+   }
+}
+
+void
+FritzServer::rewrite (void)
+{
+    for (size_t i=0;i<fritz_params->contents_size;i++) {
+        ((char *)&(fritz_params->contents))[i]++;
     }
+//    std::cerr << "rewrote " << fritz_params->contents_size << " bytes." << std::endl;
 }

 void
 FritzServer::run (void)
 {
     for (;;) {
-        wait_for_request ();
+	wait_for_client ();
+        update_params ();
+        fritz_params->message_id++;
+        rewrite ();
+        signal_client ();
     }
 }

-int
-main (int argc, char *argv[])
+/*** FritzClient ***/
+
+void
+FritzClient::open_semaphores ()
 {
-    if (argc == 3) {
-        FritzServer f (argv[1], argv[2]);
-        f.run ();
-        return 0;
-    } else {
-        std::cerr << "usage: " << argv[0] << " <shm_name> <sem_name>" << std::endl;
-        return -1;
+    server_sem = open_semaphore (server_sem_name);
+    client_sem = open_semaphore (client_sem_name);
+}
+
+void
+FritzClient::open_shared_memory (void)
+{
+    shm_fd = shm_open (shm_name, O_RDWR, 0600);
+    if (shm_fd < 0) {
+        throw fritz_exception ("Unable to open shared memory segment.");
     }
 }
+
+void
+FritzClient::wait_for_server (void)
+{
+    if (sem_wait (server_sem) == -1) {
+        throw fritz_exception ("Error waiting on semaphore for control.");
+    }
+}
+
+void
+FritzClient::signal_server (void)
+{
+   if (sem_post (client_sem) == -1) {
+       throw fritz_exception ("Unable to sem_post");
+   }
+}
+
+FritzClient::FritzClient (void)
+{
+    mode = "client";
+    open_semaphores ();
+    open_shared_memory ();
+    map_the_shm ();
+}
+
+FritzClient::~FritzClient (void)
+{
+    close_semaphores ();
+}
+
+void
+FritzClient::pass_to_server (void)
+{
+    signal_server ();
+    wait_for_server ();
+}
+
+void *
+FritzClient::grab_symbol_from (const char *lib_env, const char *sym)
+{
+    void *dl, *rv;
+    char *dl_file, *error;
+
+    dl_file = getenv (lib_env);
+    if (!dl_file) {
+        throw fritz_exception ("Can't fritz library, as environment variable is not present.");
+    }
+    dl = dlopen (dl_file, RTLD_LAZY);
+    dlerror ();
+    rv = dlsym (dl, sym);
+    if ((error = dlerror()) != NULL) {
+        std::cerr << "error loading symbol: " << error << std::endl;
+        throw fritz_exception ("Error grabbing symbol.");
+    }
+    std::cerr << "got the symbol \"" << sym << "\" from \"" << dl_file << "\" at " << rv << std::endl;
+    dlclose (dl);
+    return rv;
+}
+
+void
+FritzClient::copy_data (size_t nbytes, void *from)
+{
+    update_params ();
+    int mbytes = fritz_params->buffer_size - \
+    			((char *)fritz_params - (char *)&(fritz_params->contents));
+    if (nbytes > mbytes) {
+        throw fritz_exception ("buffer overrun; can't copy this many bytes!");
+    }
+    fritz_params->contents_size = nbytes;
+    memcpy (&(fritz_params->contents), from, nbytes);
+}
+
+size_t
+FritzClient::copy_back (size_t maxbytes, void *buf)
+{
+    if (fritz_params->contents_size > maxbytes)  {
+        throw fritz_exception ("buffer overrun; can't copy this many bytes back!");
+    }
+    memcpy (buf, &(fritz_params->contents), fritz_params->contents_size);
+    return fritz_params->contents_size;
+}
+
============================================================
--- fritz.hh	8e3312ac5309aafc33e25d03671eea7ed1db4a5c
+++ fritz.hh	0a09a9981868e04ed9e93bab0af8a66c79f87559
@@ -5,6 +5,13 @@
  * common data structures
  */

+#include <sys/errno.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <semaphore.h>
+#include <fcntl.h>
+#include <unistd.h>
+
 enum fritz_message {
   FRITZ_MESG_SYSCALL_OPEN,
   FRITZ_MESG_SYSCALL_READ,
@@ -12,12 +19,91 @@ enum fritz_message {
   FRITZ_MESG_SYSCALL_CLOSE
 };

+class fritz_exception: public std::exception
+{
+private:
+    const char *err;
+
+public:
+    fritz_exception (const char *e)
+    {
+        err = e;
+    }
+    virtual const char* what() const throw()
+    {
+        char *s_err;
+
+        s_err = strerror (errno);
+        std::cout << "from errno: " << s_err << std::endl;
+        return err;
+    }
+};
+
 struct fritz_params {
-    size_t              buffer_size;      /* size of the shared memory segment, including this struct */
+    size_t              buffer_size;      /* total size of the shared memory segment */
     pid_t               pid;              /* process ID sending this message */
     size_t              message_id;       /* monotonically increasing message ID */
-    enum fritz_message  message_type;     /* type of message */
-    void                *contents;        /* contents (descripted by message_type) */
+    int                 fd;               /* file descriptor from which data was gathered */
+    size_t              contents_size;    /* size of contents */
+    void                *contents;        /* contents */
 };

+class Fritzer {
+protected:
+    const char *mode; /* used in debugging messages, eg. "client" or "server" */
+    static const int shm_size=(1024*16);
+    pid_t my_pid;
+
+    /* semaphores */
+    const char *server_sem_name, *client_sem_name;
+    sem_t *server_sem, *client_sem;
+    /* shared memory */
+    const char *shm_name;
+    int shm_fd;
+    void *shm_mem;
+    struct fritz_params *fritz_params;
+
+    void initialise_from_environ (void);
+    sem_t *open_semaphore (const char *);
+    sem_t *create_semaphore (const char *);
+    void close_semaphores (void);
+    void map_the_shm (void);
+    void update_params (void);
+public:
+    Fritzer (void);
+    size_t get_message_id (void);
+};
+
+class FritzServer : public Fritzer {
+private:
+    void wait_for_request (void);
+    void create_semaphores ();
+    void create_shared_memory (void);
+    void wait_for_client (void);
+    void signal_client (void);
+    void rewrite (void);
+
+public:
+    FritzServer (void);
+    ~FritzServer (void);
+    void run (void);
+};
+
+class FritzClient : public Fritzer {
+private:
+    void open_semaphores (void);
+    void open_shared_memory (void);
+    void wait_for_server (void);
+    void signal_server (void);
+    void sync (void);
+public:
+    FritzClient (void);
+    ~FritzClient (void);
+    const char *Hello(void);
+    void pass_to_server (void);
+    void *grab_symbol_from (const char *, const char *);
+    void copy_data (size_t, void *);
+    size_t copy_back (size_t, void *);
+};
+
 #endif