Initial import of Dillo
This commit is contained in:
36
dpid/Makefile.am
Normal file
36
dpid/Makefile.am
Normal file
@ -0,0 +1,36 @@
|
||||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir) \
|
||||
-DEXEEXT='"$(EXEEXT)"' \
|
||||
-DDPIDRC_SYS='"$(sysconfdir)/dpidrc"'
|
||||
|
||||
bin_PROGRAMS = dpid dpidc
|
||||
dpid_LDADD = \
|
||||
$(top_builddir)/dpip/libDpip.a \
|
||||
$(top_builddir)/dlib/libDlib.a
|
||||
dpidc_LDADD = \
|
||||
$(top_builddir)/dpip/libDpip.a \
|
||||
$(top_builddir)/dlib/libDlib.a
|
||||
|
||||
EXTRA_DIST = dpidrc.in
|
||||
|
||||
dpid_SOURCES = \
|
||||
dpi.h \
|
||||
dpi_socket_dir.h \
|
||||
dpid.h \
|
||||
dpid_common.h \
|
||||
misc_new.h \
|
||||
dpi.c \
|
||||
dpi_socket_dir.c \
|
||||
dpid.c \
|
||||
dpid_common.c \
|
||||
main.c \
|
||||
misc_new.c
|
||||
|
||||
dpidc_SOURCES = dpidc.c
|
||||
|
||||
sysconf_DATA = dpidrc
|
||||
CLEANFILES = $(sysconf_DATA)
|
||||
|
||||
dpidrc: $(srcdir)/dpidrc.in Makefile
|
||||
sed -e 's|[@]libdir[@]|$(libdir)|;s|[@]EXEEXT[@]|$(EXEEXT)|g' $(srcdir)/dpidrc.in > dpidrc
|
||||
|
32
dpid/TODO
Normal file
32
dpid/TODO
Normal file
@ -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)
|
97
dpid/dpi.c
Normal file
97
dpid/dpi.c
Normal file
@ -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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*! \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 <stdlib.h> /* for exit */
|
||||
#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);
|
||||
}
|
45
dpid/dpi.h
Normal file
45
dpid/dpi.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*! \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 <unistd.h> /* for socklen_t */
|
||||
#include <sys/socket.h> /* for socklen_t and AF_LOCAL */
|
||||
|
||||
/* 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,
|
||||
AUTH_CMD, /* authentication */
|
||||
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
|
129
dpid/dpi_socket_dir.c
Normal file
129
dpid/dpi_socket_dir.c
Normal file
@ -0,0 +1,129 @@
|
||||
/*
|
||||
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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
* Create a per user temporary directory for dpi sockets
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.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, *logname;
|
||||
|
||||
logname = getenv("LOGNAME") ? getenv("LOGNAME") : "dillo";
|
||||
template = dStrconcat("/tmp/", logname, "-", "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",
|
||||
dpi_socket_dir);
|
||||
} 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);
|
||||
}
|
17
dpid/dpi_socket_dir.h
Normal file
17
dpid/dpi_socket_dir.h
Normal file
@ -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
|
908
dpid/dpid.c
Normal file
908
dpid/dpid.c
Normal file
@ -0,0 +1,908 @@
|
||||
/*
|
||||
Copyright (C) 2003 Ferdi Franceschini <ferdif@optusnet.com.au>
|
||||
Copyright (C) 2025 Rodrigo Arias Mallo <rodarima@gmail.com>
|
||||
|
||||
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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
* Main functions to set-up dpi information and to initialise sockets
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <stdlib.h> /* for exit */
|
||||
#include <fcntl.h> /* for F_SETFD, F_GETFD, FD_CLOEXEC */
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include "dpid_common.h"
|
||||
#include "dpid.h"
|
||||
#include "dpi.h"
|
||||
#include "dpi_socket_dir.h"
|
||||
#include "misc_new.h"
|
||||
|
||||
#include "../dpip/dpip.h"
|
||||
|
||||
#define DPI_EXT (".dpi" EXEEXT)
|
||||
|
||||
#define QUEUE 5
|
||||
|
||||
volatile sig_atomic_t caught_sigchld = 0;
|
||||
char *SharedKey = NULL;
|
||||
|
||||
/*! Remove dpid_comm_keys file.
|
||||
* This avoids that dillo instances connect to a stale port after dpid
|
||||
* has exited (e.g. after a reboot).
|
||||
*/
|
||||
void cleanup(void)
|
||||
{
|
||||
char *fname;
|
||||
fname = dStrconcat(dGethomedir(), "/", dotDILLO_DPID_COMM_KEYS, NULL);
|
||||
unlink(fname);
|
||||
dFree(fname);
|
||||
}
|
||||
|
||||
/*! 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;
|
||||
}
|
||||
}
|
||||
|
||||
/*! 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;
|
||||
}
|
||||
|
||||
/*! Free memory used by the services list
|
||||
*/
|
||||
void free_services_list(Dlist *s_list)
|
||||
{
|
||||
int i = 0;
|
||||
struct service *s;
|
||||
|
||||
for (i=0; i < dList_length(s_list) ; i++) {
|
||||
s = dList_nth_data(s_list, i);
|
||||
dFree(s->name);
|
||||
}
|
||||
dList_free(s_list);
|
||||
}
|
||||
|
||||
/*! Signal handler for SIGINT, SIGQUIT, and SIGTERM. Calls cleanup
|
||||
*/
|
||||
static void terminator(int sig)
|
||||
{
|
||||
(void) sig; /* suppress unused parameter warning */
|
||||
cleanup();
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
/*! Establish handler for termination signals
|
||||
* and register cleanup with atexit */
|
||||
void est_dpi_terminator(void)
|
||||
{
|
||||
struct sigaction act;
|
||||
sigset_t block;
|
||||
|
||||
sigemptyset(&block);
|
||||
sigaddset(&block, SIGHUP);
|
||||
sigaddset(&block, SIGINT);
|
||||
sigaddset(&block, SIGQUIT);
|
||||
sigaddset(&block, SIGTERM);
|
||||
|
||||
act.sa_handler = terminator;
|
||||
act.sa_mask = block;
|
||||
act.sa_flags = 0;
|
||||
|
||||
if (sigaction(SIGHUP, &act, NULL) ||
|
||||
sigaction(SIGINT, &act, NULL) ||
|
||||
sigaction(SIGQUIT, &act, NULL) ||
|
||||
sigaction(SIGTERM, &act, NULL)) {
|
||||
ERRMSG("est_dpi_terminator", "sigaction", errno);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (atexit(cleanup) != 0) {
|
||||
ERRMSG("est_dpi_terminator", "atexit", 0);
|
||||
MSG_ERR("Hey! atexit failed, how did that happen?\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static int ends_with(const char *str, const char *suffix)
|
||||
{
|
||||
if (!str || !suffix)
|
||||
return 0;
|
||||
size_t lenstr = strlen(str);
|
||||
size_t lensuffix = strlen(suffix);
|
||||
if (lensuffix > lenstr)
|
||||
return 0;
|
||||
return strncmp(str + lenstr - lensuffix, suffix, lensuffix) == 0;
|
||||
}
|
||||
|
||||
/*! 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)
|
||||
{
|
||||
if (ends_with(file_name, DPI_EXT))
|
||||
/* Any filename ending in ".dpi" (or ".dpi.exe" on Windows) */
|
||||
return DPI_FILE;
|
||||
else {
|
||||
MSG_ERR("get_file_type: Unknown file type for %s\n", file_name);
|
||||
return UNKNOWN_FILE;
|
||||
}
|
||||
}
|
||||
|
||||
/*! 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("e.g. dpi_dir=/usr/local/lib/dillo/dpi\n");
|
||||
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);
|
||||
}
|
||||
|
||||
/*! 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 ret = -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 looking 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->port = 0;
|
||||
dpi_attr->pid = 1;
|
||||
if (strstr(dpi_attr->path, ".filter") != NULL)
|
||||
dpi_attr->filter = 1;
|
||||
else
|
||||
dpi_attr->filter = 0;
|
||||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
closedir(dir_stream);
|
||||
|
||||
if (ret != 0)
|
||||
MSG_ERR("get_dpi_attr: No dpi plug-in in %s/%s\n",
|
||||
dpi_dir, service);
|
||||
}
|
||||
dFree(service_dir);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*! 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 ret = -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);
|
||||
ret = 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);
|
||||
ret = 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 ret;
|
||||
}
|
||||
|
||||
/*!
|
||||
* 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)
|
||||
{
|
||||
char *user_dpidir = NULL, *sys_dpidir = NULL, *dpidrc = NULL;
|
||||
struct dirent *user_dirent, *sys_dirent;
|
||||
int st;
|
||||
int snum;
|
||||
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 = 0;
|
||||
if (user_dpidir) {
|
||||
DIR *user_dir_stream = opendir(user_dpidir);
|
||||
/* Only complain if error is other than not found as the user may not have
|
||||
* any DPIs installed. */
|
||||
if (user_dir_stream == NULL && errno != ENOENT) {
|
||||
MSG_ERR("cannot open user dpi directory '%s': %s\n",
|
||||
user_dpidir, strerror(errno));
|
||||
} else {
|
||||
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++;
|
||||
}
|
||||
closedir(user_dir_stream);
|
||||
}
|
||||
}
|
||||
if (sys_dpidir) {
|
||||
DIR *sys_dir_stream = opendir(sys_dpidir);
|
||||
/* For system DPIs always complain. */
|
||||
if (sys_dir_stream == NULL) {
|
||||
MSG_ERR("cannot open system dpi directory '%s': %s\n",
|
||||
sys_dpidir, strerror(errno));
|
||||
} else {
|
||||
/* 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;
|
||||
*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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare two struct service pointers
|
||||
* This function is used for sorting services
|
||||
*/
|
||||
static int services_alpha_comp(const struct service *s1,
|
||||
const struct service *s2)
|
||||
{
|
||||
return -strcmp(s1->name, s2->name);
|
||||
}
|
||||
|
||||
/*! Add services reading a dpidrc file
|
||||
* each non empty or commented line has the form
|
||||
* service = path_relative_to_dpidir
|
||||
* \Return:
|
||||
* \li Returns number of available services on success
|
||||
* \li -1 on failure
|
||||
*/
|
||||
int fill_services_list(struct dp *attlist, int numdpis, Dlist **services_list)
|
||||
{
|
||||
FILE *dpidrc_stream;
|
||||
char *p, *line = NULL, *service, *path;
|
||||
int i, st;
|
||||
struct service *s;
|
||||
char *user_dpidir = NULL, *sys_dpidir = NULL, *dpidrc = NULL;
|
||||
|
||||
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;
|
||||
|
||||
if (!user_dpidir && !sys_dpidir) {
|
||||
ERRMSG("fill_services_list", "Fatal error ", 0);
|
||||
MSG_ERR("\n - Can't find the directory for dpis.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ((dpidrc_stream = fopen(dpidrc, "r")) == NULL) {
|
||||
ERRMSG("fill_services_list", "popen failed", errno);
|
||||
dFree(dpidrc);
|
||||
dFree(sys_dpidir);
|
||||
dFree(user_dpidir);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (*services_list != NULL) {
|
||||
ERRMSG("fill_services_list", "services_list parameter is not NULL", 0);
|
||||
fclose(dpidrc_stream);
|
||||
return -1;
|
||||
}
|
||||
*services_list = dList_new(8);
|
||||
|
||||
/* dpidrc parser loop */
|
||||
for (;(line = dGetline(dpidrc_stream)) != NULL; dFree(line)) {
|
||||
st = dParser_parse_rc_line(&line, &service, &path);
|
||||
if (st < 0) {
|
||||
MSG_ERR("dpid: Syntax error in %s: service=\"%s\" path=\"%s\"\n",
|
||||
dpidrc, service, path);
|
||||
continue;
|
||||
} else if (st != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
_MSG("dpid: service=%s, path=%s\n", service, path);
|
||||
|
||||
/* ignore dpi_dir silently */
|
||||
if (strcmp(service, "dpi_dir") == 0)
|
||||
continue;
|
||||
|
||||
s = dNew(struct service, 1);
|
||||
/* init services list entry */
|
||||
s->name = dStrdup(service);
|
||||
s->dp_index = -1;
|
||||
|
||||
dList_append(*services_list, s);
|
||||
/* search the dpi for a service by its path */
|
||||
for (i = 0; i < numdpis; i++)
|
||||
if ((p = strstr(attlist[i].path, path)) && *(p - 1) == '/' &&
|
||||
strlen(p) == strlen(path))
|
||||
break;
|
||||
/* if the dpi exist bind service and dpi */
|
||||
if (i < numdpis)
|
||||
s->dp_index = i;
|
||||
}
|
||||
fclose(dpidrc_stream);
|
||||
|
||||
dList_sort(*services_list, (dCompareFunc)services_alpha_comp);
|
||||
|
||||
dFree(dpidrc);
|
||||
dFree(sys_dpidir);
|
||||
dFree(user_dpidir);
|
||||
|
||||
return (dList_length(*services_list));
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a socket file descriptor
|
||||
* (useful to set socket options in a uniform way)
|
||||
*/
|
||||
static int make_socket_fd(void)
|
||||
{
|
||||
int ret, one = 1;
|
||||
|
||||
if ((ret = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
|
||||
ERRMSG("make_socket_fd", "socket", errno);
|
||||
} else {
|
||||
/* avoid delays when sending small pieces of data */
|
||||
setsockopt(ret, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
|
||||
}
|
||||
|
||||
/* set some buffering to increase the transfer's speed */
|
||||
//setsockopt(sock_fd, SOL_SOCKET, SO_SNDBUF,
|
||||
// &sock_buflen, (socklen_t)sizeof(sock_buflen));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*! Bind a socket port on localhost. Try to be close to base_port.
|
||||
* \Return
|
||||
* \li listening socket file descriptor on success
|
||||
* \li -1 on failure
|
||||
*/
|
||||
int bind_socket_fd(int base_port, int *p_port)
|
||||
{
|
||||
int sock_fd, port;
|
||||
struct sockaddr_in sin;
|
||||
int ok = 0, last_port = base_port + 50;
|
||||
|
||||
if ((sock_fd = make_socket_fd()) == -1) {
|
||||
return (-1); /* avoids nested ifs */
|
||||
}
|
||||
/* Set the socket FD to close on exec */
|
||||
fcntl(sock_fd, F_SETFD, FD_CLOEXEC | fcntl(sock_fd, F_GETFD));
|
||||
|
||||
|
||||
memset(&sin, 0, sizeof(sin));
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_addr.s_addr = inet_addr("127.0.0.1");
|
||||
|
||||
/* Try to bind a port on localhost */
|
||||
for (port = base_port; port <= last_port; ++port) {
|
||||
sin.sin_port = htons(port);
|
||||
if ((bind(sock_fd, (struct sockaddr *)&sin, sizeof(sin))) == -1) {
|
||||
if (errno == EADDRINUSE || errno == EADDRNOTAVAIL)
|
||||
continue;
|
||||
ERRMSG("bind_socket_fd", "bind", errno);
|
||||
} else if (listen(sock_fd, QUEUE) == -1) {
|
||||
ERRMSG("bind_socket_fd", "listen", errno);
|
||||
} else {
|
||||
*p_port = port;
|
||||
ok = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (port > last_port) {
|
||||
MSG_ERR("Hey! Can't find an available port from %d to %d\n",
|
||||
base_port, last_port);
|
||||
}
|
||||
|
||||
return ok ? sock_fd : -1;
|
||||
}
|
||||
|
||||
/*! Save the current port and a shared secret in a file so dillo can find it.
|
||||
* \Return:
|
||||
* \li -1 on failure
|
||||
*/
|
||||
int save_comm_keys(int srs_port)
|
||||
{
|
||||
int fd, ret = -1;
|
||||
char *fname, port_str[32];
|
||||
|
||||
fname = dStrconcat(dGethomedir(), "/", dotDILLO_DPID_COMM_KEYS, NULL);
|
||||
fd = open(fname, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
|
||||
dFree(fname);
|
||||
if (fd == -1) {
|
||||
MSG("save_comm_keys: open %s\n", dStrerror(errno));
|
||||
} else {
|
||||
snprintf(port_str, 16, "%d %s\n", srs_port, SharedKey);
|
||||
if (CKD_WRITE(fd, port_str) != -1 && CKD_CLOSE(fd) != -1) {
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*! Initialise the service request socket (IDS)
|
||||
* \Return:
|
||||
* \li Number of sockets (1 == success)
|
||||
* \li -1 on failure
|
||||
*/
|
||||
int init_ids_srs_socket(void)
|
||||
{
|
||||
int srs_port, ret = -1;
|
||||
|
||||
FD_ZERO(&sock_set);
|
||||
|
||||
if ((srs_fd = bind_socket_fd(DPID_BASE_PORT, &srs_port)) != -1) {
|
||||
/* create the shared secret */
|
||||
SharedKey = a_Misc_mksecret(8);
|
||||
/* save port number and SharedKey */
|
||||
if (save_comm_keys(srs_port) != -1) {
|
||||
FD_SET(srs_fd, &sock_set);
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*! Initialize a single dpi socket
|
||||
* \Return
|
||||
* \li 1 on success
|
||||
* \li -1 on failure
|
||||
*/
|
||||
int init_dpi_socket(struct dp *dpi_attr)
|
||||
{
|
||||
int s_fd, port, ret = -1;
|
||||
|
||||
if ((s_fd = bind_socket_fd(DPID_BASE_PORT, &port)) != -1) {
|
||||
dpi_attr->sock_fd = s_fd;
|
||||
dpi_attr->port = port;
|
||||
FD_SET(s_fd, &sock_set);
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*! Setup sockets for the plugins and add them 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)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Initialise sockets for each dpi */
|
||||
for (i = 0; i < numdpis; i++) {
|
||||
if (init_dpi_socket(dpi_attr_list + i) == -1)
|
||||
return (-1);
|
||||
numsocks++;
|
||||
}
|
||||
|
||||
return (numsocks);
|
||||
}
|
||||
|
||||
/*! SIGCHLD handler
|
||||
*/
|
||||
void dpi_sigchld(int sig)
|
||||
{
|
||||
if (sig == SIGCHLD)
|
||||
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].sock_fd, &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);
|
||||
}
|
||||
}
|
||||
|
||||
/*! EINTR aware connect() call */
|
||||
int ckd_connect (int sock_fd, struct sockaddr *addr, socklen_t len)
|
||||
{
|
||||
ssize_t ret;
|
||||
|
||||
do {
|
||||
ret = connect(sock_fd, addr, len);
|
||||
} while (ret == -1 && errno == EINTR);
|
||||
if (ret == -1) {
|
||||
ERRMSG("dpid.c", "connect", errno);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*! Send DpiBye command to all active non-filter dpis
|
||||
*/
|
||||
void stop_active_dpis(struct dp *dpi_attr_list, int numdpis)
|
||||
{
|
||||
char *bye_cmd, *auth_cmd;
|
||||
int i, sock_fd;
|
||||
struct sockaddr_in sin;
|
||||
|
||||
bye_cmd = a_Dpip_build_cmd("cmd=%s", "DpiBye");
|
||||
auth_cmd = a_Dpip_build_cmd("cmd=%s msg=%s", "auth", SharedKey);
|
||||
|
||||
memset(&sin, 0, sizeof(sin));
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_addr.s_addr = inet_addr("127.0.0.1");
|
||||
|
||||
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 ((sock_fd = make_socket_fd()) == -1) {
|
||||
ERRMSG("stop_active_dpis", "socket", errno);
|
||||
continue;
|
||||
}
|
||||
|
||||
sin.sin_port = htons(dpi_attr_list[i].port);
|
||||
if (ckd_connect(sock_fd, (struct sockaddr *)&sin, sizeof(sin)) == -1) {
|
||||
ERRMSG("stop_active_dpis", "connect", errno);
|
||||
MSG_ERR("%s\n", dpi_attr_list[i].path);
|
||||
} else if (CKD_WRITE(sock_fd, auth_cmd) == -1) {
|
||||
ERRMSG("stop_active_dpis", "write", errno);
|
||||
} else if (CKD_WRITE(sock_fd, bye_cmd) == -1) {
|
||||
ERRMSG("stop_active_dpis", "write", errno);
|
||||
}
|
||||
dClose(sock_fd);
|
||||
}
|
||||
|
||||
dFree(auth_cmd);
|
||||
dFree(bye_cmd);
|
||||
|
||||
/* Allow child dpis some time to read dpid_comm_keys before erasing it */
|
||||
sleep (1);
|
||||
}
|
||||
|
||||
/*! 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].sock_fd, &sock_set);
|
||||
dClose(dpi_attr_list[i].sock_fd);
|
||||
}
|
||||
}
|
||||
|
||||
/*! 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(void)
|
||||
{
|
||||
stop_active_dpis(dpi_attr_list, numdpis);
|
||||
free_plugin_list(&dpi_attr_list, numdpis);
|
||||
free_services_list(services_list);
|
||||
services_list = NULL;
|
||||
numdpis = 0;
|
||||
numsocks = 1; /* the srs socket */
|
||||
FD_ZERO(&sock_set);
|
||||
FD_SET(srs_fd, &sock_set);
|
||||
numdpis = register_all(&dpi_attr_list);
|
||||
fill_services_list(dpi_attr_list, numdpis, &services_list);
|
||||
numsocks = init_all_dpi_sockets(dpi_attr_list);
|
||||
return (numdpis);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Get value of msg field from dpi_tag
|
||||
* \Return
|
||||
* message on success, NULL on failure
|
||||
*/
|
||||
char *get_message(int sock_fd, char *dpi_tag)
|
||||
{
|
||||
char *msg, *d_cmd;
|
||||
|
||||
msg = a_Dpip_get_attr(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_fd, d_cmd);
|
||||
dFree(d_cmd);
|
||||
}
|
||||
return (msg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare a struct service pointer and a service name
|
||||
* This function is used for searching services by name
|
||||
*/
|
||||
int service_match(const struct service *A, const char *B)
|
||||
{
|
||||
int A_len, B_len, len;
|
||||
|
||||
A_len = strlen(A->name);
|
||||
B_len = strlen(B);
|
||||
len = MAX (A_len, B_len);
|
||||
|
||||
if (A->name[A_len - 1] == '*')
|
||||
len = A_len - 1;
|
||||
|
||||
return(dStrnAsciiCasecmp(A->name, B, len));
|
||||
}
|
||||
|
||||
/*!
|
||||
* Send socket port that matches dpi_id to client
|
||||
*/
|
||||
void send_sockport(int sock_fd, char *dpi_tag, struct dp *dpi_attr_list)
|
||||
{
|
||||
int i;
|
||||
char *dpi_id, *d_cmd, port_str[16];
|
||||
struct service *serv;
|
||||
|
||||
dReturn_if_fail((dpi_id = get_message(sock_fd, dpi_tag)) != NULL);
|
||||
|
||||
serv = dList_find_custom(services_list,dpi_id,(dCompareFunc)service_match);
|
||||
|
||||
if (serv == NULL || (i = serv->dp_index) == -1)
|
||||
for (i = 0; i < numdpis; i++)
|
||||
if (!strncmp(dpi_attr_list[i].id, dpi_id,
|
||||
dpi_attr_list[i].id - strchr(dpi_attr_list[i].id, '.')))
|
||||
break;
|
||||
|
||||
if (i < numdpis) {
|
||||
/* found */
|
||||
snprintf(port_str, 8, "%d", dpi_attr_list[i].port);
|
||||
d_cmd = a_Dpip_build_cmd("cmd=%s msg=%s", "send_data", port_str);
|
||||
(void) CKD_WRITE(sock_fd, d_cmd);
|
||||
dFree(d_cmd);
|
||||
}
|
||||
|
||||
dFree(dpi_id);
|
||||
}
|
115
dpid/dpid.h
Normal file
115
dpid/dpid.h
Normal file
@ -0,0 +1,115 @@
|
||||
/*! \file
|
||||
* Main functions to set-up dpi information and to initialise sockets
|
||||
*/
|
||||
|
||||
#ifndef DPID_H
|
||||
#define DPID_H
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/select.h> /* for fd_set */
|
||||
#include <sys/un.h>
|
||||
#include <signal.h> /* for sig_atomic_t */
|
||||
#include <netinet/in.h> /* for ntohl, IPPORT_USERRESERVED and stuff */
|
||||
|
||||
#include "d_size.h"
|
||||
|
||||
/* FreeBSD 6.4 doesn't have it */
|
||||
#ifndef IPPORT_USERRESERVED
|
||||
#define IPPORT_USERRESERVED 5000
|
||||
#endif
|
||||
|
||||
#define PATH_LEN 50
|
||||
#define CMDLEN 20
|
||||
#define MSGLEN 50
|
||||
#define DPID_BASE_PORT (IPPORT_USERRESERVED + 20)
|
||||
|
||||
/*! \TODO: Should read this from dillorc */
|
||||
#define SRS_NAME "dpid.srs"
|
||||
extern char *srs_name;
|
||||
|
||||
/*! dpid's service request socket file descriptor */
|
||||
extern int srs_fd;
|
||||
|
||||
/*! plugin state information
|
||||
*/
|
||||
struct dp {
|
||||
char *id;
|
||||
char *path;
|
||||
int sock_fd;
|
||||
int port;
|
||||
pid_t pid;
|
||||
int filter;
|
||||
};
|
||||
|
||||
/*! bind dpi with service
|
||||
*/
|
||||
struct service {
|
||||
char *name;
|
||||
int dp_index;
|
||||
};
|
||||
|
||||
/*! Number of available plugins */
|
||||
extern int numdpis;
|
||||
|
||||
/*! Number of sockets being watched */
|
||||
extern int numsocks;
|
||||
|
||||
/*! State information for each plugin. */
|
||||
extern struct dp *dpi_attr_list;
|
||||
|
||||
/*! service served for each plugin */
|
||||
extern Dlist *services_list;
|
||||
|
||||
/*! Set of sockets watched for connections */
|
||||
extern 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);
|
||||
|
||||
void cleanup(void);
|
||||
|
||||
void free_dpi_attr(struct dp *dpi_attr);
|
||||
|
||||
void free_plugin_list(struct dp **dpi_attr_list_ptr, int numdpis);
|
||||
|
||||
void free_services_list(Dlist *s_list);
|
||||
|
||||
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 fill_services_list(struct dp *attlist, int numdpis, Dlist **services_list);
|
||||
|
||||
int init_ids_srs_socket(void);
|
||||
|
||||
int init_dpi_socket(struct dp *dpi_attr);
|
||||
|
||||
int init_all_dpi_sockets(struct dp *dpi_attr_list);
|
||||
|
||||
void dpi_sigchld(int sig);
|
||||
|
||||
void handle_sigchld(void);
|
||||
|
||||
void est_dpi_sigchld(void);
|
||||
|
||||
void est_dpi_terminator(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(void);
|
||||
|
||||
char *get_message(int sock, char *dpi_tag);
|
||||
|
||||
int service_match(const struct service *A, const char *B);
|
||||
|
||||
void send_sockport(int sock_fd, char * dpi_tag, struct dp *dpi_attr_list);
|
||||
|
||||
#endif
|
59
dpid/dpid_common.c
Normal file
59
dpid/dpid_common.c
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* File: dpid_common.c
|
||||
*
|
||||
* Copyright 2008 Jorge Arellano Cid <jcid@dillo.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.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));
|
||||
}
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Provides an error checked close() call.
|
||||
* Call this via the CKD_CLOSE macro
|
||||
* \return close return value
|
||||
*/
|
||||
ssize_t ckd_close(int fd, char *file, int line)
|
||||
{
|
||||
ssize_t ret;
|
||||
|
||||
ret = dClose(fd);
|
||||
if (ret == -1)
|
||||
MSG_ERR("%s:%d: close: %s\n", file, line, dStrerror(errno));
|
||||
return ret;
|
||||
}
|
||||
|
54
dpid/dpid_common.h
Normal file
54
dpid/dpid_common.h
Normal file
@ -0,0 +1,54 @@
|
||||
#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 <dirent.h>
|
||||
#include <stddef.h> /* size_t */
|
||||
#include <sys/types.h> /* ssize_t */
|
||||
|
||||
#include "../dlib/dlib.h"
|
||||
|
||||
/*
|
||||
* Debugging macros
|
||||
*/
|
||||
#define _MSG(...)
|
||||
#define MSG(...) printf("[dpid]: " __VA_ARGS__)
|
||||
#define MSG_ERR(...) fprintf(stderr, "[dpid]: " __VA_ARGS__)
|
||||
|
||||
#define dotDILLO_DPI ".dillo/dpi"
|
||||
#define dotDILLO_DPIDRC ".dillo/dpidrc"
|
||||
#define dotDILLO_DPID_COMM_KEYS ".dillo/dpid_comm_keys"
|
||||
|
||||
#define ERRMSG(CALLER, CALLED, ERR)\
|
||||
errmsg(CALLER, CALLED, ERR, __FILE__, __LINE__)
|
||||
#define _ERRMSG(CALLER, CALLED, ERR)
|
||||
|
||||
|
||||
/*!
|
||||
* Macros for calling ckd_write and ckd_close functions
|
||||
*/
|
||||
#define CKD_WRITE(fd, msg) ckd_write(fd, msg, __FILE__, __LINE__)
|
||||
#define CKD_CLOSE(fd) ckd_close(fd, __FILE__, __LINE__)
|
||||
|
||||
/*! 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);
|
||||
|
||||
ssize_t ckd_write(int fd, char *msg, char *file, int line);
|
||||
ssize_t ckd_close(int fd, char *file, int line);
|
||||
|
||||
#endif
|
133
dpid/dpidc.c
Normal file
133
dpid/dpidc.c
Normal file
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (C) 2009-2013 Jorge Arellano Cid <jcid@dillo.org>
|
||||
* Copyright (C) 2024 Rodrigo Arias Mallo <rodarima@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> /* for exit */
|
||||
#include <string.h> /* for memset */
|
||||
#include <unistd.h> /* for read and write */
|
||||
#include <ctype.h> /* for isxdigit */
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "../dlib/dlib.h"
|
||||
#include "../dpip/dpip.h"
|
||||
|
||||
#define MSG_ERR(...) printf("** ERROR **: " __VA_ARGS__);
|
||||
|
||||
char *CMD_REGISTER = "<cmd='register_all' '>";
|
||||
char *CMD_STOP = "<cmd='DpiBye' '>";
|
||||
|
||||
static char SharedKey[32];
|
||||
|
||||
static void print_usage(const char *prgname)
|
||||
{
|
||||
fprintf(stderr,"Control program for the Dillo plugin daemon\n"
|
||||
"Usage: %s {stop|register|chat}\n\n", prgname);
|
||||
}
|
||||
|
||||
static void error(char *msg)
|
||||
{
|
||||
perror(msg);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read dpid's communication keys from its saved file.
|
||||
* Return value: 1 on success, -1 on error.
|
||||
*/
|
||||
static int Dpi_read_comm_keys(int *port)
|
||||
{
|
||||
FILE *In;
|
||||
char *fname, *rcline = NULL, *tail;
|
||||
int i, ret = -1;
|
||||
|
||||
fname = dStrconcat(dGethomedir(), "/.dillo/dpid_comm_keys", NULL);
|
||||
if ((In = fopen(fname, "r")) == NULL) {
|
||||
MSG_ERR("[Dpi_read_comm_keys] %s\n", dStrerror(errno));
|
||||
} else if ((rcline = dGetline(In)) == NULL) {
|
||||
MSG_ERR("[Dpi_read_comm_keys] empty file: %s\n", fname);
|
||||
} else {
|
||||
*port = strtol(rcline, &tail, 10);
|
||||
for (i = 0; *tail && isxdigit(tail[i+1]); ++i)
|
||||
SharedKey[i] = tail[i+1];
|
||||
SharedKey[i] = 0;
|
||||
ret = 1;
|
||||
}
|
||||
dFree(rcline);
|
||||
dFree(fname);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int sockfd, portno, n;
|
||||
struct sockaddr_in serv_addr;
|
||||
char buffer[256];
|
||||
|
||||
if (argc != 2) {
|
||||
print_usage(argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Read dpid's port number from saved file */
|
||||
if (Dpi_read_comm_keys(&portno) == -1) {
|
||||
MSG_ERR("main: Can't read dpid's port number\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sockfd < 0)
|
||||
error("ERROR opening socket");
|
||||
memset(&serv_addr, 0, sizeof(serv_addr));
|
||||
serv_addr.sin_family = AF_INET;
|
||||
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
|
||||
|
||||
serv_addr.sin_port = htons(portno);
|
||||
if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
|
||||
error("ERROR connecting");
|
||||
|
||||
snprintf(buffer, sizeof(buffer), "<cmd='auth' msg='%s' '>", SharedKey);
|
||||
n = write(sockfd, buffer, strlen(buffer));
|
||||
if (n < 0)
|
||||
error("ERROR writing to socket");
|
||||
|
||||
if (strcmp(argv[1], "stop") == 0) {
|
||||
strcpy(buffer, CMD_STOP);
|
||||
} else if (strcmp(argv[1], "register") == 0) {
|
||||
strcpy(buffer, CMD_REGISTER);
|
||||
} else if (strcmp(argv[1], "chat") == 0) {
|
||||
printf("Please enter the message: ");
|
||||
memset(buffer,0,256);
|
||||
if (fgets(buffer,255,stdin) == NULL)
|
||||
MSG_ERR("dpidc: Can't read the message\n");
|
||||
} else {
|
||||
MSG_ERR("main: Unknown operation '%s'\n", argv[1]);
|
||||
print_usage(argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
n = write(sockfd,buffer,strlen(buffer));
|
||||
if (n < 0)
|
||||
error("ERROR writing to socket");
|
||||
/*
|
||||
memset(buffer,0,256);
|
||||
n = read(sockfd,buffer,255);
|
||||
if (n < 0)
|
||||
error("ERROR reading from socket");
|
||||
printf("%s\n",buffer);
|
||||
*/
|
||||
dClose(sockfd);
|
||||
return 0;
|
||||
}
|
5
dpid/dpidrc.in
Normal file
5
dpid/dpidrc.in
Normal file
@ -0,0 +1,5 @@
|
||||
dpi_dir=@libdir@/dillo/dpi
|
||||
|
||||
proto.file=file/file.dpi@EXEEXT@
|
||||
proto.ftp=ftp/ftp.filter.dpi@EXEEXT@
|
||||
proto.data=datauri/datauri.filter.dpi@EXEEXT@
|
422
dpid/main.c
Normal file
422
dpid/main.c
Normal file
@ -0,0 +1,422 @@
|
||||
/*
|
||||
Copyright (C) 2003 Ferdi Franceschini <ferdif@optusnet.com.au>
|
||||
Copyright (C) 2020 Axel Beckert <abe@debian.org>
|
||||
Copyright (C) 2023 Michal Grezl <walley@walley.org>
|
||||
Copyright (C) 2025 Rodrigo Arias Mallo <rodarima@gmail.com>
|
||||
|
||||
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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <errno.h> /* for ckd_write */
|
||||
#include <unistd.h> /* for ckd_write */
|
||||
#include <stdlib.h> /* for exit */
|
||||
#include <assert.h> /* for assert */
|
||||
#include <sys/stat.h> /* for umask */
|
||||
|
||||
#include "dpid_common.h"
|
||||
#include "dpid.h"
|
||||
#include "dpi.h"
|
||||
#include "dpi_socket_dir.h"
|
||||
#include "misc_new.h"
|
||||
|
||||
#include "../dlib/dlib.h"
|
||||
#include "../dpip/dpip.h"
|
||||
|
||||
sigset_t mask_sigchld;
|
||||
|
||||
/* fix for gcc 10 */
|
||||
|
||||
enum {
|
||||
no_errors,
|
||||
dpid_srs_addrinuse /* dpid service request socket address already in use */
|
||||
} dpi_errno;
|
||||
|
||||
char *srs_name;
|
||||
int numdpis;
|
||||
fd_set sock_set;
|
||||
struct dp *dpi_attr_list;
|
||||
Dlist *services_list;
|
||||
int numsocks;
|
||||
int srs_fd;
|
||||
|
||||
// end of fix
|
||||
|
||||
|
||||
/** 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.sock_fd, (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, (char*)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 (dClose(newsock) == -1) {
|
||||
ERRMSG("start_plugin", "close", errno);
|
||||
MSG_ERR("ERROR in child proc for %s\n", dpi_attr.path);
|
||||
exit(1);
|
||||
}
|
||||
dClose(STDIN_FILENO);
|
||||
dClose(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.sock_fd, STDIN_FILENO) == -1) {
|
||||
ERRMSG("start_plugin", "dup2", errno);
|
||||
MSG_ERR("ERROR in child proc for %s\n", dpi_attr.path);
|
||||
exit(1);
|
||||
}
|
||||
if (dClose(dpi_attr.sock_fd) == -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, (char*)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(Dsh *sh)
|
||||
{
|
||||
char *dpip_tag;
|
||||
|
||||
(void) sigprocmask(SIG_BLOCK, &mask_sigchld, NULL);
|
||||
dpip_tag = a_Dpip_dsh_read_token(sh, 1);
|
||||
(void) sigprocmask(SIG_UNBLOCK, &mask_sigchld, NULL);
|
||||
|
||||
return dpip_tag;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Get value of cmd field in dpi_tag
|
||||
* \Return
|
||||
* command code on success, -1 on failure
|
||||
*/
|
||||
static int get_command(Dsh *sh, char *dpi_tag)
|
||||
{
|
||||
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, "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");
|
||||
a_Dpip_dsh_write_str(sh, 1, d_cmd);
|
||||
dFree(d_cmd);
|
||||
COMMAND = -1;
|
||||
} else if (strcmp("auth", cmd) == 0) {
|
||||
COMMAND = AUTH_CMD;
|
||||
} 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
|
||||
*/
|
||||
static 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;
|
||||
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;
|
||||
services_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++)
|
||||
dClose(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);
|
||||
|
||||
#if 0
|
||||
/* 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);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Init and get services list */
|
||||
fill_services_list(dpi_attr_list, numdpis, &services_list);
|
||||
|
||||
/* Remove any sockets that may have been leftover from a crash */
|
||||
//cleanup();
|
||||
|
||||
/* Initialise sockets */
|
||||
if ((numsocks = init_ids_srs_socket()) == -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_socket failed", 0);
|
||||
ERRMSG("main", "init_ids_srs_socket failed", 0);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
numsocks = init_all_dpi_sockets(dpi_attr_list);
|
||||
est_dpi_terminator();
|
||||
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 (found %d dpis)\n", numdpis);
|
||||
/* 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();
|
||||
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_fd, &selected_set)) {
|
||||
int sock_fd;
|
||||
socklen_t sin_sz;
|
||||
struct sockaddr_in sin;
|
||||
char *req = NULL;
|
||||
|
||||
--n;
|
||||
assert(n >= 0);
|
||||
sin_sz = (socklen_t) sizeof(sin);
|
||||
sock_fd = accept(srs_fd, (struct sockaddr *)&sin, &sin_sz);
|
||||
if (sock_fd == -1) {
|
||||
ERRMSG("main", "accept", errno);
|
||||
MSG_ERR("accept on srs socket failed\n");
|
||||
MSG_ERR("service pending connections, and continue\n");
|
||||
} else {
|
||||
int command;
|
||||
Dsh *sh;
|
||||
|
||||
sh = a_Dpip_dsh_new(sock_fd, sock_fd, 1024);
|
||||
read_next:
|
||||
req = get_request(sh);
|
||||
command = get_command(sh, req);
|
||||
switch (command) {
|
||||
case AUTH_CMD:
|
||||
if (a_Dpip_check_auth(req) != -1) {
|
||||
dFree(req);
|
||||
goto read_next;
|
||||
}
|
||||
break;
|
||||
case BYE_CMD:
|
||||
stop_active_dpis(dpi_attr_list, numdpis);
|
||||
//cleanup();
|
||||
exit(0);
|
||||
break;
|
||||
case CHECK_SERVER_CMD:
|
||||
send_sockport(sock_fd, req, dpi_attr_list);
|
||||
break;
|
||||
case REGISTER_ALL_CMD:
|
||||
register_all_cmd();
|
||||
break;
|
||||
case UNKNOWN_CMD:
|
||||
{
|
||||
char *d_cmd = a_Dpip_build_cmd("cmd=%s msg=%s",
|
||||
"DpiError", "Unknown command");
|
||||
(void) CKD_WRITE(sock_fd, 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_Dpip_dsh_close(sh);
|
||||
a_Dpip_dsh_free(sh);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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].sock_fd, &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].sock_fd, &sock_set);
|
||||
if ((dpi_attr_list[i].pid = fork()) == -1) {
|
||||
ERRMSG("main", "fork", errno);
|
||||
/* exit(1); */
|
||||
} else if (dpi_attr_list[i].pid == 0) {
|
||||
/* child */
|
||||
(void) sigprocmask(SIG_SETMASK, &mask_none, NULL);
|
||||
start_server_plugin(dpi_attr_list[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
199
dpid/misc_new.c
Normal file
199
dpid/misc_new.c
Normal file
@ -0,0 +1,199 @@
|
||||
/*
|
||||
* File: misc_new.c
|
||||
*
|
||||
* Copyright 2008 Jorge Arellano Cid <jcid@dillo.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <errno.h> /* errno, err-codes */
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <sys/stat.h> /* stat */
|
||||
#include <stdlib.h> /* rand, srand */
|
||||
|
||||
#include "../dlib/dlib.h"
|
||||
#include "dpid_common.h"
|
||||
#include "misc_new.h" /* for function prototypes */
|
||||
|
||||
/*! 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;
|
||||
size_t i;
|
||||
size_t tagmem = 10;
|
||||
ssize_t rdln = 1;
|
||||
|
||||
tag = NULL;
|
||||
// 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;
|
||||
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.
|
||||
*/
|
||||
char *a_Misc_mkdtemp(char *template)
|
||||
{
|
||||
for (;;) {
|
||||
if (a_Misc_mkfname(template) && mkdir(template, 0700) == 0)
|
||||
break;
|
||||
if (errno == EEXIST)
|
||||
continue;
|
||||
return 0;
|
||||
}
|
||||
return template;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new, nonexistent file name from a template.
|
||||
* (adapted from dietlibc; alternative to mkdtemp())
|
||||
*/
|
||||
char *a_Misc_mkfname(char *template)
|
||||
{
|
||||
char *tmp = template + strlen(template) - 6;
|
||||
int i;
|
||||
uint_t random;
|
||||
struct stat stat_buf;
|
||||
|
||||
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 (stat(template, &stat_buf) == -1 && errno == ENOENT)
|
||||
return template;
|
||||
|
||||
MSG_ERR("a_Misc_mkfname: another round for %s \n", template);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new, random hexadecimal string of 'nchar' characters.
|
||||
*/
|
||||
char *a_Misc_mksecret(int nchar)
|
||||
{
|
||||
int i;
|
||||
uint_t random;
|
||||
char *secret = dNew(char, nchar + 1);
|
||||
|
||||
srand((uint_t)(time(0) ^ getpid()));
|
||||
random = (unsigned) rand();
|
||||
for (i = 0; i < nchar; ++i) {
|
||||
int hexdigit = (random >> (i * 5)) & 0x0f;
|
||||
|
||||
secret[i] = hexdigit > 9 ? hexdigit + 'a' - 10 : hexdigit + '0';
|
||||
}
|
||||
secret[i] = 0;
|
||||
MSG("a_Misc_mksecret: %s\n", secret);
|
||||
|
||||
return secret;
|
||||
}
|
||||
|
10
dpid/misc_new.h
Normal file
10
dpid/misc_new.h
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef MISC_NEW_H
|
||||
#define MISC_NEW_H
|
||||
|
||||
Dstr *a_Misc_rdtag(int socket);
|
||||
char *a_Misc_readtag(int sock);
|
||||
char *a_Misc_mkdtemp(char *template);
|
||||
char *a_Misc_mkfname(char *template);
|
||||
char *a_Misc_mksecret(int nchar);
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user