aboutsummaryrefslogtreecommitdiff
path: root/dpid
diff options
context:
space:
mode:
authorjcid <devnull@localhost>2007-10-07 00:36:34 +0200
committerjcid <devnull@localhost>2007-10-07 00:36:34 +0200
commit93715c46a99c96d6c866968312691ec9ab0f6a03 (patch)
tree573f19ec6aa740844f53a7c0eb7114f04096bf64 /dpid
Initial revision
Diffstat (limited to 'dpid')
-rw-r--r--dpid/Makefile.am26
-rw-r--r--dpid/TODO32
-rw-r--r--dpid/dpi.c97
-rw-r--r--dpid/dpi.h54
-rw-r--r--dpid/dpi_service.c114
-rw-r--r--dpid/dpi_service.h20
-rw-r--r--dpid/dpi_socket_dir.c128
-rw-r--r--dpid/dpi_socket_dir.h17
-rw-r--r--dpid/dpid.c734
-rw-r--r--dpid/dpid.h103
-rw-r--r--dpid/dpid_common.c43
-rw-r--r--dpid/dpid_common.h61
-rw-r--r--dpid/dpidc31
-rw-r--r--dpid/main.c398
-rw-r--r--dpid/misc_new.c172
-rw-r--r--dpid/misc_new.h12
16 files changed, 2042 insertions, 0 deletions
diff --git a/dpid/Makefile.am b/dpid/Makefile.am
new file mode 100644
index 00000000..cd15afd4
--- /dev/null
+++ b/dpid/Makefile.am
@@ -0,0 +1,26 @@
+AM_CPPFLAGS=-DDPIDRC_SYS='"$(sysconfdir)/dpidrc"'
+
+bin_PROGRAMS = dpid
+dpid_LDADD = ../dpip/libDpip.a ../dlib/libDlib.a
+
+EXTRA_DIST = dpidc
+bin_SCRIPTS = dpidc
+
+dpid_SOURCES = \
+ dpi.h \
+ dpi_service.h \
+ dpi_socket_dir.h \
+ dpid.h \
+ dpid_common.h \
+ misc_new.h \
+ dpi.c \
+ dpi_service.c \
+ dpi_socket_dir.c \
+ dpid.c \
+ dpid_common.c \
+ main.c \
+ misc_new.c
+
+install-data-local :
+ $(mkinstalldirs) $(DESTDIR)$(sysconfdir)
+ echo dpi_dir=$(libdir)/dillo/dpi > $(DESTDIR)$(sysconfdir)/dpidrc
diff --git a/dpid/TODO b/dpid/TODO
new file mode 100644
index 00000000..c9967535
--- /dev/null
+++ b/dpid/TODO
@@ -0,0 +1,32 @@
+Todo List
+
+ File dpi_service.c
+ This module should be removed because its original functions
+ have been removed or modified. Put these functions in dpid.c
+
+ File dpi_service.h
+ This module should be removed because its original functions
+ have been removed or modified. Put these functions in dpid.c
+
+ Add other file types, but first we need to add files associated
+ with a dpi to the design.
+
+ Global SRS_NAME
+ Should read this from dillorc
+
+ File dpid_common.h
+ The dpid error codes will be used in the next patch
+
+ Global main()
+ + add new plugins when they become available
+ __________________________________________________________
+
+Remove global variables.
+
+Use a singly linked list for dpi_attr_list
+
+Allow dpis to be registered one at a time
+
+Only run dpis listed in users dillorc
+
+MAYBE Have dpid accept all connections to dpis (fixes inf loop if dpi crashes before accept)
diff --git a/dpid/dpi.c b/dpid/dpi.c
new file mode 100644
index 00000000..45e5b49d
--- /dev/null
+++ b/dpid/dpi.c
@@ -0,0 +1,97 @@
+/*
+ Copyright (C) 2003 Ferdi Franceschini <ferdif@optusnet.com.au>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*! \file
+ * Access functions for ~/.dillo/dpi_socket_dir.
+ * The most useful function for dillo is a_Dpi_srs, it returns
+ * the full path to the dpid service request socket.
+ */
+
+#include <errno.h>
+#include "dpid_common.h"
+#include "dpi.h"
+#include "misc_new.h"
+
+/*! \Return
+ * Returns path to the dpi_socket_dir file
+ * Use dFree to free memory
+ */
+char *a_Dpi_sockdir_file(void)
+{
+ char *dpi_socket_dir, *dirfile_path = "/.dillo/dpi_socket_dir";
+
+ dpi_socket_dir = dStrconcat(dGethomedir(), dirfile_path, NULL);
+ return dpi_socket_dir;
+}
+
+/*! Read socket directory path from ~/.dillo/dpi_socket_dir
+ * \Return
+ * socket directory path or NULL if the dpi_socket_dir file does not exist.
+ * \Note
+ * This function exits if ~/.dillo does not exist or
+ * if the dpi_socket_dir file cannot be opened for a
+ * reason other than it does not exist.
+ */
+
+char *a_Dpi_rd_dpi_socket_dir(char *dirname)
+{
+ FILE *dir;
+ char *sockdir = NULL, *rcpath;
+
+ rcpath = dStrconcat(dGethomedir(), "/.dillo", NULL);
+
+ /* If .dillo does not exist it is an unrecoverable error */
+ if (access(rcpath, F_OK) == -1) {
+ ERRMSG("a_Dpi_rd_dpi_socket_dir", "access", errno);
+ MSG_ERR(" - %s\n", rcpath);
+ exit(1);
+ }
+ dFree(rcpath);
+
+ if ((dir = fopen(dirname, "r")) != NULL) {
+ sockdir = dGetline(dir);
+ fclose(dir);
+ } else if (errno == ENOENT) {
+ ERRMSG("a_Dpi_rd_dpi_socket_dir", "fopen", errno);
+ MSG_ERR(" - %s\n", dirname);
+ } else if (errno != ENOENT) {
+ ERRMSG("a_Dpi_rd_dpi_socket_dir", "fopen", errno);
+ MSG_ERR(" - %s\n", dirname);
+ exit(1);
+ }
+
+ return sockdir;
+}
+
+/*!
+ * \Modifies
+ * srs_name
+ * \Return
+ * The service request socket name with its complete path.
+ */
+char *a_Dpi_srs(void)
+{
+ char *dirfile_path, *sockdir, *srs_name;
+
+ dirfile_path = a_Dpi_sockdir_file();
+ sockdir = dStrstrip(a_Dpi_rd_dpi_socket_dir(dirfile_path));
+ srs_name = dStrconcat(sockdir, "/", "dpid.srs", NULL);
+ dFree(sockdir);
+ dFree(dirfile_path);
+ return (srs_name);
+}
diff --git a/dpid/dpi.h b/dpid/dpi.h
new file mode 100644
index 00000000..d97fdc6d
--- /dev/null
+++ b/dpid/dpi.h
@@ -0,0 +1,54 @@
+/*! \file
+ * Access functions for ~/.dillo/dpi_socket_dir.
+ * The most useful function for dillo is a_Dpi_srs, it returns
+ * the full path to the dpid service request socket.
+ */
+
+#ifndef DPI_H
+#define DPI_H
+
+#include <config.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Check the Unix98 goodie */
+#ifndef socklen_t
+ #define socklen_t uint32_t
+#endif
+
+/* Some systems may not have this one... */
+#ifndef AF_LOCAL
+ #define AF_LOCAL AF_UNIX
+#endif
+
+/* This one is tricky, some sources state it should include the byte
+ * for the terminating NULL, and others say it shouldn't.
+ * The other way is to only use this one when a native SUN_LEN is not present,
+ * but as dillo has used this for a long time successfully, here it goes.
+ */
+# define D_SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) \
+ + strlen ((ptr)->sun_path))
+
+/*!
+ * dpi commands
+ */
+enum {
+ UNKNOWN_CMD,
+ BYE_CMD, /* "DpiBye" */
+ CHECK_SERVER_CMD, /* "check_server" */
+ REGISTER_ALL_CMD, /* "register_all" */
+ REGISTER_SERVICE_CMD /* "register_service" */
+};
+
+
+char *a_Dpi_sockdir_file(void);
+
+char *a_Dpi_rd_dpi_socket_dir(char *dirname);
+
+char *a_Dpi_srs(void);
+
+#endif
diff --git a/dpid/dpi_service.c b/dpid/dpi_service.c
new file mode 100644
index 00000000..07cdad8e
--- /dev/null
+++ b/dpid/dpi_service.c
@@ -0,0 +1,114 @@
+/*
+ Copyright (C) 2003 Ferdi Franceschini <ferdif@optusnet.com.au>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*! \file
+ * \todo
+ * This module should be removed because its original functions
+ * have been removed or modified.
+ * Put these functions in dpid.c
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include "dpid_common.h"
+#include "dpid.h"
+#include "../dpip/dpip.h"
+
+#ifdef TEST
+#include "testdat.h"
+#endif
+
+/* exported functions */
+char *get_dpi_dir(char *dpidrc);
+
+
+/*! Get dpi directory path from dpidrc
+ * \Return
+ * dpi directory on success, NULL on failure
+ * \Important
+ * The dpi_dir definition in dpidrc must have no leading white space.
+ */
+char *get_dpi_dir(char *dpidrc)
+{
+ FILE *In;
+ int len;
+ char *rcline = NULL, *value = NULL, *p;
+
+ if ((In = fopen(dpidrc, "r")) == NULL) {
+ ERRMSG("dpi_dir", "fopen", errno);
+ MSG_ERR(" - %s\n", dpidrc);
+ return (NULL);
+ }
+
+ while ((rcline = dGetline(In)) != NULL) {
+ if (strncmp(rcline, "dpi_dir", 7) == 0)
+ break;
+ dFree(rcline);
+ }
+ fclose(In);
+
+ if (!rcline) {
+ ERRMSG("dpi_dir", "Failed to find a dpi_dir entry in dpidrc", 0);
+ MSG_ERR("Put your dillo plugins path in %s\n", dpidrc);
+ MSG_ERR("eg. dpi_dir=/usr/local/lib/dillo/dpi ");
+ MSG_ERR("with no leading spaces.\n");
+ value = NULL;
+ } else {
+ len = (int) strlen(rcline);
+ if (len && rcline[len - 1] == '\n')
+ rcline[len - 1] = 0;
+
+ if ((p = strchr(rcline, '='))) {
+ while (*++p == ' ');
+ value = dStrdup(p);
+ } else {
+ ERRMSG("dpi_dir", "strchr", 0);
+ MSG_ERR(" - '=' not found in %s\n", rcline);
+ value = NULL;
+ }
+ }
+
+ dFree(rcline);
+ return (value);
+}
+
+/*! Send the list of available dpi IDs to a client
+ * \Return
+ * 1 on success, -1 on failure.
+ *
+static int send_service_list(int sock, struct dp *dpi_attr_list, int srv_num)
+{
+ int i;
+ char *buf;
+ ssize_t wlen = 0;
+
+ for (i = 0; i < srv_num && wlen != -1; i++) {
+ d_cmd = a_Dpip_build_cmd("cmd=%s msg=%s",
+ "send_data", dpi_attr_list[i].id);
+ wlen = write(sock, d_cmd, strlen(d_cmd));
+ dFree(d_cmd);
+ }
+ if (wlen == -1) {
+ ERRMSG("send_service_list", "write", errno);
+ return (-1);
+ }
+ return (1);
+}
+ */
diff --git a/dpid/dpi_service.h b/dpid/dpi_service.h
new file mode 100644
index 00000000..af7679b3
--- /dev/null
+++ b/dpid/dpi_service.h
@@ -0,0 +1,20 @@
+/*! \file
+ * \todo
+ * This module should be removed because its original functions
+ * have been removed or modified.
+ * Put these functions in dpid.c
+ */
+
+#ifndef DPI_SERVICE_H
+#define DPI_SERVICE_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "dpid.h"
+
+char *get_dpi_dir(char *dpidrc);
+
+int send_service_list(int sock, struct dp *dpi_attr_list, int srv_num);
+
+#endif
diff --git a/dpid/dpi_socket_dir.c b/dpid/dpi_socket_dir.c
new file mode 100644
index 00000000..c18faf0d
--- /dev/null
+++ b/dpid/dpi_socket_dir.c
@@ -0,0 +1,128 @@
+/*
+ Copyright (C) 2003 Ferdi Franceschini <ferdif@optusnet.com.au>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*! \file
+ * Create a per user temporary directory for dpi sockets
+ */
+
+#include <errno.h>
+#include "dpid_common.h"
+#include "dpi.h"
+#include "misc_new.h"
+#include "dpi_socket_dir.h" /* for function prototypes */
+
+/*! Save socket directory name in ~/.dillo/dpi_socket_dir
+ * \Return
+ * \li 1 on success
+ * \li -1 on failure
+ */
+int w_dpi_socket_dir(char *dirname, char *sockdir)
+{
+ FILE *dir;
+
+ if ((dir = fopen(dirname, "w")) == NULL) {
+ ERRMSG("w_dpi_socket_dir", "fopen", errno);
+ return (-1);
+ }
+ fprintf(dir, "%s", sockdir);
+ fclose(dir);
+ return (1);
+}
+
+/*! Test that socket directory exists and is a directory
+ * \Return
+ * \li 1 on success
+ * \li 0 on failure
+ * \bug Does not check permissions or that it's a symbolic link
+ * to another directory.
+ */
+int tst_dir(char *dir)
+{
+ char *dirtest;
+ int ret = 0;
+
+ /* test for a directory */
+ dirtest = dStrconcat(dir, "/", NULL);
+ if (access(dirtest, F_OK) == -1) {
+ ERRMSG("tst_dir", "access", errno);
+ MSG_ERR(" - %s\n", dirtest);
+ } else {
+ ret = 1;
+ }
+ dFree(dirtest);
+
+ return ret;
+}
+
+/*! Create socket directory
+ * \Return
+ * \li Socket directory path on success
+ * \li NULL on failure
+ */
+char *mk_sockdir(void)
+{
+ char *template;
+
+ template = dStrconcat("/tmp/", getlogin(), "-", "XXXXXX", NULL);
+ if (a_Misc_mkdtemp(template) == NULL) {
+ ERRMSG("mk_sockdir", "a_Misc_mkdtemp", 0);
+ MSG_ERR(" - %s\n", template);
+ dFree(template);
+ return (NULL);
+ }
+ return template;
+}
+
+/*! Create socket directory if it does not exist and save its name in
+ * ~/.dillo/dpi_socket_dir.
+ * \Return
+ * \li Socket directory name on success
+ * \li NULL on failure.
+ */
+char *init_sockdir(char *dpi_socket_dir)
+{
+ char *sockdir = NULL;
+ int dir_ok = 0;
+
+ if ((sockdir = a_Dpi_rd_dpi_socket_dir(dpi_socket_dir)) == NULL) {
+ MSG_ERR("init_sockdir: The dpi_socket_dir file %s does not exist\n",
+ sockdir);
+ } else {
+ if ((dir_ok = tst_dir(sockdir)) == 1) {
+ MSG_ERR("init_sockdir: The socket directory %s exists and is OK\n",
+ sockdir);
+ } else {
+ MSG_ERR("init_sockdir: The socket directory %s does not exist "
+ "or is not a directory\n", sockdir);
+ dFree(sockdir);
+ }
+ }
+ if (!dir_ok) {
+ sockdir = mk_sockdir();
+ if (sockdir == NULL) {
+ ERRMSG("init_sockdir", "mk_sockdir", 0);
+ MSG_ERR(" - Failed to create dpi socket directory\n");
+ } else if ((w_dpi_socket_dir(dpi_socket_dir, sockdir)) == -1) {
+ ERRMSG("init_sockdir", "w_dpi_socket_dir", 0);
+ MSG_ERR(" - failed to save %s\n", sockdir);
+ dFree(sockdir);
+ sockdir = NULL;
+ }
+ }
+ return (sockdir);
+}
diff --git a/dpid/dpi_socket_dir.h b/dpid/dpi_socket_dir.h
new file mode 100644
index 00000000..87719212
--- /dev/null
+++ b/dpid/dpi_socket_dir.h
@@ -0,0 +1,17 @@
+/*! \file
+ * Create a per user temporary directory for dpi sockets
+ */
+
+#ifndef DPI_SOCKET_DIR_H
+#define DPI_SOCKET_DIR_H
+
+
+int w_dpi_socket_dir(char *dirname, char *sockdir);
+
+int tst_dir(char *dir);
+
+char *mk_sockdir(void);
+
+char *init_sockdir(char *dpi_socket_dir);
+
+#endif
diff --git a/dpid/dpid.c b/dpid/dpid.c
new file mode 100644
index 00000000..9fe2e74d
--- /dev/null
+++ b/dpid/dpid.c
@@ -0,0 +1,734 @@
+/*
+ Copyright (C) 2003 Ferdi Franceschini <ferdif@optusnet.com.au>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*! \file
+ * Main functions to set-up dpi information and to initialise sockets
+ */
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include "dpid_common.h"
+#include "dpid.h"
+#include "dpi.h"
+#include "dpi_socket_dir.h"
+#include "dpi_service.h"
+#include "misc_new.h"
+
+#include "../dpip/dpip.h"
+
+#define QUEUE 5
+
+volatile sig_atomic_t caught_sigchld = 0;
+
+/*! Return the basename of a filename
+ */
+char *get_basename(char *filename)
+{
+ char *p;
+
+ if (filename && (p = strrchr(filename, '/'))) {
+ filename = p + 1;
+ }
+ return filename;
+}
+
+/*! Close and remove the sockets in the
+ * given dpi attribute list
+ */
+void rm_dpi_sockets(struct dp *dpi_attr_list, int numdpis)
+{
+ int i;
+
+ for (i = 0; i < numdpis; i++) {
+ a_Misc_close_fd(dpi_attr_list[i].socket);
+ (void) unlink(dpi_attr_list[i].sockpath);
+ }
+}
+
+/*! Close and remove inactive dpi sockets
+ * \Return
+ * Number of active dpis.
+ */
+int rm_inactive_dpi_sockets(struct dp *dpi_attr_list, int numdpis)
+{
+ int i, active = 0;
+
+ for (i = 0; i < numdpis; i++) {
+ if (dpi_attr_list[i].pid == 1) {
+ a_Misc_close_fd(dpi_attr_list[i].socket);
+ (void) unlink(dpi_attr_list[i].sockpath);
+ } else
+ active++;
+ }
+ return (active);
+}
+
+/*! Remove sockets
+ */
+void cleanup(char *socket_dir)
+{
+ DIR *dir;
+ struct dirent *dir_entry = NULL;
+ char *sockpath;
+
+ dir = opendir(socket_dir);
+ if (dir == NULL) {
+ ERRMSG("cleanup", "opendir", errno);
+ return;
+ }
+ while ( (dir_entry = readdir(dir)) != NULL ) {
+ if (dir_entry->d_name[0] == '.')
+ continue;
+ sockpath = dStrconcat(socket_dir, "/", dir_entry->d_name, NULL);
+ unlink(sockpath);
+ dFree(sockpath);
+ }
+ closedir(dir);
+}
+
+/*! Free memory used to describe
+ * a set of dpi attributes
+ */
+void free_dpi_attr(struct dp *dpi_attr)
+{
+ if (dpi_attr->id != NULL) {
+ dFree(dpi_attr->id);
+ dpi_attr->id = NULL;
+ }
+ if (dpi_attr->path != NULL) {
+ dFree(dpi_attr->path);
+ dpi_attr->path = NULL;
+ }
+ if (dpi_attr->sockpath != NULL) {
+ dFree(dpi_attr->sockpath);
+ dpi_attr->sockpath = NULL;
+ }
+}
+
+/*! Free memory used by the plugin list
+ */
+void free_plugin_list(struct dp **dpi_attr_list_ptr, int numdpis)
+{
+ int i;
+ struct dp *dpi_attr_list = *dpi_attr_list_ptr;
+
+ if (dpi_attr_list == NULL)
+ return;
+
+ for (i = 0; i < numdpis; i++)
+ free_dpi_attr(dpi_attr_list + i);
+
+ dFree(dpi_attr_list);
+ *dpi_attr_list_ptr = NULL;
+}
+
+/*! \todo
+ * Remove terminator and est_terminator unless we really want to clean up
+ * on abnormal exit.
+ */
+#if 0
+/*! Signal handler for SIGINT, SIGQUIT, and SIGTERM. Calls cleanup
+ */
+void terminator(int sig)
+{
+ (void) signal(SIGCHLD, SIG_DFL);
+ cleanup();
+ (void) signal(sig, SIG_DFL);
+ (void) raise(sig);
+ _exit(0);
+}
+
+/*! Establish handler for termination signals
+ * and register cleanup with atexit */
+void est_terminator(void)
+{
+ struct sigaction act;
+ sigset_t block;
+
+ (void) sigemptyset(&block);
+ (void) sigaddset(&block, SIGINT);
+ (void) sigaddset(&block, SIGQUIT);
+ (void) sigaddset(&block, SIGTERM);
+ (void) sigaddset(&block, SIGSEGV);
+
+ act.sa_handler = terminator;
+ act.sa_mask = block;
+ act.sa_flags = 0;
+
+ if (sigaction(SIGINT, &act, NULL) ||
+ sigaction(SIGQUIT, &act, NULL) ||
+ sigaction(SIGTERM, &act, NULL) || sigaction(SIGSEGV, &act, NULL)) {
+ ERRMSG("est_terminator", "sigaction", errno);
+ exit(1);
+ }
+
+ if (atexit(cleanup) != 0) {
+ ERRMSG("est_terminator", "atexit", 0);
+ MSG_ERR("Hey! atexit failed, how did that happen?\n");
+ exit(1);
+ }
+}
+#endif
+
+/*! Identify a given file
+ * Currently there is only one file type associated with dpis.
+ * More file types will be added as needed
+ */
+enum file_type get_file_type(char *file_name)
+{
+ char *dot = strrchr(file_name, '.');
+
+ if (dot && !strcmp(dot, ".dpi"))
+ return DPI_FILE; /* Any filename ending in ".dpi" */
+ else {
+ MSG_ERR("get_file_type: Unknown file type for %s\n", file_name);
+ return UNKNOWN_FILE;
+ }
+}
+
+/*! Scans a service directory in dpi_dir and fills dpi_attr
+ * \Note
+ * Caller must allocate memory for dpi_attr.
+ * \Return
+ * \li 0 on success
+ * \li -1 on failure
+ * \todo
+ * Add other file types, but first we need to add files associated with a dpi
+ * to the design.
+ */
+int get_dpi_attr(char *dpi_dir, char *service, struct dp *dpi_attr)
+{
+ char *service_dir = NULL;
+ struct stat statinfo;
+ enum file_type ftype;
+ int retval = -1;
+ DIR *dir_stream;
+ struct dirent *dir_entry = NULL;
+
+ service_dir = dStrconcat(dpi_dir, "/", service, NULL);
+ if (stat(service_dir, &statinfo) == -1) {
+ ERRMSG("get_dpi_attr", "stat", errno);
+ MSG_ERR("file=%s\n", service_dir);
+ } else if ((dir_stream = opendir(service_dir)) == NULL) {
+ ERRMSG("get_dpi_attr", "opendir", errno);
+ } else {
+ /* Scan the directory loking for dpi files.
+ * (currently there's only the dpi program, but in the future
+ * there may also be helper scripts.) */
+ while ( (dir_entry = readdir(dir_stream)) != NULL) {
+ if (dir_entry->d_name[0] == '.')
+ continue;
+
+ ftype = get_file_type(dir_entry->d_name);
+ switch (ftype) {
+ case DPI_FILE:
+ dpi_attr->path =
+ dStrconcat(service_dir, "/", dir_entry->d_name, NULL);
+ dpi_attr->id = dStrdup(service);
+ dpi_attr->sockpath = NULL;
+ dpi_attr->pid = 1;
+ if (strstr(dpi_attr->path, ".filter") != NULL)
+ dpi_attr->filter = 1;
+ else
+ dpi_attr->filter = 0;
+ retval = 0;
+ break;
+ default:
+ break;
+ }
+ }
+ closedir(dir_stream);
+
+ if (retval != 0)
+ MSG_ERR("get_dpi_attr: No dpi plug-in in %s/%s\n",
+ dpi_dir, service);
+ }
+ dFree(service_dir);
+ return retval;
+}
+
+/*! Register a service
+ * Retrieves attributes for "service" and stores them
+ * in dpi_attr. It looks for "service" in ~/.dillo/dpi
+ * first, and then in the system wide dpi directory.
+ * Caller must allocate memory for dpi_attr.
+ * \Return
+ * \li 0 on success
+ * \li -1 on failure
+ */
+int register_service(struct dp *dpi_attr, char *service)
+{
+ char *user_dpi_dir, *dpidrc, *user_service_dir, *dir = NULL;
+ int retval = -1;
+
+ user_dpi_dir = dStrconcat(dGethomedir(), "/", dotDILLO_DPI, NULL);
+ user_service_dir =
+ dStrconcat(dGethomedir(), "/", dotDILLO_DPI, "/", service, NULL);
+
+ dpidrc = dStrconcat(dGethomedir(), "/", dotDILLO_DPIDRC, NULL);
+ if (access(dpidrc, F_OK) == -1) {
+ if (access(DPIDRC_SYS, F_OK) == -1) {
+ ERRMSG("register_service", "Error ", 0);
+ MSG_ERR("\n - There is no %s or %s file\n", dpidrc,
+ DPIDRC_SYS);
+ dFree(user_dpi_dir);
+ dFree(user_service_dir);
+ dFree(dpidrc);
+ return(-1);
+ }
+ dFree(dpidrc);
+ dpidrc = dStrdup(DPIDRC_SYS);
+ }
+
+ /* Check home dir for dpis */
+ if (access(user_service_dir, F_OK) == 0) {
+ get_dpi_attr(user_dpi_dir, service, dpi_attr);
+ retval = 0;
+ } else { /* Check system wide dpis */
+ if ((dir = get_dpi_dir(dpidrc)) != NULL) {
+ if (access(dir, F_OK) == 0) {
+ get_dpi_attr(dir, service, dpi_attr);
+ retval = 0;
+ } else {
+ ERRMSG("register_service", "get_dpi_attr failed", 0);
+ }
+ } else {
+ ERRMSG("register_service", "dpi_dir: Error getting dpi dir.", 0);
+ }
+ }
+ dFree(user_dpi_dir);
+ dFree(user_service_dir);
+ dFree(dpidrc);
+ dFree(dir);
+ return (retval);
+}
+
+/*!
+ * Create dpi directory for available
+ * plugins and create plugin list.
+ * \Return
+ * \li Returns number of available plugins on success
+ * \li -1 on failure
+ */
+int register_all(struct dp **attlist)
+{
+ DIR *user_dir_stream, *sys_dir_stream;
+ char *user_dpidir = NULL, *sys_dpidir = NULL, *dpidrc = NULL;
+ char *basename=NULL;
+ struct dirent *user_dirent, *sys_dirent;
+ int j, st, not_in_user_list;
+ int snum, usr_srv_num;
+ size_t dp_sz = sizeof(struct dp);
+
+ if (*attlist != NULL) {
+ ERRMSG("register_all", "attlist parameter should be NULL", 0);
+ return -1;
+ }
+
+ user_dpidir = dStrconcat(dGethomedir(), "/", dotDILLO_DPI, NULL);
+ if (access(user_dpidir, F_OK) == -1) {
+ /* no dpis in user's space */
+ dFree(user_dpidir);
+ user_dpidir = NULL;
+ }
+ dpidrc = dStrconcat(dGethomedir(), "/", dotDILLO_DPIDRC, NULL);
+ if (access(dpidrc, F_OK) == -1) {
+ dFree(dpidrc);
+ dpidrc = dStrdup(DPIDRC_SYS);
+ if (access(dpidrc, F_OK) == -1) {
+ dFree(dpidrc);
+ dpidrc = NULL;
+ }
+ }
+ if (!dpidrc || (sys_dpidir = get_dpi_dir(dpidrc)) == NULL)
+ sys_dpidir = NULL;
+ dFree(dpidrc);
+
+ if (!user_dpidir && !sys_dpidir) {
+ ERRMSG("register_all", "Fatal error ", 0);
+ MSG_ERR("\n - Can't find the directory for dpis.\n");
+ exit(1);
+ }
+
+ /* Get list of services in user's .dillo/dpi directory */
+ snum = usr_srv_num = 0;
+ if (user_dpidir && (user_dir_stream = opendir(user_dpidir)) != NULL) {
+ while ((user_dirent = readdir(user_dir_stream)) != NULL) {
+ if (user_dirent->d_name[0] == '.')
+ continue;
+ *attlist = (struct dp *) dRealloc(*attlist, (snum + 1) * dp_sz);
+ st=get_dpi_attr(user_dpidir, user_dirent->d_name, &(*attlist)[snum]);
+ if (st == 0)
+ snum++;
+ }
+ usr_srv_num = snum;
+ closedir(user_dir_stream);
+ }
+ if (sys_dpidir && (sys_dir_stream = opendir(sys_dpidir)) != NULL) {
+ /* if system service is not in user list then add it */
+ while ((sys_dirent = readdir(sys_dir_stream)) != NULL) {
+ if (sys_dirent->d_name[0] == '.')
+ continue;
+ not_in_user_list = 1;
+ for (j = 0; j < usr_srv_num; j++) {
+ basename = get_basename((*attlist)[j].path);
+ if (strcmp(sys_dirent->d_name, basename) == 0) {
+ not_in_user_list = 0;
+ break;
+ }
+ }
+ if (not_in_user_list) {
+ *attlist = (struct dp *) dRealloc(*attlist, (snum + 1) * dp_sz);
+ st=get_dpi_attr(sys_dpidir, sys_dirent->d_name, &(*attlist)[snum]);
+ if (st == 0)
+ snum++;
+ }
+ }
+ closedir(sys_dir_stream);
+ }
+
+ dFree(sys_dpidir);
+ dFree(user_dpidir);
+
+ /* todo: do we consider snum == 0 an error?
+ * (if so, we should return -1 ) */
+ return (snum);
+}
+
+/*! Initialise the service request socket
+ * \Return:
+ * \li Number of sockets (1 == success)
+ * \li -1 on failure
+ */
+int init_srs_socket(char *sockdir)
+{
+ int retval = -1;
+ struct sockaddr_un srs_sa;
+ size_t sun_path_len;
+ socklen_t addr_sz;
+
+ srs_name = dStrconcat(sockdir, "/", SRS_NAME, NULL);
+ FD_ZERO(&sock_set);
+
+ /* Initialise srs, service request socket on startup */
+ if ((srs = socket(AF_LOCAL, SOCK_STREAM, 0)) == -1) {
+ ERRMSG("init_srs_socket", "socket", errno);
+ return (retval); /* avoids nesting ifs too deeply */
+ }
+ /* Set srs to close on exec */
+ fcntl(srs, F_SETFD, FD_CLOEXEC | fcntl(srs, F_GETFD));
+
+ srs_sa.sun_family = AF_LOCAL;
+
+ sun_path_len = sizeof(srs_sa.sun_path);
+ if (strlen(srs_name) > sun_path_len) {
+ ERRMSG("init_srs_socket", "srs_name is too long", 0);
+ MSG_ERR("\n - it should be <= %lu chars", (ulong_t)sun_path_len);
+ MSG_ERR("\n - srs_name = %s\n", srs_name);
+ return(retval);
+ }
+ strncpy(srs_sa.sun_path, srs_name, sun_path_len);
+ addr_sz = (socklen_t) D_SUN_LEN(&srs_sa);
+
+ if ((bind(srs, (struct sockaddr *) &srs_sa, addr_sz)) == -1) {
+ if (errno == EADDRINUSE) {
+ ERRMSG("init_srs_socket", "bind", errno);
+ MSG_ERR("srs_sa.sun_path = %s\n", srs_sa.sun_path);
+ dpi_errno = dpid_srs_addrinuse;
+ } else {
+ ERRMSG("init_srs_socket", "bind", errno);
+ MSG_ERR("srs_sa.sun_path = %s\n", srs_sa.sun_path);
+ }
+ } else if (chmod(srs_sa.sun_path, S_IRUSR | S_IWUSR) == -1) {
+ ERRMSG("init_srs_socket", "chmod", errno);
+ MSG_ERR("srs_sa.sun_path = %s\n", srs_sa.sun_path);
+ } else if (listen(srs, QUEUE) == -1) {
+ ERRMSG("init_srs_socket", "listen", errno);
+ } else {
+ retval = 1;
+ }
+
+ FD_SET(srs, &sock_set);
+ return (retval);
+}
+
+/*! Initialise a single dpi socket
+ * \Return
+ * \li 1 on success
+ * \li -1 on failure
+ */
+int init_dpi_socket(struct dp *dpi_attr, char *sockdir)
+{
+ int caught_error = 0, s;
+ char *dpi_nm; /* pointer to basename in dpi_attr->path */
+ struct sockaddr_un sa;
+ size_t sp_len;
+ socklen_t addr_sz;
+ size_t sock_buflen = 8192;
+
+ sp_len = sizeof(sa.sun_path);
+ if ((s = socket(AF_LOCAL, SOCK_STREAM, 0)) == -1) {
+ ERRMSG("init_all_dpi_sockets", "socket", errno);
+ return (-1); /* avoids nested ifs */
+ }
+ /* Set the socket FD to close on exec */
+ fcntl(s, F_SETFD, FD_CLOEXEC | fcntl(s, F_GETFD));
+
+ /* set some buffering to increase the transfer's speed */
+ setsockopt(s, SOL_SOCKET, SO_SNDBUF,
+ &sock_buflen, (socklen_t)sizeof(sock_buflen));
+
+ dpi_attr->socket = s;
+ dpi_attr->sa.sun_family = AF_LOCAL;
+ dpi_nm = get_basename(dpi_attr->path);
+
+ dpi_attr->sockpath = dStrconcat(sockdir, "/", dpi_nm, NULL);
+ if (strlen(dpi_attr->sockpath) > sp_len) {
+ ERRMSG("init_all_dpi_sockets", "socket path is too long", 0);
+ MSG_ERR("\n - it should be <= %lu chars", (ulong_t)sp_len);
+ MSG_ERR("\n - socket path = %s\n", dpi_attr->sockpath);
+ return(-1);
+ }
+ strncpy(dpi_attr->sa.sun_path, dpi_attr->sockpath, sp_len);
+ addr_sz = (socklen_t) D_SUN_LEN(&dpi_attr->sa);
+
+ if ((bind(s, (struct sockaddr *) &dpi_attr->sa, addr_sz)) == -1) {
+ ERRMSG("init_all_dpi_sockets", "bind", errno);
+ MSG_ERR("%s\n", dpi_attr->sa.sun_path);
+ caught_error = 1;
+ } else if (chmod(dpi_attr->sa.sun_path, S_IRUSR | S_IWUSR) == -1) {
+ ERRMSG("init_all_dpi_sockets", "chmod", errno);
+ MSG_ERR("%s\n", dpi_attr->sa.sun_path);
+ caught_error = 1;
+ } else if (listen(s, QUEUE) == -1) {
+ ERRMSG("init_all_dpi_sockets", "listen", errno);
+ caught_error = 1;
+ }
+
+ if (caught_error) {
+ return (-1);
+ } else {
+ FD_SET(s, &sock_set);
+ return (1);
+ }
+}
+
+/*! Setup sockets for the plugins and add them to
+ * to the set of sockets (sock_set) watched by select.
+ * \Return
+ * \li Number of sockets on success
+ * \li -1 on failure
+ * \Modifies
+ * dpi_attr_list.sa, dpi_attr_list.socket, numsocks, sock_set, srs
+ * \Uses
+ * numdpis, srs, srs_name
+ */
+int init_all_dpi_sockets(struct dp *dpi_attr_list, char *sockdir)
+{
+ int i;
+ struct sockaddr_un sa;
+ size_t sp_len;
+
+ sp_len = sizeof(sa.sun_path);
+
+ /* Initialise sockets for each dpi */
+ for (i = 0; i < numdpis; i++) {
+ if (init_dpi_socket(dpi_attr_list + i, sockdir) == -1)
+ return (-1);
+ numsocks++;
+ }
+
+ return (numsocks);
+}
+
+/*! SIGCHLD handler
+ */
+void dpi_sigchld(int sig)
+{
+ caught_sigchld = 1;
+}
+
+/*! Called by main loop when caught_sigchld == 1 */
+void handle_sigchld(void)
+{
+ // pid_t pid;
+ int i, status; //, num_active;
+
+ /* For all of the dpis in the current list
+ * add the ones that have exited to the set of sockets being
+ * watched by 'select'.
+ */
+ for (i = 0; i < numdpis; i++) {
+ if (waitpid(dpi_attr_list[i].pid, &status, WNOHANG) > 0) {
+ dpi_attr_list[i].pid = 1;
+ FD_SET(dpi_attr_list[i].socket, &sock_set);
+ numsocks++;
+ }
+ }
+
+ /* Wait for any old dpis that have exited */
+ while (waitpid(-1, &status, WNOHANG) > 0)
+ ;
+}
+
+/*! Establish SIGCHLD handler */
+void est_dpi_sigchld(void)
+{
+ struct sigaction sigact;
+ sigset_t set;
+
+ (void) sigemptyset(&set);
+ sigact.sa_handler = dpi_sigchld;
+ sigact.sa_mask = set;
+ sigact.sa_flags = SA_NOCLDSTOP;
+ if (sigaction(SIGCHLD, &sigact, NULL) == -1) {
+ ERRMSG("est_dpi_sigchld", "sigaction", errno);
+ exit(1);
+ }
+}
+
+/*! Send DpiBye command to all active non-filter dpis
+ */
+void stop_active_dpis(struct dp *dpi_attr_list, int numdpis)
+{
+ static char *DpiBye_cmd = NULL;
+ int i, dpi_socket;
+ struct sockaddr_un dpi_addr;
+ struct sockaddr_un sa;
+ size_t sun_path_len, addr_len;
+
+ if (!DpiBye_cmd)
+ DpiBye_cmd = a_Dpip_build_cmd("cmd=%s", "DpiBye");
+
+ sun_path_len = sizeof(sa.sun_path);
+ addr_len = sizeof(dpi_addr);
+
+ dpi_addr.sun_family = AF_LOCAL;
+
+ for (i = 0; i < numdpis; i++) {
+ /* Skip inactive dpis and filters */
+ if (dpi_attr_list[i].pid == 1 || dpi_attr_list[i].filter)
+ continue;
+
+ if ((dpi_socket = socket(AF_LOCAL, SOCK_STREAM, 0)) == -1) {
+ ERRMSG("stop_active_dpis", "socket", errno);
+ }
+ if (strlen(dpi_attr_list[i].sockpath) > sun_path_len) {
+ ERRMSG("stop_active_dpis", "socket path is too long", 0);
+ MSG_ERR("\n - it should be <= %lu chars",(ulong_t)sun_path_len);
+ MSG_ERR("\n - socket path = %s\n", dpi_attr_list[i].sockpath);
+ }
+ strncpy(dpi_addr.sun_path, dpi_attr_list[i].sockpath, sun_path_len);
+ if (connect(dpi_socket, (struct sockaddr *) &dpi_addr, addr_len) == -1) {
+ ERRMSG("stop_active_dpis", "connect", errno);
+ MSG_ERR("%s\n", dpi_addr.sun_path);
+ }
+ (void) write(dpi_socket, DpiBye_cmd, strlen(DpiBye_cmd));
+ a_Misc_close_fd(dpi_socket);
+ }
+}
+
+/*! Removes dpis in dpi_attr_list from the
+ * set of sockets watched by select and
+ * closes their sockets.
+ */
+void ignore_dpi_sockets(struct dp *dpi_attr_list, int numdpis)
+{
+ int i;
+
+ for (i = 0; i < numdpis; i++) {
+ FD_CLR(dpi_attr_list[i].socket, &sock_set);
+ a_Misc_close_fd(dpi_attr_list[i].socket);
+ }
+}
+
+/*! Registers available dpis and stops active non-filter dpis.
+ * Called when dpid receives
+ * cmd='register' service='all'
+ * command
+ * \Return
+ * Number of available dpis
+ */
+int register_all_cmd(char *sockdir)
+{
+ stop_active_dpis(dpi_attr_list, numdpis);
+ rm_dpi_sockets(dpi_attr_list, numdpis);
+ free_plugin_list(&dpi_attr_list, numdpis);
+ numdpis = 0;
+ numsocks = 1; /* the srs socket */
+ FD_ZERO(&sock_set);
+ FD_SET(srs, &sock_set);
+ numdpis = register_all(&dpi_attr_list);
+ numsocks = init_all_dpi_sockets(dpi_attr_list, sockdir);
+ return (numdpis);
+}
+
+/*!
+ * Get value of msg field from dpi_tag
+ * \Return
+ * message on success, NULL on failure
+ */
+char *get_message(int sock, char *dpi_tag)
+{
+ char *msg, *d_cmd;
+
+ msg = a_Dpip_get_attr(dpi_tag, strlen(dpi_tag), "msg");
+ if (msg == NULL) {
+ ERRMSG("get_message", "failed to parse msg", 0);
+ d_cmd = a_Dpip_build_cmd("cmd=%s msg=%s",
+ "DpiError", "Failed to parse request");
+ (void) CKD_WRITE(sock, d_cmd);
+ dFree(d_cmd);
+ }
+ return (msg);
+}
+
+/*!
+ * Send socket path that matches dpi_id to client
+ */
+void send_sockpath(int sock, char *dpi_tag, struct dp *dpi_attr_list)
+{
+ int i;
+ char *dpi_id;
+ char *d_cmd;
+
+ dReturn_if_fail((dpi_id = get_message(sock, dpi_tag)) != NULL);
+
+ for (i = 0; i < numdpis; i++)
+ if (strstr(dpi_attr_list[i].id, dpi_id))
+ break;
+ if (i < numdpis) {
+ /* found */
+ if (access(dpi_attr_list[i].path, F_OK) == -1) {
+ ERRMSG("send_sockpath", "access", errno);
+ MSG_ERR(" - %s\n", dpi_attr_list[i].sockpath);
+ d_cmd = a_Dpip_build_cmd("cmd=%s msg=%s",
+ "DpiError", "Plugin currently unavailable");
+ (void) CKD_WRITE(sock, d_cmd);
+ dFree(d_cmd);
+ } else {
+ d_cmd = a_Dpip_build_cmd("cmd=%s msg=%s",
+ "send_data", dpi_attr_list[i].sockpath);
+ (void) CKD_WRITE(sock, d_cmd);
+ dFree(d_cmd);
+ }
+ }
+
+ dFree(dpi_id);
+}
diff --git a/dpid/dpid.h b/dpid/dpid.h
new file mode 100644
index 00000000..2a41f538
--- /dev/null
+++ b/dpid/dpid.h
@@ -0,0 +1,103 @@
+/*! \file
+ * Main functions to set-up dpi information and to initialise sockets
+ */
+
+#ifndef DPID_H
+#define DPID_H
+
+#include <assert.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/un.h>
+#include <errno.h>
+
+#include "d_size.h"
+
+
+#define PATH_LEN 50
+#define CMDLEN 20
+#define MSGLEN 50
+/*! \todo: Should read this from dillorc */
+#define SRS_NAME "dpid.srs"
+char *srs_name;
+
+/*! dpid service request socket */
+int srs;
+
+/*! plugin state information
+ */
+struct dp {
+ char *id;
+ char *path;
+ char *sockpath;
+ int socket;
+ struct sockaddr_un sa;
+ pid_t pid;
+ int filter;
+};
+
+/*! Number of available plugins */
+int numdpis;
+
+/*! Number of sockets being watched */
+int numsocks;
+
+/*! State information for each plugin. */
+struct dp *dpi_attr_list;
+
+/*! Set of sockets watched for connections */
+fd_set sock_set;
+
+/*! Set to 1 by the SIGCHLD handler dpi_sigchld */
+extern volatile sig_atomic_t caught_sigchld;
+
+void rm_dpi_sockets(struct dp *dpi_attr_list, int numdpis);
+
+int rm_inactive_dpi_sockets(struct dp *dpi_attr_list, int numdpis);
+
+void cleanup(char *socket_dir);
+
+void free_dpi_attr(struct dp *dpi_attr);
+
+void free_plugin_list(struct dp **dpi_attr_list_ptr, int numdpis);
+
+enum file_type get_file_type(char *file_name);
+
+int get_dpi_attr(char *dpi_dir, char *service, struct dp *dpi_attr);
+
+int register_service(struct dp *dpi_attr, char *service);
+
+int register_all(struct dp **attlist);
+
+int init_srs_socket(char *sockdir);
+
+int init_dpi_socket(struct dp *dpi_attr, char *sockdir);
+
+int init_all_dpi_sockets(struct dp *dpi_attr_list, char *sockdir);
+
+void dpi_sigchld(int sig);
+
+void handle_sigchld(void);
+
+void est_dpi_sigchld(void);
+
+void stop_active_dpis(struct dp *dpi_attr_list, int numdpis);
+
+void ignore_dpi_sockets(struct dp *dpi_attr_list, int numdpis);
+
+int register_all_cmd(char *sockdir);
+
+char *get_message(int sock, char *dpi_tag);
+
+void send_sockpath(int sock, char * dpi_tag, struct dp *dpi_attr_list);
+
+#endif
diff --git a/dpid/dpid_common.c b/dpid/dpid_common.c
new file mode 100644
index 00000000..a04d9c4f
--- /dev/null
+++ b/dpid/dpid_common.c
@@ -0,0 +1,43 @@
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "dpid_common.h"
+
+/*
+ * Send a verbose error message.
+ */
+void errmsg(char *caller, char *called, int errornum, char *file, int line)
+{
+ MSG_ERR("%s:%d: %s: %s\n", file, line, caller, called);
+ if (errornum > 0)
+ MSG_ERR("%s\n", dStrerror(errornum));
+}
+
+/*! Selector function for scandir
+ * Do not scan files starting with '.'
+ */
+int no_dotfiles(const struct dirent *filedat)
+{
+ if (filedat->d_name[0] == '.')
+ return 0;
+ else
+ return 1;
+}
+
+/*!
+ * Provides an error checked write command.
+ * Call this via the CKD_WRITE macro
+ * \return write return value
+ */
+ssize_t ckd_write(int fd, char *msg, char *file, int line)
+{
+ ssize_t ret;
+
+ do {
+ ret = write(fd, msg, strlen(msg));
+ } while (ret == -1 && errno == EINTR);
+ if (ret == -1) {
+ MSG_ERR("%s:%d: write: %s\n", file, line, dStrerror(errno));
+ }
+ return (ret);
+}
diff --git a/dpid/dpid_common.h b/dpid/dpid_common.h
new file mode 100644
index 00000000..4311a8a8
--- /dev/null
+++ b/dpid/dpid_common.h
@@ -0,0 +1,61 @@
+#ifndef DPID_COMMON_H
+#define DPID_COMMON_H
+
+/*! \file
+ * Declares common functions, global variables, and types.
+ *
+ * \todo
+ * The dpid error codes will be used in
+ * the next patch
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <dirent.h>
+
+#include "../dlib/dlib.h"
+
+/*
+ * Debugging macros
+ */
+#define _MSG(...)
+#define MSG(...) printf("[dpid]: " __VA_ARGS__)
+#define _MSG_ERR(...)
+#define MSG_ERR(...) fprintf(stderr, "[dpid]: " __VA_ARGS__)
+
+#define dotDILLO_DPI ".dillo/dpi"
+#define dotDILLO_DPIDRC ".dillo/dpidrc"
+#define ERRMSG(CALLER, CALLED, ERR)\
+ errmsg(CALLER, CALLED, ERR, __FILE__, __LINE__)
+#define _ERRMSG(CALLER, CALLED, ERR)
+
+
+/*!
+ * Macro for calling the ckd_write function
+ */
+#define CKD_WRITE(fd, msg) ckd_write(fd, msg, __FILE__, __LINE__)
+
+
+/*! Error codes for dpid */
+enum {
+ no_errors,
+ dpid_srs_addrinuse /* dpid service request socket address already in use */
+} dpi_errno;
+
+/*! Intended for identifying dillo plugins
+ * and related files
+ */
+enum file_type {
+ DPI_FILE, /*! Any file name containing .dpi */
+ UNKNOWN_FILE
+};
+
+
+void errmsg(char *caller, char *called, int errornum, char *file, int line);
+
+int no_dotfiles(const struct dirent *filedat);
+
+ssize_t ckd_write(int fd, char *msg, char *file, int line);
+
+#endif
diff --git a/dpid/dpidc b/dpid/dpidc
new file mode 100644
index 00000000..88b887cb
--- /dev/null
+++ b/dpid/dpidc
@@ -0,0 +1,31 @@
+#!/usr/bin/perl -w
+# Author: Ferdi Franceschini
+#
+# dpid control program
+# Currently allows
+# register: Tells dpid to register all available dpis
+# stop: Stops dpid.
+
+use strict;
+use IO::Socket::UNIX;
+
+# Get socket directory name
+open(DSD, "<$ENV{HOME}/.dillo/dpi_socket_dir");
+my $dir = <DSD>;
+close(DSD);
+
+my $socket = IO::Socket::UNIX->new(Peer => "$dir/dpid.srs", Type => SOCK_STREAM, Timeout => 1000 ) or die "new: $@";
+
+$socket->autoflush(1);
+
+my %dpi_command = (
+ "register" => "<dpi cmd='register_all' '>",
+ "stop" => "<dpi cmd='DpiBye' '>",
+ );
+
+if ( exists($dpi_command{$ARGV[0]}) ) {
+ print $socket $dpi_command{$ARGV[0]};
+} else {
+ close($socket);
+ print "Usage: dpidc register|stop\n";
+}
diff --git a/dpid/main.c b/dpid/main.c
new file mode 100644
index 00000000..09c46968
--- /dev/null
+++ b/dpid/main.c
@@ -0,0 +1,398 @@
+/*
+ Copyright (C) 2003 Ferdi Franceschini <ferdif@optusnet.com.au>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <assert.h>
+#include "dpid_common.h"
+#include "dpid.h"
+#include "dpi.h"
+#include "dpi_socket_dir.h"
+#include "misc_new.h"
+#include "../dpip/dpip.h"
+
+sigset_t mask_sigchld;
+
+
+/* Start a dpi filter plugin after accepting the pending connection
+ * \Return
+ * \li Child process ID on success
+ * \li 0 on failure
+ */
+static int start_filter_plugin(struct dp dpi_attr)
+{
+ int newsock, old_stdout=-1, old_stdin=-1;
+ socklen_t csz;
+ struct sockaddr_un clnt_addr;
+ pid_t pid;
+
+ csz = (socklen_t) sizeof(clnt_addr);
+
+ newsock = accept(dpi_attr.socket, (struct sockaddr *) &clnt_addr, &csz);
+ if (newsock == -1)
+ ERRMSG("start_plugin", "accept", errno);
+
+ dup2(STDIN_FILENO, old_stdin);
+ if (dup2(newsock, STDIN_FILENO) == -1) {
+ ERRMSG("start_plugin", "dup2", errno);
+ MSG_ERR("ERROR in child proc for %s\n", dpi_attr.path);
+ exit(1);
+ }
+
+ dup2(STDOUT_FILENO, old_stdout);
+ if (dup2(newsock, STDOUT_FILENO) == -1) {
+ ERRMSG("start_plugin", "dup2", errno);
+ MSG_ERR("ERROR in child proc for %s\n", dpi_attr.path);
+ exit(1);
+ }
+ if ((pid = fork()) == -1) {
+ ERRMSG("main", "fork", errno);
+ return 0;
+ }
+ if (pid == 0) {
+ /* Child, start plugin */
+ if (execl(dpi_attr.path, dpi_attr.path, NULL) == -1) {
+ ERRMSG("start_plugin", "execl", errno);
+ MSG_ERR("ERROR in child proc for %s\n", dpi_attr.path);
+ exit(1);
+ }
+ }
+
+ /* Parent, Close sockets fix stdio and return pid */
+ if (a_Misc_close_fd(newsock) == -1) {
+ ERRMSG("start_plugin", "close", errno);
+ MSG_ERR("ERROR in child proc for %s\n", dpi_attr.path);
+ exit(1);
+ }
+ a_Misc_close_fd(STDIN_FILENO);
+ a_Misc_close_fd(STDOUT_FILENO);
+ dup2(old_stdin, STDIN_FILENO);
+ dup2(old_stdout, STDOUT_FILENO);
+ return pid;
+}
+
+static void start_server_plugin(struct dp dpi_attr)
+{
+ if (dup2(dpi_attr.socket, STDIN_FILENO) == -1) {
+ ERRMSG("start_plugin", "dup2", errno);
+ MSG_ERR("ERROR in child proc for %s\n", dpi_attr.path);
+ exit(1);
+ }
+ if (a_Misc_close_fd(dpi_attr.socket) == -1) {
+ ERRMSG("start_plugin", "close", errno);
+ MSG_ERR("ERROR in child proc for %s\n", dpi_attr.path);
+ exit(1);
+ }
+ if (execl(dpi_attr.path, dpi_attr.path, NULL) == -1) {
+ ERRMSG("start_plugin", "execl", errno);
+ MSG_ERR("ERROR in child proc for %s\n", dpi_attr.path);
+ exit(1);
+ }
+}
+
+/*!
+ * Read service request from sock
+ * \Return
+ * pointer to dynamically allocated request tag
+ */
+static char *get_request(int sock)
+{
+ char *req, buf[10];
+ size_t buflen;
+ size_t rqsz;
+ ssize_t rdln;
+
+ req = NULL;
+ buf[0] = '\0';
+ buflen = sizeof(buf) / sizeof(buf[0]);
+
+ (void) sigprocmask(SIG_BLOCK, &mask_sigchld, NULL);
+ for (rqsz = 0; (rdln = read(sock, buf, buflen)) != 0; rqsz += rdln) {
+ if (rdln == -1)
+ break;
+ req = (char *) realloc(req, rqsz + rdln + 1);
+ if (rqsz == 0)
+ req[0] = '\0';
+ strncat(req, buf, (size_t) rdln);
+ }
+ (void) sigprocmask(SIG_UNBLOCK, &mask_sigchld, NULL);
+ if (rdln == -1) {
+ ERRMSG("get_request", "read", errno);
+ }
+
+ return (req);
+}
+
+/*!
+ * Get value of cmd field in dpi_tag
+ * \Return
+ * command code on success, -1 on failure
+ */
+static int get_command(int sock, char *dpi_tag, struct dp *dpi_attr_list)
+{
+ char *cmd, *d_cmd;
+ int COMMAND;
+
+ if (dpi_tag == NULL) {
+ _ERRMSG("get_command", "dpid tag is NULL", 0);
+ return (-1);
+ }
+
+ cmd = a_Dpip_get_attr(dpi_tag, strlen(dpi_tag), "cmd");
+
+ if (cmd == NULL) {
+ ERRMSG("get_command", "a_Dpip_get_attr", 0);
+ MSG_ERR(": dpid failed to parse cmd in %s\n", dpi_tag);
+ d_cmd = a_Dpip_build_cmd("cmd=%s msg=%s",
+ "DpiError", "Failed to parse request");
+ (void) CKD_WRITE(sock, d_cmd);
+ dFree(d_cmd);
+ COMMAND = -1;
+ } else if (strcmp("DpiBye", cmd) == 0) {
+ COMMAND = BYE_CMD;
+ } else if (strcmp("check_server", cmd) == 0) {
+ COMMAND = CHECK_SERVER_CMD;
+ } else if (strcmp("register_all", cmd) == 0) {
+ COMMAND = REGISTER_ALL_CMD;
+ } else if (strcmp("register_service", cmd) == 0) {
+ COMMAND = REGISTER_SERVICE_CMD;
+ } else { /* Error unknown command */
+ COMMAND = UNKNOWN_CMD;
+ }
+
+ dFree(cmd);
+ return (COMMAND);
+}
+
+/*
+ * Check whether a dpi server is running
+ */
+int server_is_running(char *server_id)
+{
+ int i;
+
+ /* Search in the set of running servers */
+ for (i = 0; i < numdpis; i++) {
+ if (!dpi_attr_list[i].filter && dpi_attr_list[i].pid > 1 &&
+ strcmp(dpi_attr_list[i].id, server_id) == 0)
+ return 1;
+ }
+ return 0;
+}
+
+
+/*
+ * Get MAX open FD limit (yes, it's tricky --Jcid).
+ */
+static int get_open_max(void)
+{
+#ifdef OPEN_MAX
+ return OPEN_MAX;
+#else
+ int ret = sysconf(_SC_OPEN_MAX);
+ if (ret < 0)
+ ret = 256;
+ return ret;
+#endif
+}
+
+/*! \todo
+ * \li Add a dpid_idle_timeout variable to dpidrc
+ * \bug Infinite loop if plugin crashes before it accepts a connection
+ */
+int main(void)
+{
+ int i, n = 0, open_max;
+ char *dirname = NULL, *sockdir = NULL;
+ int dpid_idle_timeout = 60 * 60; /* default, in seconds */
+ struct timeval select_timeout;
+ sigset_t mask_none;
+ fd_set selected_set;
+
+ dpi_attr_list = NULL;
+ //daemon(0,0); /* Use 0,1 for feedback */
+ /* todo: call setsid() ?? */
+
+ /* Allow read and write access, but only for the user.
+ * todo: can this cause trouble with umount? */
+ umask(0077);
+ /* todo: make dpid work on any directory. */
+ // chdir("/");
+
+ /* close inherited file descriptors */
+ open_max = get_open_max();
+ for (i = 3; i < open_max; i++)
+ a_Misc_close_fd(i);
+
+ /* this sleep used to unmask a race condition */
+ // sleep(2);
+
+ dpi_errno = no_errors;
+
+ /* Get list of available dpis */
+ numdpis = register_all(&dpi_attr_list);
+
+ /* Get name of socket directory */
+ dirname = a_Dpi_sockdir_file();
+ if ((sockdir = init_sockdir(dirname)) == NULL) {
+ ERRMSG("main", "init_sockdir", 0);
+ MSG_ERR("Failed to create socket directory\n");
+ exit(1);
+ }
+
+ /* Remove any sockets that may have been leftover from a crash */
+ cleanup(sockdir);
+ /* Initialise sockets */
+ if ((numsocks = init_srs_socket(sockdir)) == -1) {
+ switch (dpi_errno) {
+ case dpid_srs_addrinuse:
+ MSG_ERR("dpid refuses to start, possibly because:\n");
+ MSG_ERR("\t1) An instance of dpid is already running.\n");
+ MSG_ERR("\t2) A previous dpid didn't clean up on exit.\n");
+ exit(1);
+ default:
+ ERRMSG("main", "init_srs_sockets failed", 0);
+ exit(1);
+ }
+ }
+ numsocks = init_all_dpi_sockets(dpi_attr_list, sockdir);
+ //est_terminator(); /* Do we still want to clean up on an abnormal exit? */
+ est_dpi_sigchld();
+
+ (void) sigemptyset(&mask_sigchld);
+ (void) sigaddset(&mask_sigchld, SIGCHLD);
+ (void) sigemptyset(&mask_none);
+ (void) sigprocmask(SIG_SETMASK, &mask_none, NULL);
+
+ printf("dpid started\n");
+/* Start main loop */
+ while (1) {
+ do {
+ (void) sigprocmask(SIG_BLOCK, &mask_sigchld, NULL);
+ if (caught_sigchld) {
+ handle_sigchld();
+ caught_sigchld = 0;
+ }
+ (void) sigprocmask(SIG_UNBLOCK, &mask_sigchld, NULL);
+ select_timeout.tv_sec = dpid_idle_timeout;
+ select_timeout.tv_usec = 0;
+ selected_set = sock_set;
+ n = select(FD_SETSIZE, &selected_set, NULL, NULL, &select_timeout);
+ if (n == 0) { /* select timed out, try to exit */
+ /* BUG: This is a workaround for dpid not to exit when the
+ * downloads server is active. The proper way to handle it is with
+ * a dpip command that asks the server whether it's busy.
+ * Note: the cookies server may lose session info too. */
+ if (server_is_running("downloads"))
+ continue;
+
+ stop_active_dpis(dpi_attr_list, numdpis);
+ cleanup(sockdir);
+ exit(0);
+ }
+ } while (n == -1 && errno == EINTR);
+
+ if (n == -1) {
+ ERRMSG("main", "select", errno);
+ exit(1);
+ }
+ /* If the service req socket is selected then service the req. */
+ if (FD_ISSET(srs, &selected_set)) {
+ int sock;
+ socklen_t csz;
+ struct sockaddr_un clnt_addr;
+ char *req = NULL;
+
+ --n;
+ assert(n >= 0);
+ csz = (socklen_t) sizeof(clnt_addr);
+ sock = accept(srs, (struct sockaddr *) &clnt_addr, &csz);
+ if (sock == -1) {
+ ERRMSG("main", "accept", errno);
+ MSG_ERR("accept on srs socket failed\n");
+ MSG_ERR("service pending connections, and continue\n");
+ } else {
+ int command;
+
+ req = get_request(sock);
+ command = get_command(sock, req, dpi_attr_list);
+ switch (command) {
+ case BYE_CMD:
+ stop_active_dpis(dpi_attr_list, numdpis);
+ cleanup(sockdir);
+ exit(0);
+ break;
+ case CHECK_SERVER_CMD:
+ send_sockpath(sock, req, dpi_attr_list);
+ break;
+ case REGISTER_ALL_CMD:
+ register_all_cmd(sockdir);
+ break;
+ case UNKNOWN_CMD:
+ {
+ char *d_cmd = a_Dpip_build_cmd("cmd=%s msg=%s",
+ "DpiError", "Unknown command");
+ (void) CKD_WRITE(sock, d_cmd);
+ dFree(d_cmd);
+ ERRMSG("main", "Unknown command", 0);
+ MSG_ERR(" for request: %s\n", req);
+ break;
+ }
+ case -1:
+ _ERRMSG("main", "get_command failed", 0);
+ break;
+ }
+ if (req)
+ free(req);
+ a_Misc_close_fd(sock);
+ }
+ }
+
+ /* While there's a request on one of the plugin sockets
+ * find the matching plugin and start it. */
+ for (i = 0; n > 0 && i < numdpis; i++) {
+ if (FD_ISSET(dpi_attr_list[i].socket, &selected_set)) {
+ --n;
+ assert(n >= 0);
+
+ if (dpi_attr_list[i].filter) {
+ /* start a dpi filter plugin and continue watching its socket
+ * for new connections */
+ (void) sigprocmask(SIG_SETMASK, &mask_none, NULL);
+ start_filter_plugin(dpi_attr_list[i]);
+ } else {
+ /* start a dpi server plugin but don't wait for new connections
+ * on its socket */
+ numsocks--;
+ assert(numsocks >= 0);
+ FD_CLR(dpi_attr_list[i].socket, &sock_set);
+ if ((dpi_attr_list[i].pid = fork()) == -1) {
+ ERRMSG("main", "fork", errno);
+ /* exit(1); */
+ } else if (dpi_attr_list[i].pid == 0) {
+ (void) sigprocmask(SIG_SETMASK, &mask_none, NULL);
+ start_server_plugin(dpi_attr_list[i]);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/dpid/misc_new.c b/dpid/misc_new.c
new file mode 100644
index 00000000..038e1fa6
--- /dev/null
+++ b/dpid/misc_new.c
@@ -0,0 +1,172 @@
+#include <stdio.h>
+#include <time.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <fcntl.h>
+#include "d_size.h"
+#include "misc_new.h"
+#include "dpid_common.h"
+
+#include "misc_new.h" /* for function prototypes */
+
+
+/*
+ * Close a FD handling EINTR.
+ */
+int a_Misc_close_fd(int fd)
+{
+ int st;
+
+ do {
+ st = close(fd);
+ } while (st < 0 && errno == EINTR);
+ return st;
+}
+
+/*! Reads a dpi tag from a socket
+ * \li Continues after a signal interrupt
+ * \Return
+ * Dstr pointer to tag on success, NULL on failure
+ * \important Caller is responsible for freeing the returned Dstr *
+ */
+Dstr *a_Misc_rdtag(int socket)
+{
+ char c = '\0';
+ ssize_t rdlen;
+ Dstr *tag;
+
+ tag = dStr_sized_new(64);
+
+ errno = 0;
+
+ do {
+ rdlen = read(socket, &c, 1);
+ if (rdlen == -1 && errno != EINTR)
+ break;
+ dStr_append_c(tag, c);
+ } while (c != '>');
+
+ if (rdlen == -1) {
+ perror("a_Misc_rdtag");
+ dStr_free(tag, TRUE);
+ return (NULL);
+ }
+ return (tag);
+}
+
+/*!
+ * Read a dpi tag from sock
+ * \return
+ * pointer to dynamically allocated request tag
+ */
+char *a_Misc_readtag(int sock)
+{
+ char *tag, c, buf[10];
+ size_t buflen, i;
+ size_t taglen = 0, tagmem = 10;
+ ssize_t rdln = 1;
+
+ tag = NULL;
+ buf[0] = '\0';
+ buflen = sizeof(buf) / sizeof(buf[0]);
+ // new start
+ tag = (char *) dMalloc(tagmem + 1);
+ for (i = 0; (rdln = read(sock, &c, 1)) != 0; i++) {
+ if (i == tagmem) {
+ tagmem += tagmem;
+ tag = (char *) dRealloc(tag, tagmem + 1);
+ }
+ tag[i] = c;
+ taglen += rdln;
+ if (c == '>') {
+ tag[i + 1] = '\0';
+ break;
+ }
+ }
+ // new end
+ if (rdln == -1) {
+ ERRMSG("a_Misc_readtag", "read", errno);
+ }
+
+ return (tag);
+}
+
+/*! Reads a dpi tag from a socket without hanging on read.
+ * \li Continues after a signal interrupt
+ * \Return
+ * \li 1 on success
+ * \li 0 if input is not available within timeout microseconds.
+ * \li -1 on failure
+ * \important Caller is responsible for freeing the returned Dstr *
+ */
+/* Is this useful?
+int a_Misc_nohang_rdtag(int socket, int timeout, Dstr **tag)
+{
+ int n_fd;
+ fd_set sock_set, select_set;
+ struct timeval tout;
+
+ FD_ZERO(&sock_set);
+ FD_SET(socket, &sock_set);
+
+ errno = 0;
+ do {
+ select_set = sock_set;
+ tout.tv_sec = 0;
+ tout.tv_usec = timeout;
+ n_fd = select(socket + 1, &select_set, NULL, NULL, &tout);
+ } while (n_fd == -1 && errno == EINTR);
+
+ if (n_fd == -1) {
+ MSG_ERR("%s:%d: a_Misc_nohang_rdtag: %s\n",
+ __FILE__, __LINE__, dStrerror(errno));
+ return(-1);
+ }
+ if (n_fd == 0) {
+ return(0);
+ } else {
+ *tag = a_Misc_rdtag(socket);
+ return(1);
+ }
+}
+*/
+
+/*
+ * Alternative to mkdtemp().
+ * Not as strong as mkdtemp, but enough for creating a directory.
+ * (adapted from dietlibc)
+ */
+char *a_Misc_mkdtemp(char *template)
+{
+ char *tmp = template + strlen(template) - 6;
+ int i;
+ unsigned int random;
+
+ if (tmp < template)
+ goto error;
+ for (i = 0; i < 6; ++i)
+ if (tmp[i] != 'X') {
+ error:
+ errno = EINVAL;
+ return 0;
+ }
+ srand((uint_t)(time(0) ^ getpid()));
+ for (;;) {
+ random = (unsigned) rand();
+ for (i = 0; i < 6; ++i) {
+ int hexdigit = (random >> (i * 5)) & 0x1f;
+
+ tmp[i] = hexdigit > 9 ? hexdigit + 'a' - 10 : hexdigit + '0';
+ }
+ if (mkdir(template, 0700) == 0)
+ break;
+ if (errno == EEXIST)
+ continue;
+ return 0;
+ }
+ return template;
+}
diff --git a/dpid/misc_new.h b/dpid/misc_new.h
new file mode 100644
index 00000000..94e10676
--- /dev/null
+++ b/dpid/misc_new.h
@@ -0,0 +1,12 @@
+#ifndef MISC_NEW_H
+#define MISC_NEW_H
+
+#include "../dlib/dlib.h"
+
+
+int a_Misc_close_fd(int fd);
+Dstr *a_Misc_rdtag(int socket);
+char *a_Misc_readtag(int sock);
+char *a_Misc_mkdtemp(char *template);
+
+#endif