diff options
37 files changed, 2366 insertions, 3558 deletions
diff --git a/libproxy/CMakeLists.txt b/libproxy/CMakeLists.txt index e06ba82..b484309 100644 --- a/libproxy/CMakeLists.txt +++ b/libproxy/CMakeLists.txt @@ -1,5 +1,5 @@ ### Main library -add_library(libproxy SHARED array.cpp config_file.cpp misc.cpp module_manager.cpp pac.cpp proxy.cpp strdict.cpp url.cpp) +add_library(libproxy SHARED config_file.cpp dl_module.cpp module_manager.cpp module_types.cpp pac.cpp proxy.cpp url.cpp) target_link_libraries(libproxy m pthread dl) set_property(SOURCE proxy.cpp PROPERTY COMPILE_DEFINITIONS SYSCONFDIR="/etc/";MODULEDIR="${moduledir}") set_target_properties(libproxy PROPERTIES PREFIX "" COMPILE_FLAGS -g VERSION 0 SOVERSION 0.0.0) @@ -21,7 +21,7 @@ function(px_module name condition) endif() add_library(${name} MODULE modules/${name}.cpp) target_link_libraries(${name} libproxy) - set_target_properties(${name} PROPERTIES PREFIX "" COMPILE_FLAGS "-g -std=c99") + set_target_properties(${name} PROPERTIES PREFIX "" COMPILE_FLAGS -g) set_property(SOURCE modules/${name}.cpp PROPERTY COMPILE_DEFINITIONS SYSCONFDIR="/etc/";LIBEXECDIR="${libexecdir}";GCONFTOOLBIN="${GCONFTOOLBIN}") install(TARGETS ${name} LIBRARY DESTINATION ${rmoduledir}) if(${ARGC} GREATER 3) @@ -60,15 +60,15 @@ if(UNIX AND NOT APPLE) endif() if(X11_FOUND) px_check_modules(GNOME gconf-2.0) - find_package(KDE4) - if(${KDE4_FOUND} STREQUAL "TRUE") - set(KDE4_FOUND 1) - set(KDE4_LIBRARIES ${KDE4_KDECORE_LIBS}) - include_directories(${KDE4_INCLUDE_DIR}) - link_directories(${KDE4_LIB_DIR}) - else() - set(KDE4_FOUND 0) - endif() + #find_package(KDE4) + #if(${KDE4_FOUND} STREQUAL "TRUE") + # set(KDE4_FOUND 1) + # set(KDE4_LIBRARIES ${KDE4_KDECORE_LIBS}) + # include_directories(${KDE4_INCLUDE_DIR}) + # link_directories(${KDE4_LIB_DIR}) + #else() + # set(KDE4_FOUND 0) + #endif() endif() find_program(GCONFTOOLBIN gconftool-2) endif() @@ -86,11 +86,11 @@ if(UNIX AND NOT APPLE) px_module(network_networkmanager ${NM_FOUND} ${NM_LIBRARIES}) px_module(pacrunner_mozjs ${MOZJS_FOUND} ${MOZJS_LIBRARIES}) px_module(pacrunner_webkit ${WEBKIT_FOUND} ${WEBKIT_LIBRARIES}) -# if(GNOME_FOUND) -# add_executable(pxgconf src/modules/pxgconf.c) -# target_link_libraries(pxgconf ${GNOME_LIBRARIES}) -# install(TARGETS pxgconf RUNTIME DESTINATION ${rlibexecdir}) -# endif() + if(GNOME_FOUND) + add_executable(pxgconf modules/pxgconf.cpp) + target_link_libraries(pxgconf ${GNOME_LIBRARIES}) + install(TARGETS pxgconf RUNTIME DESTINATION ${rlibexecdir}) + endif() elseif(APPLE) px_module(pacrunner_webkit 2 ${WEBKIT_LIBRARIES}) px_module(pacrunner_macosx 2) diff --git a/libproxy/array.cpp b/libproxy/array.cpp deleted file mode 100644 index b4c7f23..0000000 --- a/libproxy/array.cpp +++ /dev/null @@ -1,157 +0,0 @@ -/******************************************************************************* - * libproxy - A library for proxy configuration - * Copyright (C) 2006 Nathaniel McCallum <nathaniel@natemccallum.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - ******************************************************************************/ - -#include <stdint.h> -#include <string.h> - -#include "misc.hpp" -#include "array.hpp" - -struct _pxArray { - pxArrayItemsEqual equals; - pxArrayItemCallback free; - bool unique; - bool replace; - unsigned int length; - void **data; -}; - -static bool -identity(void *a, void *b) -{ - return (a == b); -} - -static void -nothing(void *a) -{ - return; -} - -pxArray * -px_array_new(pxArrayItemsEqual equals, pxArrayItemCallback free, bool unique, bool replace) -{ - pxArray *self = (pxArray *) px_malloc0(sizeof(pxArray)); - self->equals = equals ? equals : &identity; - self->free = free ? free : ¬hing; - self->unique = unique; - self->replace = replace; - self->length = 0; - self->data = NULL; - return self; -} - -bool -px_array_add(pxArray *self, void *item) -{ - /* Verify some basic stuff */ - if (!self || !item) return false; - - /* If we are a unique array and a dup is found, either bail or replace the item */ - if (self->unique && px_array_find(self, item) >= 0) - { - if (!self->replace) - return false; - - self->free(self->data[px_array_find(self, item)]); - self->data[px_array_find(self, item)] = item; - return true; - } - - void **data = (void **) px_malloc0(sizeof(void *) * (self->length + 1)); - memcpy(data, self->data, sizeof(void *) * self->length); - data[self->length++] = item; - px_free(self->data); - self->data = data; - return true; -} - -bool -px_array_del(pxArray *self, const void *item) -{ - int index = px_array_find(self, item); - if (index < 0) return false; - - /* Free the old one and shift elements down */ - self->free(self->data[index]); - memmove(self->data+index, - self->data+index+1, - sizeof(void *) * (--self->length - index)); - - return true; -} - -void -px_array_foreach(pxArray *self, pxArrayItemCallbackWithArg cb, void *arg) -{ - for (int i=0 ; i < self->length ; i++) - cb(self->data[i], arg); -} - -int -px_array_find(pxArray *self, const void *item) -{ - if (!self || !item) return -1; - - for (int i=0 ; i < self->length ; i++) - if (self->equals(self->data[i], (void *) item)) - return i; - - return -1; -} - -const void * -px_array_get(pxArray *self, int index) -{ - if (!self) return NULL; - if (index < 0) index = self->length + index; - if (index < 0) return NULL; - if (index >= self->length) return NULL; - - return self->data[index]; -} - -void -px_array_free(pxArray *self) -{ - if (!self) return; - - // NOTE: We free in the reverse order of allocation - // This fixes an odd bug where dlopen()'d modules need - // to be dlclose()'d in the reverse order of their opening - for (int i=self->length-1 ; i >= 0 ; i--) - self->free(self->data[i]); - px_free(self->data); - px_free(self); -} - -int -px_array_length(pxArray *self) -{ - if (!self) return -1; - - return self->length; -} - -void -px_array_sort(pxArray *self, int (*compare)(const void *, const void *)) -{ - qsort(self->data, self->length, sizeof(void *), compare); -} - diff --git a/libproxy/array.hpp b/libproxy/array.hpp deleted file mode 100644 index d94b001..0000000 --- a/libproxy/array.hpp +++ /dev/null @@ -1,51 +0,0 @@ -/******************************************************************************* - * libproxy - A library for proxy configuration - * Copyright (C) 2006 Nathaniel McCallum <nathaniel@natemccallum.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - ******************************************************************************/ - -#ifndef ARRAY_H_ -#define ARRAY_H_ -#include <stdbool.h> - -typedef bool (*pxArrayItemsEqual)(void *, void *); -typedef void (*pxArrayItemCallback)(void *); -typedef void (*pxArrayItemCallbackWithArg)(void *, void *); -typedef struct _pxArray pxArray; - -__attribute__ ((visibility("default"))) -pxArray *px_array_new(pxArrayItemsEqual equals, pxArrayItemCallback free, bool unique, bool replace); - -__attribute__ ((visibility("default"))) -bool px_array_add(pxArray *self, void *item); - -bool px_array_del(pxArray *self, const void *item); - -void px_array_foreach(pxArray *self, pxArrayItemCallbackWithArg cb, void *arg); - -int px_array_find(pxArray *self, const void *item); - -__attribute__ ((visibility("default"))) -const void *px_array_get(pxArray *self, int index); - -__attribute__ ((visibility("default"))) -void px_array_free(pxArray *self); - -int px_array_length(pxArray *self); - -void px_array_sort(pxArray *self, int (*compare)(const void *, const void *)); - -#endif /* ARRAY_H_ */ diff --git a/libproxy/config_file.cpp b/libproxy/config_file.cpp index f13e570..ae3ede4 100644 --- a/libproxy/config_file.cpp +++ b/libproxy/config_file.cpp @@ -17,102 +17,85 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ******************************************************************************/ +#include <fstream> + #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> -#include <fcntl.h> -#include <string.h> -#include "misc.hpp" -#include "strdict.hpp" #include "config_file.hpp" -struct _pxConfigFile { - char *filename; - time_t mtime; - pxStrDict *sections; -}; +namespace com { +namespace googlecode { +namespace libproxy { -pxConfigFile * -px_config_file_new(char *filename) -{ - /* Open the file and stat it */ - struct stat st; - int fd = open(filename, O_RDONLY); - if (fd < 0) return NULL; - fstat(fd, &st); - - /* Allocate our structure; get mtime and filename */ - pxConfigFile *self = (pxConfigFile *) px_malloc0(sizeof(pxConfigFile)); - self->filename = px_strdup(filename); - self->mtime = st.st_mtime; - self->sections = px_strdict_new((pxStrDictItemCallback) px_strdict_free); - - /* Add one section (PX_CONFIG_FILE_DEFAULT_SECTION) */ - px_strdict_set(self->sections, PX_CONFIG_FILE_DEFAULT_SECTION, px_strdict_new(free)); - pxStrDict *current = (pxStrDict *) px_strdict_get(self->sections, PX_CONFIG_FILE_DEFAULT_SECTION); - - /* Parse our file */ - for (char *line=NULL ; (line = px_readline(fd, NULL, 0)) ; px_free(line) ) - { - if (*line) - { - /* Strip */ - char *tmp = px_strstrip(line); - px_free(line); line = tmp; - /* Check for comment and/or empty line */ - if (*line == '#' || !strcmp(line, "")) continue; - /* If we have a new section */ - if (*line == '[' || line[strlen(line)-1] == ']') - { - /* Get just the section name */ - memmove(line, line+1, strlen(line)-1); - line[strlen(line)-2] = '\0'; - if (px_strdict_get(self->sections, line)) - current = (pxStrDict *) px_strdict_get(self->sections, line); - else - { - px_strdict_set(self->sections, line, px_strdict_new(free)); - current = (pxStrDict *) px_strdict_get(self->sections, line); - } - - } - - /* If this is a key/val line, get the key/val. */ - else if ((tmp = strchr(line, '=')) && tmp[1]) - { - *tmp = '\0'; - char *key = px_strstrip(line); - px_strdict_set(current, key, px_strstrip(tmp+1)); - px_free(key); - } - } - } - close(fd); - return self; -} +#define PX_CONFIG_FILE_DEFAULT_SECTION "__DEFAULT__" -bool -px_config_file_is_stale(pxConfigFile *self) -{ - struct stat st; - return (!stat(self->filename, &st) && st.st_mtime > self->mtime); +static string trim(string str, const char *set) { + const string::size_type first = str.find_first_not_of(set); + if (first != string::npos) + str = str.substr(first, str.find_last_not_of(set)-first+1); + return str; } -char * -px_config_file_get_value(pxConfigFile *self, char *section, char *key) -{ - return px_strdup((const char *) px_strdict_get((pxStrDict *) px_strdict_get(self->sections, section), key)); +string config_file::get_value(const string key) throw (key_error) { + return this->get_value(PX_CONFIG_FILE_DEFAULT_SECTION, key); } -void -px_config_file_free(pxConfigFile *self) -{ - if (!self) return; +string config_file::get_value(const string section, const string key) throw (key_error) { + if (this->sections.find(section) == this->sections.end()) + throw key_error(string("Section not found: ") + section); + if (this->sections[section].find(key) == this->sections[section].end()) + throw key_error(string("Key not found in section: ") + section); + return this->sections[section][key]; +} - px_strdict_free(self->sections); - px_free(self->filename); - px_free(self); +bool config_file::is_stale() { + struct stat st; + return (!stat(this->filename.c_str(), &st) && st.st_mtime > this->mtime); } +bool config_file::load(string filename) { + // Stat the file and get its mtime + struct stat st; + if (stat(filename.c_str(), &st)) + return false; + this->filename = filename; + this->mtime = st.st_mtime; + + // Open the file + ifstream file(filename.c_str()); + if (!file.is_open()) + return false; + + string current = PX_CONFIG_FILE_DEFAULT_SECTION; + for (string line="" ; !file.eof() ; getline(file, line)) { + if (file.fail()) { + this->sections.clear(); + file.close(); + return false; + } + + // Strip the line + line = trim(line, " \t"); + + // Check for comment and/or empty line + if (line[0] == '#' || line[0] == ';' || line == "") continue; + + // If we have a new section, get the current section name + if (line[0] == '[' || line[line.size()-1] == ']') + current = trim(line, "[]"); + + // Otherwise set our value + else if (line.find('=') != string::npos) + this->sections[current][line.substr(0, line.find('='))] = line.substr(line.find('=')+1); + } + + file.close(); + return true; +} + +} +} +} diff --git a/libproxy/config_file.hpp b/libproxy/config_file.hpp index 4d578bd..0be5045 100644 --- a/libproxy/config_file.hpp +++ b/libproxy/config_file.hpp @@ -1,38 +1,53 @@ /******************************************************************************* * libproxy - A library for proxy configuration * Copyright (C) 2006 Nathaniel McCallum <nathaniel@natemccallum.com> - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. - * + * * This library 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 * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ******************************************************************************/ -#ifndef CONFIG_FILE_H_ -#define CONFIG_FILE_H_ +#ifndef CONFIG_FILE_HPP_ +#define CONFIG_FILE_HPP_ -#include <stdbool.h> +#include <stdexcept> +#include <map> +using namespace std; -#define PX_CONFIG_FILE_DEFAULT_SECTION "__DEFAULT__" +namespace com { +namespace googlecode { +namespace libproxy { -typedef struct _pxConfigFile pxConfigFile; +class key_error : public runtime_error { +public: + key_error(const string& __arg): runtime_error(__arg) {} +}; -__attribute__ ((visibility("default"))) -pxConfigFile *px_config_file_new (char *filename); -__attribute__ ((visibility("default"))) -bool px_config_file_is_stale (pxConfigFile *self); -__attribute__ ((visibility("default"))) -char *px_config_file_get_value (pxConfigFile *self, char *section, char *key); -__attribute__ ((visibility("default"))) -void px_config_file_free (pxConfigFile *self); +class config_file { +public: + string get_value(const string key) throw (key_error); + string get_value(const string section, const string key) throw (key_error); + bool is_stale(); + bool load(string filename); -#endif /*CONFIG_FILE_H_*/ +private: + string filename; + time_t mtime; + map<string, map<string, string> > sections; +}; + +} +} +} + +#endif /*CONFIG_FILE_HPP_*/ diff --git a/libproxy/dl_module.cpp b/libproxy/dl_module.cpp new file mode 100644 index 0000000..ccceb44 --- /dev/null +++ b/libproxy/dl_module.cpp @@ -0,0 +1,82 @@ +/******************************************************************************* + * libproxy - A library for proxy configuration + * Copyright (C) 2009 Nathaniel McCallum <nathaniel@natemccallum.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + ******************************************************************************/ + +#include "dl_module.hpp" + +#ifdef _WIN32 +#include <windows.h> +#define pdlmtype HMODULE +#define pdlopen(filename) LoadLibrary(filename) +#define pdlsym GetProcAddress +#define pdlclose FreeLibrary +static std::string pdlerror() { + std::string e; + LPTSTR msg; + + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER |FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + &msg, + 0, + NULL); + e = std::string(msg); + LocalFree(msg); + return e; +} + +#else +#include <dlfcn.h> +#define pdlmtype void* +#define pdlopen(filename) dlopen(filename, RTLD_NOW | RTLD_LOCAL) +#define pdlsym dlsym +#define pdlclose dlclose +static std::string pdlerror() { return std::string(dlerror()); } +#endif + +namespace com { +namespace googlecode { +namespace libproxy { +using namespace std; + +dl_module::~dl_module() { + pdlclose((pdlmtype) this->dlobject); +} + +dl_module::dl_module(const string filename) throw (dl_error) { + this->dlobject = pdlopen(filename.c_str()); + if (!this->dlobject) + throw dl_error(pdlerror()); +} + +bool dl_module::operator==(const dl_module& module) const { + return (this->dlobject == module.dlobject); +} + +void* dl_module::getsym(const string symbolname) const throw (dl_error) { + void*sym = pdlsym((pdlmtype) this->dlobject, symbolname.c_str()); + if (!sym) + throw dl_error("Symbol not found: " + symbolname); + return sym; +} + +} +} +} diff --git a/libproxy/strdict.hpp b/libproxy/dl_module.hpp index 01829e7..5ed1cb0 100644 --- a/libproxy/strdict.hpp +++ b/libproxy/dl_module.hpp @@ -1,39 +1,54 @@ /******************************************************************************* * libproxy - A library for proxy configuration - * Copyright (C) 2006 Nathaniel McCallum <nathaniel@natemccallum.com> - * + * Copyright (C) 2009 Nathaniel McCallum <nathaniel@natemccallum.com> + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. - * + * * This library 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 * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ******************************************************************************/ -#include <stdbool.h> - -typedef void (*pxStrDictItemCallback)(void *); -typedef void (*pxStrDictForeachCallback)(const char *, void *, void *); - -typedef struct _pxStrDict pxStrDict; - -__attribute__ ((visibility("default"))) -pxStrDict *px_strdict_new(pxStrDictItemCallback free); - -__attribute__ ((visibility("default"))) -bool px_strdict_set(pxStrDict *self, const char *key, void *value); - -__attribute__ ((visibility("default"))) -const void *px_strdict_get(pxStrDict *self, const char *key); - -void px_strdict_foreach(pxStrDict *self, pxStrDictForeachCallback *cb, void *arg); - -__attribute__ ((visibility("default"))) -void px_strdict_free(pxStrDict *self); +#ifndef DLOBJECT_HPP_ +#define DLOBJECT_HPP_ + +#include <string> +#include <stdexcept> + +namespace com { +namespace googlecode { +namespace libproxy { + +using namespace std; + +class dl_error : public runtime_error { +public: + dl_error(const string& __arg): runtime_error(__arg) {} +}; + +class dl_module { + public: + ~dl_module(); + dl_module(const string filename) throw (dl_error); + bool operator==(const dl_module& module) const; + template <class T> T get_symbol(const string symbolname) const throw (dl_error) { + return (T) this->getsym(symbolname); + } + + private: + void* getsym(const string symbolname) const throw (dl_error); + void* dlobject; + }; +} +} +} + +#endif /* DLOBJECT_HPP_ */ diff --git a/libproxy/misc.cpp b/libproxy/misc.cpp deleted file mode 100644 index 2c79eba..0000000 --- a/libproxy/misc.cpp +++ /dev/null @@ -1,295 +0,0 @@ -/******************************************************************************* - * libproxy - A library for proxy configuration - * Copyright (C) 2006 Nathaniel McCallum <nathaniel@natemccallum.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - ******************************************************************************/ - -#include <assert.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <ctype.h> -#include <stdarg.h> - -#include "misc.hpp" - -/** - * Allocates memory and always returns valid memory. - * @size Amount of memory to allocate in bytes - * @return Pointer to the allocated memory - */ -__attribute__ ((visibility("default"))) -void * -px_malloc0(size_t size) -{ - void *mem = malloc(size); - assert(mem != NULL); - memset(mem, 0, size); - return mem; -} - -/** - * Frees memory and doesn't crash if that memory is NULL - * @mem Memory to free or NULL - */ -__attribute__ ((visibility("default"))) -void -px_free(void *mem) -{ - if (!mem) return; - free(mem); -} - -/** - * Duplicates the first n characters of the string s - * @s String to duplicate - * @n Number of characters of the string to duplicate - * @return Newly allocated string - */ -char * -px_strndup(const char *s, size_t n) -{ - if (!s) return NULL; - char *tmp = (char *) px_malloc0(n+1); - strncpy(tmp, s, n); - return tmp; -} - -/** - * Duplicates a string - * @s String to duplicate - * @return Newly allocated string - */ -char * -px_strdup(const char *s) -{ - if (!s) return NULL; - return px_strndup(s, strlen(s)); -} - -/** - * Duplicates a string vector - * @sv String vector to duplicate - * @return Newly allocated string vector (free w/ px_strfreev()) - */ -char ** -px_strdupv(const char **sv) -{ - int count; - - if (!sv) return NULL; - for (count=0 ; sv[count] ; count++); - - char **output = (char **) px_malloc0(sizeof(char *) * ++count); - for (int i=0 ; sv[i] ; i++) - output[i] = px_strdup(sv[i]); - - return output; -} - -/** - * Concatenates two or more strings into a newly allocated string - * @s The first string to concatenate. - * @... Subsequent strings. The last argument must be NULL. - * @return Newly allocated string - */ -char * -px_strcat(const char *s, ...) -{ - va_list args; - - /* Count the number of characters to concatentate */ - va_start(args, s); - int count = strlen(s); - for (char *tmp = NULL ; (tmp = va_arg(args, char *)) ; count += strlen(tmp)); - va_end(args); - - /* Build our output string */ - char *output = (char *) px_malloc0(count + 1); - strcat(output, s); - va_start(args, s); - for (char *tmp = NULL ; (tmp = va_arg(args, char *)) ; ) - strcat(output, tmp); - va_end(args); - - return output; -} - -/** - * Joins NULL terminated array of strings into one string separated by delimiter - * @strv NULL terminated array of string to join - * @delimiter The string to use in between each string in the array - * @return Newly allocated string - */ -char * -px_strjoin(const char **strv, const char *delimiter) -{ - if (!strv) return NULL; - if (!delimiter) return NULL; - - /* Count up the length we need */ - size_t length = 0; - for (int i=0 ; strv[i]; i++) - length += strlen(strv[i]) + strlen(delimiter); - if (!length) return NULL; - - /* Do the join */ - char *str = (char *) px_malloc0(length); - for (int i=0 ; strv[i]; i++) - { - strcat(str, strv[i]); - if (strv[i+1]) strcat(str, delimiter); - } - return str; -} - -/** - * Splits a string into a NULL terminated array based on delimiter - * @string The string to split - * @delimiter The delimiter to split on - * @return The NULL terminated array (free with px_strfreev()) - */ -char ** -px_strsplit(const char *string, const char *delimiter) -{ - /* if string is empty, return NULL */ - if (!string) return NULL; - - /* Count how many times the delimiter appears */ - int count = 1; - for (const char *tmp = string ; (tmp = strstr(tmp, delimiter)) ; tmp += strlen(delimiter)) - count++; - - /* Allocate the vector */ - char **strv = (char **) px_malloc0(sizeof(char *) * (count + 1)); - - /* Fill the vector */ - const char *last = string; - for (int i=0 ; i < count ; i++) - { - const char *tmp = strstr(last, delimiter); - if (!tmp) - strv[i] = px_strdup(last); - else - { - strv[i] = px_strndup(last, tmp - last); - last = tmp + strlen(delimiter); - } - } - - return strv; -} - -/** - * Frees the memory used by a NULL terminated string array - * @strv The NULL terminated string array - */ -void -px_strfreev(char **strv) -{ - if (!strv) return; - for (int i=0 ; *(strv + i) ; i++) - px_free(*(strv + i)); - px_free(strv); -} - -/** - * Reads a single line of text from the specified file descriptor - * @fd File descriptor to read from - * @buffer The buffer to write to (usually NULL) - * @bufsize The size of the buffer (usually 0) - * @return Newly allocated string containing one line only - */ -char * -px_readline(int fd, char *buffer, size_t bufsize) -{ - char c = '\0'; - - /* Verify we have an open socket */ - if (fd < 0) return NULL; - - /* Read a character. If we don't get a character, return the buffer. */ - if (read(fd, &c, 1) != 1) return buffer; - - /* If we are at the end of the line, return. */ - if (c == '\n') return buffer ? buffer : px_strdup(""); - - /* We have a character, make sure we have a buffer. */ - if (!buffer) - { - buffer = px_strdup(""); - bufsize = 0; - } - - /* If our buffer is full, add more to the buffer. */ - if (bufsize <= strlen(buffer)) - { - char *tmp = (char *) px_malloc0(1024 + strlen(buffer) + 1); - strcpy(tmp, buffer); - free(buffer); - buffer = tmp; - bufsize = strlen(buffer) + 1024; - } - - strncat(buffer, &c, 1); - return px_readline(fd, buffer, bufsize); -} - -/** - * Trims off all the leading whitespace characters - * @string The string to strip - * @return A newly allocated copy of string without all the leading whitespace - */ -char * -px_strlstrip(char *string) -{ - for (int i=0 ; string[i] ; i++) - if (!isspace(string[i])) - return px_strdup(string + i); - return px_strdup(""); -} - -/** - * Trims off all the trailing whitespace characters - * @string The string to strip - * @return A newly allocated copy of string without all the trailing whitespace - */ -char * -px_strrstrip(char *string) -{ - char *tmp = string = px_strdup(string); - - for (int i=0 ; string[i] ; i++) - if (!isspace(string[i])) - tmp = string + i; - tmp[1] = '\0'; - return string; -} - -/** - * Trims off all the leading and trailing whitespace characters - * @string The string to strip - * @return A newly allocated copy of string without all the leading and trailing whitespace - */ -char * -px_strstrip(char *string) -{ - char *tmp = px_strrstrip(string); - string = px_strlstrip(tmp); - px_free(tmp); - return string; -} diff --git a/libproxy/module_manager.cpp b/libproxy/module_manager.cpp index 4a18136..201fc76 100644 --- a/libproxy/module_manager.cpp +++ b/libproxy/module_manager.cpp @@ -17,181 +17,137 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ******************************************************************************/ -#include <stdio.h> -#include <stdlib.h> -#include <libgen.h> -#include <string.h> -#include <dirent.h> -#include <math.h> - -#ifdef _WIN32 -#include <windows.h> -#define pdlmtype HMODULE -#define pdlopen(filename) LoadLibrary(filename) -#define pdlsym GetProcAddress -#define pdlclose FreeLibrary -#else -#include <dlfcn.h> -#define pdlmtype void * -#define pdlopen(filename) dlopen(filename, RTLD_NOW | RTLD_LOCAL) -#define pdlsym dlsym -#define pdlclose dlclose -#endif +#include <sys/stat.h> // For stat() +#include <dirent.h> // For opendir(), readdir(), closedir() #include "module_manager.hpp" -#include "misc.hpp" -#include "array.hpp" -#include "strdict.hpp" -struct _pxModuleManager { - pxArray *dlmodules; - pxStrDict *registrations; - pxStrDict *types; -}; +namespace com { +namespace googlecode { +namespace libproxy { +using namespace std; -typedef struct _pxModuleTypeRegistration { - pxModuleRegistrationComparison cmp; - bool sngl; -} pxModuleTypeRegistration; +static vector<string> strsplit(const char* cstr, string delimiter) { + vector<string> v; + string str = cstr ? cstr : ""; -static void -regfree(pxModuleRegistration *self) -{ - px_free(self->name); - if (self->instance) - self->free(self->instance); - px_free(self); -} + for (int i=str.find(delimiter) ; i != string::npos ; i=str.find(delimiter)) { + v.push_back(str.substr(0, i)); + str = str.substr(i+delimiter.size()); + } + if (str != "") + v.push_back(str); -static bool -regeq(pxModuleRegistration *self, pxModuleRegistration *other) -{ - return !strcmp(self->name, other->name); + return v; } -static char * -basename_noext(const char *filename) -{ - char *tmp = px_strdup(filename); - filename = px_strdup(basename(tmp)); - px_free(tmp); - if (strrchr(filename, '.')) - ((char *) strrchr(filename, '.'))[0] = '\0'; - return (char *) filename; +static string basename_noext(string filename) { + // Basename + if (filename.find_last_of("/\\") != string::npos) + filename = filename.substr(filename.find_last_of("/\\")+1); + + // Noext + if (filename.rfind(".") != string::npos) + return filename.substr(0, filename.rfind(".")); + return filename; } -static bool -globmatch(const char *glob, const char *string) +static bool globmatch(string glob, string str) { - if (!glob) return false; - if (!string) return false; - - char **segments = px_strsplit(glob, "*"); - for (int i=0 ; segments[i] ; i++) + vector<string> segments = strsplit(glob.c_str(), "*"); + for (vector<string>::iterator i=segments.begin() ; i != segments.end() ; i++) { + // Handle when the glob does not end with '*' + // (insist the segment match the end of the string) + if (i == segments.end() && *i != "" && str != "") + return false; + // Search for this segment in this string - const char *offset = strstr(string, segments[i]); + int offset = str.find(*i); // If the segment isn't found at all, its not a match - if (!offset) - goto nomatch; + if (offset == string::npos) + return false; // Handle when the glob does not start with '*' // (insist the segment match the start of the string) - if (i == 0 && strcmp(segments[i], "") && offset != string) - goto nomatch; + if (i == segments.begin() && *i != "" && offset != 0) + return false; // Increment further into the string - string = offset + strlen(segments[i]); - - // Handle when the glob does not end with '*' - // (insist the segment match the end of the string) - if (!segments[i+1] && strcmp(segments[i], "") && string[0]) - goto nomatch; + str = str.substr(offset + i->size()); } - px_strfreev(segments); return true; - - nomatch: - px_strfreev(segments); - return false; } -pxModuleManager * -px_module_manager_new() -{ - pxModuleManager *self = (pxModuleManager *) px_malloc0(sizeof(pxModuleManager)); - self->dlmodules = px_array_new(NULL, (pxArrayItemCallback) pdlclose, true, false); - self->registrations = px_strdict_new((pxStrDictItemCallback) px_array_free); - self->types = px_strdict_new((pxStrDictItemCallback) px_free); - return self; +string module::_bnne(const string fn) const { + return basename_noext(fn); } -void -px_module_manager_free(pxModuleManager *self) -{ - px_strdict_free(self->types); - px_strdict_free(self->registrations); - px_array_free(self->dlmodules); - px_free(self); +module_manager::~module_manager() { + // Free all modules + for (map<const type_info*, vector<module*> >::iterator i=this->modules.begin() ; i != this->modules.end() ; i++) { + for (vector<module*>::iterator j=i->second.begin() ; j != i->second.end() ; j++) + delete *j; + i->second.clear(); + } + this->modules.clear(); + + // Free all dl_modules + for (set<dl_module*>::iterator i=this->dl_modules.begin() ; i != this->dl_modules.end() ; i++) + delete *i; + this->dl_modules.clear(); } -bool -px_module_manager_load(pxModuleManager *self, char *filename) -{ - pxModuleLoadFunction load; - if (!self) return false; - if (!filename) return false; +bool module_manager::load_file(const string filename) { + dl_module* dlobj = NULL; + module_manager::INIT_TYPE load; + + // Stat the file to make sure it is a file + struct stat st; + if (stat(filename.c_str(), &st) != 0) return false; + if (!S_ISREG(st.st_mode)) return false; // Prepare for blacklist check - char **blacklist = px_strsplit(getenv("PX_MODULE_BLACKLIST"), ","); - char **whitelist = px_strsplit(getenv("PX_MODULE_WHITELIST"), ","); - char *modname = basename_noext(filename); - bool doload = true; + vector<string> blacklist = strsplit(getenv("PX_MODULE_BLACKLIST"), ","); + vector<string> whitelist = strsplit(getenv("PX_MODULE_WHITELIST"), ","); + string modname = basename_noext(filename); + bool doload = true; // Check our whitelist/blacklist to see if we should load this module - for (int i=0 ; blacklist && blacklist[i]; i++) - if (globmatch(blacklist[i], modname)) + for (vector<string>::iterator i=blacklist.begin() ; i != blacklist.end() ; i++) + if (globmatch(*i, modname)) doload = false; - for (int i=0 ; whitelist && whitelist[i]; i++) - if (globmatch(whitelist[i], modname)) + for (vector<string>::iterator i=whitelist.begin() ; i != whitelist.end() ; i++) + if (globmatch(*i, modname)) doload = true; - // Cleanup - px_strfreev(blacklist); - px_strfreev(whitelist); - px_free(modname); - if (!doload) return false; - /* Load the module */ - pdlmtype module = pdlopen(filename); - if (!module) goto error; + // Load the module + dlobj = new dl_module (filename); - /* Make sure this module is unique */ - if (px_array_find(self->dlmodules, module) >= 0) goto error; + // Insert the module + if (this->dl_modules.insert(dlobj).second == false) { + delete dlobj; + return false; + } - /* Call the px_module_load() function */ - load = (pxModuleLoadFunction) pdlsym(module, "px_module_load"); - if (!load || !load(self)) goto error; + // Call the INIT function + load = dlobj->get_symbol<module_manager::INIT_TYPE>(module_manager::INIT_NAME()); + if (!load || !load(*this)) { + this->dl_modules.erase(dlobj); + delete dlobj; + return false; + } - if (!px_array_add(self->dlmodules, module)) goto error; return true; - -error: - if (module) pdlclose(module); - return false; } -bool -px_module_manager_load_dir(pxModuleManager *self, char *dirname) -{ - if (!self) return false; - if (!dirname) return false; - +bool module_manager::load_dir(const string dirname) { /* Open the module dir */ - DIR *moduledir = opendir(dirname); + DIR *moduledir = opendir(dirname.c_str()); if (!moduledir) return false; /* For each module... */ @@ -200,88 +156,14 @@ px_module_manager_load_dir(pxModuleManager *self, char *dirname) for (int i=0 ; (ent = readdir(moduledir)) ; i++) { /* Load the module */ - char *tmp = px_strcat(dirname, "/", ent->d_name, NULL); - loaded = px_module_manager_load(self, tmp) || loaded; - px_free(tmp); + string tmp = dirname + "/" + ent->d_name; + loaded = this->load_file(tmp) || loaded; + } closedir(moduledir); return loaded; } -bool -_px_module_manager_register_module_full(pxModuleManager *self, - const char *id, - const char *name, - size_t namelen, - pxModuleConstructor _new, - pxModuleDestructor free) -{ - if (!self) return false; - if (!id) return false; - if (!name) return false; - if (!_new) return false; - - // Ensure only a single registration in the case of a singleton - pxModuleTypeRegistration *tr = (pxModuleTypeRegistration *) px_strdict_get(self->types, id); - if (tr && tr->sngl && px_array_length((pxArray *) px_strdict_get(self->registrations, id)) > 0) - return false; - - pxModuleRegistration *reg = (pxModuleRegistration *) px_malloc0(sizeof(pxModuleRegistration)); - reg->name = px_strndup(name, namelen); - reg->pxnew = _new; - reg->free = free; - - // Create a new empty array if there is no registrations for this id - if (!px_strdict_get(self->registrations, id)) - px_strdict_set(self->registrations, id, px_array_new((pxArrayItemsEqual) regeq, (pxArrayItemCallback) regfree, true, true)); - - // Add the module to the registrations for this id - pxArray *registrations = (pxArray *) px_strdict_get(self->registrations, id); - return px_array_add(registrations, reg); } - -void ** -_px_module_manager_instantiate_type_full(pxModuleManager *self, - const char *id) -{ - if (!self) return NULL; - if (!id) return NULL; - - // Find the array of registrations for this id - pxArray *regs = (pxArray *) px_strdict_get(self->registrations, id); - if (!regs || px_array_length(regs) < 1) return NULL; - - // Make sure we have an instance for each of our registrations - for (int i=0 ; i < px_array_length(regs) ; i++) - { - pxModuleRegistration *reg = (pxModuleRegistration *) px_array_get(regs, i); - if (!reg->instance) - reg->instance = reg->pxnew(); - } - - // Sort the instances - if (px_strdict_get(self->types, id)) - px_array_sort(regs, (int (*)(const void*, const void*)) ((pxModuleTypeRegistration *) px_strdict_get(self->types, id))->cmp); - - // Allocate our instances array - void **instances = (void **) px_malloc0(sizeof(void *) * (px_array_length(regs) + 1)); - for (int i=0 ; i < px_array_length(regs) ; i++) - instances[i] = ((pxModuleRegistration *) px_array_get(regs, i))->instance; - return instances; } - -bool -_px_module_manager_register_type_full(pxModuleManager *self, - const char *id, - pxModuleRegistrationComparison cmp, - bool singleton) -{ - if (!self) return false; - if (!id) return false; - if (!cmp && !singleton) return true; - - pxModuleTypeRegistration *tr = (pxModuleTypeRegistration *) px_malloc0(sizeof(pxModuleTypeRegistration)); - tr->cmp = cmp; - tr->sngl = singleton; - return px_strdict_set(self->types, id, tr); } diff --git a/libproxy/module_manager.hpp b/libproxy/module_manager.hpp index edc82f0..9c7ce4d 100644 --- a/libproxy/module_manager.hpp +++ b/libproxy/module_manager.hpp @@ -17,61 +17,103 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ******************************************************************************/ -#ifndef MODULE_MANAGER_H_ -#define MODULE_MANAGER_H_ - -#include <stdbool.h> -#include <assert.h> - -/* - * Define the pxModuleManager object - */ -typedef struct _pxModuleManager pxModuleManager; -typedef void *(*pxModuleConstructor)(); -typedef void (*pxModuleDestructor) (void *module); - -typedef bool (*pxModuleLoadFunction)(pxModuleManager *); -typedef void (*pxModuleFreeFunction)(pxModuleManager *); - - -/* - * Define the pxModuleRegistration object - */ -struct _pxModuleRegistration { - char *name; - void *instance; - pxModuleConstructor pxnew; - pxModuleDestructor free; +#ifndef MODULEMANAGER_HPP_ +#define MODULEMANAGER_HPP_ + +#include <map> +#include <set> +#include <vector> +#include <typeinfo> +#include <algorithm> + +#include "dl_module.hpp" + +#define PX_MODULE_ID(name) virtual string get_id() const { return this->_bnne(name ? name : __FILE__); } +#define PX_MODULE_LOAD(basetype, name, cond) \ + extern "C" bool px_module_load(module_manager& mm) { \ + if (cond) return mm.register_module<basetype>(new name ## _ ## basetype); \ + return false; \ + } + +namespace com { +namespace googlecode { +namespace libproxy { +using namespace std; + +class module { +public: + virtual ~module() {} + virtual bool operator<(const module& other) const { return false; } + virtual string get_id() const=0; + +protected: + string _bnne(const string fn) const; }; -typedef struct _pxModuleRegistration pxModuleRegistration; -typedef int (*pxModuleRegistrationComparison)(pxModuleRegistration **self, pxModuleRegistration **other); -pxModuleManager *px_module_manager_new (); -void px_module_manager_free (pxModuleManager *self); +class module_manager { +public: + typedef bool (*INIT_TYPE)(module_manager&); + static const char* INIT_NAME() { return "px_module_load"; } + + ~module_manager(); + + template <class T> vector<T*> get_modules() const { + vector<module*> modlist = this->modules.find(&typeid(T))->second; + vector<T*> retlist; -bool px_module_manager_load (pxModuleManager *self, char *filename); -bool px_module_manager_load_dir (pxModuleManager *self, char *dirname); + for (int i=0 ; i < modlist.size() ; i++) + retlist.push_back(dynamic_cast<T*>(modlist[i])); -#define __str__(s) #s -#define __px_module_manager_get_id(type, version) #type "__" __str__(version) + return retlist; + } -__attribute__ ((visibility("default"))) -bool _px_module_manager_register_module_full(pxModuleManager *self, const char *id, const char *name, size_t namelen, pxModuleConstructor pxnew, pxModuleDestructor free); -#define px_module_manager_register_module(self, type, pxnew, free) \ - _px_module_manager_register_module_full(self, __px_module_manager_get_id(type, type ## Version), \ - __FILE__, strrchr(__FILE__, '.') ? strrchr(__FILE__, '.') - __FILE__ : strlen(__FILE__), \ - pxnew, free) -#define px_module_manager_register_module_with_name(self, type, name, pxnew, free) \ - _px_module_manager_register_module_full(self, __px_module_manager_get_id(type, type ## Version), name, strlen(name), pxnew, free) + template <class T> bool register_module(T* module) { + struct pcmp { + static bool cmp(T* x, T* y) { return *x < *y; } + }; -void **_px_module_manager_instantiate_type_full(pxModuleManager *self, const char *id); -#define px_module_manager_instantiate_type(self, type) \ - (type **) _px_module_manager_instantiate_type_full(self, __px_module_manager_get_id(type, type ## Version)) + // If the class for this module is a singleton... + if (this->singletons.find(&typeid(T)) != this->singletons.end()) { + // ... and we already have an instance of this class ... + if (this->modules[&typeid(T)].size() > 0) { + // ... free the module and return + delete module; + return false; + } + } -bool _px_module_manager_register_type_full(pxModuleManager *self, const char *id, pxModuleRegistrationComparison cmp, bool singleton); -#define px_module_manager_register_type(self, type, cmp, sngl) \ - _px_module_manager_register_type_full(self, __px_module_manager_get_id(type, type ## Version), cmp, sngl) + // Otherwise we just add the module and sort + vector<T*> modlist = this->get_modules<T>(); + modlist.push_back(module); + sort(modlist.begin(), modlist.end(), &pcmp::cmp); + + // Insert to our store + this->modules[&typeid(T)].clear(); + for (int i=0 ; i < modlist.size() ; i++) + this->modules[&typeid(T)].push_back(modlist[i]); + + return true; + + } + + template <class T> bool set_singleton(bool singleton) { + if (singleton) + return this->singletons.insert(&typeid(T)).second; + this->singletons.erase(&typeid(T)); + return true; + } + + bool load_file(const string filename); + bool load_dir(const string dirname); + +private: + set<dl_module*> dl_modules; + map<const type_info*, vector<module*> > modules; + set<const type_info*> singletons; +}; -#define PX_MODULE_SUBCLASS(type) type __parent__ +} +} +} -#endif /* MODULE_MANAGER_H_ */ +#endif /* MODULEMANAGER_HPP_ */ diff --git a/libproxy/module_types.cpp b/libproxy/module_types.cpp new file mode 100644 index 0000000..c5c2b70 --- /dev/null +++ b/libproxy/module_types.cpp @@ -0,0 +1,123 @@ +/******************************************************************************* + * libproxy - A library for proxy configuration + * Copyright (C) 2009 Nathaniel McCallum <nathaniel@natemccallum.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + ******************************************************************************/ + +#include "module_types.hpp" + +namespace com { +namespace googlecode { +namespace libproxy { +using namespace std; + +static const char *DEFAULT_CONFIG_ORDER[] = { + "USER", + "SESSION", + "SYSTEM", + "config_envvar", + "config_wpad", + NULL +}; + +static const char *DEFAULT_WPAD_ORDER[] = { + "wpad_dhcp", + "wpad_slp", + "wpad_dns", + "wpad_dnsdevolution", + NULL +}; + +static inline int _config_module_findpos(config_module::category category, string id, string order) { + if (order == "") + return 0; + + size_t next = order.find(","); + string segment = order.substr(0, next); + + if ((segment == "USER" && config_module::CATEGORY_USER == category) || + (segment == "SESSION" && config_module::CATEGORY_SESSION == category) || + (segment == "SYSTEM" && config_module::CATEGORY_SYSTEM == category) || + (segment == id)) + return 0; + + return 1 + _config_module_findpos(category, id, order.substr(next == string::npos ? string::npos : next+1)); +} + +string config_module::get_ignore(url url) { + return ""; +} + +bool config_module::set_creds(url proxy, string username, string password) { + return false; +} + +bool config_module::operator<(const config_module& module) const { + // Attempt to get config order + const char* fileorder = getenv("_PX_CONFIG_ORDER"); + const char* envorder = getenv("PX_CONFIG_ORDER"); + + // Create the config order + string order = string(fileorder ? fileorder : "") + + string((fileorder && envorder) ? "," : "") + + string( envorder ? envorder : ""); + for (int i=0 ; DEFAULT_CONFIG_ORDER[i] ; i++) + order += string(",") + DEFAULT_CONFIG_ORDER[i]; + + return (_config_module_findpos(this->get_category(), this->get_id(), order) - + _config_module_findpos(module.get_category(), module.get_id(), order) < 0); +} + +bool config_module::get_valid() { + return this->valid; +} + +void config_module::set_valid(bool valid) { + this->valid = valid; +} + +pacrunner_module::pacrunner_module() { + this->pr = NULL; +} + +pacrunner_module::~pacrunner_module() { + if (this->pr) delete this->pr; +} + +string pacrunner_module::run(const pac pac, const url url) throw (bad_alloc) { + if (!this->pr || this->last != pac.to_string()) { + if (this->pr) delete this->pr; + this->pr = this->get_pacrunner(pac); + this->last = pac.to_string(); + } + + return this->pr->run(url); +} + +bool wpad_module::operator<(const wpad_module& module) const { + for (int i=0 ; DEFAULT_WPAD_ORDER[i] ; i++) { + if (module.get_id() == DEFAULT_WPAD_ORDER[i]) + break; + if (this->get_id() == DEFAULT_WPAD_ORDER[i]) + return true; + } + return false; +} + + +} +} +} diff --git a/libproxy/module_types.hpp b/libproxy/module_types.hpp new file mode 100644 index 0000000..b9aa3ea --- /dev/null +++ b/libproxy/module_types.hpp @@ -0,0 +1,123 @@ +/******************************************************************************* + * libproxy - A library for proxy configuration + * Copyright (C) 2009 Nathaniel McCallum <nathaniel@natemccallum.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + ******************************************************************************/ + +#ifndef MODULE_TYPES_HPP_ +#define MODULE_TYPES_HPP_ + +#include <stdexcept> + +#include "module_manager.hpp" +#include "pac.hpp" + +namespace com { +namespace googlecode { +namespace libproxy { +using namespace std; + +// Config module +class config_module : public module { +public: + typedef enum { + CATEGORY_AUTO = 0, + CATEGORY_NONE = 0, + CATEGORY_SYSTEM = 1, + CATEGORY_SESSION = 2, + CATEGORY_USER = 3, + CATEGORY__LAST = CATEGORY_USER + } category; + + // Abstract methods + virtual category get_category() const=0; + virtual url get_config(url dst) throw (runtime_error)=0; + + // Virtual methods + virtual string get_ignore(url dst); + virtual bool set_creds(url proxy, string username, string password); + + // Final methods + bool get_valid(); + void set_valid(bool valid); + bool operator<(const config_module& module) const; +private: + bool valid; +}; + +#define PX_MODULE_CONFIG_CATEGORY(cat) virtual category get_category() const { return cat; } + +// Ignore module +class ignore_module : public module { +public: + // Abstract methods + virtual bool ignore(url& dst, string ignorestr)=0; +}; + +// Network module +class network_module : public module { +public: + // Abstract methods + virtual bool changed()=0; +}; + +// PACRunner module +class pacrunner { +public: + virtual string run(const url url) throw (bad_alloc)=0; +}; + +class pacrunner_module : public module { +public: + // Abstract methods + virtual pacrunner* get_pacrunner(const pac pac) throw (bad_alloc)=0; + + // Final methods + pacrunner_module(); + ~pacrunner_module(); + string run(const pac pac, const url dst) throw (bad_alloc); +private: + pacrunner* pr; + string last; +}; + +#define PX_DEFINE_PACRUNNER_MODULE(name, cond) \ + class name ## _pacrunner_module : public pacrunner_module { \ + public: \ + PX_MODULE_ID(NULL); \ + pacrunner* get_pacrunner(const pac pac) throw (bad_alloc) { \ + return new name ## _pacrunner(pac); \ + } \ + }; \ + PX_MODULE_LOAD(pacrunner_module, name, cond) + +// WPAD module +class wpad_module : public module { +public: + // Abstract methods + virtual bool found()=0; + virtual pac* next()=0; + virtual void rewind()=0; + + // Virtual methods + virtual bool operator<(const wpad_module& module) const; +}; + +} +} +} + +#endif /* MODULE_TYPES_HPP_ */ diff --git a/libproxy/modules.hpp b/libproxy/modules.hpp deleted file mode 100644 index 2c84630..0000000 --- a/libproxy/modules.hpp +++ /dev/null @@ -1,89 +0,0 @@ -/******************************************************************************* - * libproxy - A library for proxy configuration - * Copyright (C) 2009 Nathaniel McCallum <nathaniel@natemccallum.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - ******************************************************************************/ - -#ifndef MODULE_H_ -#define MODULE_H_ -#include "module_manager.hpp" -#include "pac.hpp" - -/* - * Config module - */ -enum _pxConfigModuleCategory { - PX_CONFIG_MODULE_CATEGORY_AUTO = 0, - PX_CONFIG_MODULE_CATEGORY_NONE = 0, - PX_CONFIG_MODULE_CATEGORY_SYSTEM = 1, - PX_CONFIG_MODULE_CATEGORY_SESSION = 2, - PX_CONFIG_MODULE_CATEGORY_USER = 3, - PX_CONFIG_MODULE_CATEGORY__LAST = PX_CONFIG_MODULE_CATEGORY_USER -}; -typedef enum _pxConfigModuleCategory pxConfigModuleCategory; - -typedef struct _pxConfigModule { - pxConfigModuleCategory category; - bool valid; - char *(*get_config) (struct _pxConfigModule *self, pxURL *url); - char *(*get_ignore) (struct _pxConfigModule *self, pxURL *url); - bool (*get_credentials)(struct _pxConfigModule *self, pxURL *proxy, char **username, char **password); - bool (*set_credentials)(struct _pxConfigModule *self, pxURL *proxy, const char *username, const char *password); -} pxConfigModule; -#define pxConfigModuleVersion 0 - -#define PX_CONFIG_MODULE_BUILD(self, cat, getconf, getign, getcred, setcred) \ - ((pxConfigModule *) self)->category = cat; \ - ((pxConfigModule *) self)->get_config = getconf; \ - ((pxConfigModule *) self)->get_ignore = getign; \ - ((pxConfigModule *) self)->get_credentials = getcred; \ - ((pxConfigModule *) self)->set_credentials = setcred; - -/* - * Ignore module - */ -typedef struct _pxIgnoreModule { - bool (*ignore)(struct _pxIgnoreModule *self, pxURL *url, const char *ignorestr); -} pxIgnoreModule; -#define pxIgnoreModuleVersion 0 - -/* - * Network module - */ -typedef struct _pxNetworkModule { - bool (*changed)(struct _pxNetworkModule *self); -} pxNetworkModule; -#define pxNetworkModuleVersion 0 - -/* - * PACRunner module - */ -typedef struct _pxPACRunnerModule { - char *(*run)(struct _pxPACRunnerModule *self, pxPAC *pac, pxURL *url); -} pxPACRunnerModule; -#define pxPACRunnerModuleVersion 0 - -/* - * WPAD module - */ -typedef struct _pxWPADModule { - bool found; - pxPAC *(*next) (struct _pxWPADModule *self); - void (*rewind)(struct _pxWPADModule *self); -} pxWPADModule; -#define pxWPADModuleVersion 0 - -#endif /* MODULE_H_ */ diff --git a/libproxy/modules/config_direct.cpp b/libproxy/modules/config_direct.cpp deleted file mode 100644 index 446e7fb..0000000 --- a/libproxy/modules/config_direct.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/******************************************************************************* - * libproxy - A library for proxy configuration - * Copyright (C) 2006 Nathaniel McCallum <nathaniel@natemccallum.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - ******************************************************************************/ - -#include <stdlib.h> -#include <string.h> - -#include "../misc.hpp" -#include "../modules.hpp" - -static char * -_get_config(pxConfigModule *self, pxURL *url) -{ - return px_strdup("direct://"); -} - -static char * -_get_ignore(pxConfigModule *self, pxURL *url) -{ - return px_strdup(""); -} - -static bool -_get_credentials(pxConfigModule *self, pxURL *url, char **username, char **password) -{ - return false; -} - -static bool -_set_credentials(pxConfigModule *self, pxURL *url, const char *username, const char *password) -{ - return false; -} - -static void * -_constructor() -{ - pxConfigModule *self = px_malloc0(sizeof(pxConfigModule)); - PX_CONFIG_MODULE_BUILD(self, PX_CONFIG_MODULE_CATEGORY_NONE, _get_config, _get_ignore, _get_credentials, _set_credentials); - return self; -} - -bool -px_module_load(pxModuleManager *self) -{ - return px_module_manager_register_module(self, pxConfigModule, _constructor, px_free); -} diff --git a/libproxy/modules/config_envvar.cpp b/libproxy/modules/config_envvar.cpp index 315bd0c..b8620b5 100644 --- a/libproxy/modules/config_envvar.cpp +++ b/libproxy/modules/config_envvar.cpp @@ -17,60 +17,47 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ******************************************************************************/ -#include <stdlib.h> -#include <string.h> - -#include "../misc.hpp" -#include "../modules.hpp" - -static char * -_get_config(pxConfigModule *self, pxURL *url) -{ - char *proxy = NULL; - - // If the URL is an ftp url, try to read the ftp proxy - if (!strcmp(px_url_get_scheme(url), "ftp")) - proxy = getenv("ftp_proxy"); - - // If the URL is an https url, try to read the https proxy - else if (!strcmp(px_url_get_scheme(url), "https")) - proxy = getenv("https_proxy"); - - // If the URL is not ftp or no ftp_proxy was found, get the http_proxy - if (!proxy) - proxy = getenv("http_proxy"); - - return px_strdup(proxy); -} - -static char * -_get_ignore(pxConfigModule *self, pxURL *url) -{ - return px_strdup(getenv("no_proxy")); -} - -static bool -_get_credentials(pxConfigModule *self, pxURL *url, char **username, char **password) -{ - return false; -} - -static bool -_set_credentials(pxConfigModule *self, pxURL *url, const char *username, const char *password) -{ - return false; -} - -static void * -_constructor() -{ - pxConfigModule *self = (pxConfigModule *) px_malloc0(sizeof(pxConfigModule)); - PX_CONFIG_MODULE_BUILD(self, PX_CONFIG_MODULE_CATEGORY_NONE, _get_config, _get_ignore, _get_credentials, _set_credentials); - return self; -} - -bool -px_module_load(pxModuleManager *self) -{ - return px_module_manager_register_module(self, pxConfigModule, _constructor, px_free); -} +#include <cstdlib> + +#include "../module_types.hpp" +using namespace com::googlecode::libproxy; + +class envvar_config_module : public config_module { +public: + PX_MODULE_ID(NULL); + PX_MODULE_CONFIG_CATEGORY(config_module::CATEGORY_NONE); + + url get_config(url url) throw (runtime_error) { + char *proxy = NULL; + + // If the URL is an ftp url, try to read the ftp proxy + if (url.get_scheme() == "ftp") { + if (!(proxy = getenv("ftp_proxy"))) + proxy = getenv("FTP_PROXY"); + } + + // If the URL is an https url, try to read the https proxy + if (url.get_scheme() == "https") { + if (!(proxy = getenv("https_proxy"))) + proxy = getenv("HTTPS_PROXY"); + } + + // If the URL is not ftp or no ftp_proxy was found, get the http_proxy + if (!proxy) { + if (!(proxy = getenv("http_proxy"))) + proxy = getenv("HTTP_PROXY"); + } + + if (!proxy) + throw runtime_error("Unable to read configuration"); + return com::googlecode::libproxy::url(proxy); + } + + string get_ignore(url dst) { + char *ignore = getenv("no_proxy"); + ignore = ignore ? ignore : getenv("NO_PROXY"); + return string(ignore ? ignore : ""); + } +}; + +PX_MODULE_LOAD(config_module, envvar, true); diff --git a/libproxy/modules/config_file.cpp b/libproxy/modules/config_file.cpp index 39cd01f..bd5640a 100644 --- a/libproxy/modules/config_file.cpp +++ b/libproxy/modules/config_file.cpp @@ -17,98 +17,48 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ******************************************************************************/ -#include <stdlib.h> -#include <string.h> - -#include "../misc.hpp" -#include "../modules.hpp" #include "../config_file.hpp" +#include "../module_types.hpp" +using namespace com::googlecode::libproxy; -typedef struct _pxFileConfigModule { - PX_MODULE_SUBCLASS(pxConfigModule); - char *filename; - pxConfigFile *cf; -} pxFileConfigModule; - -static void -_destructor(void *s) -{ - pxFileConfigModule *self = (pxFileConfigModule *) self; - - px_config_file_free(self->cf); - px_free(self->filename); - px_free(self); -} - -static char * -_get_config(pxConfigModule *ss, pxURL *url) -{ - pxFileConfigModule *self = (pxFileConfigModule *) self; - - if (!self->cf) - self->cf = px_config_file_new(self->filename); - if (!self->cf) - return NULL; - return px_config_file_get_value(self->cf, PX_CONFIG_FILE_DEFAULT_SECTION, "proxy"); -} - -static char * -_get_ignore(pxConfigModule *s, pxURL *url) -{ - pxFileConfigModule *self = (pxFileConfigModule *) self; - - if (!self->cf) - self->cf = px_config_file_new(self->filename); - if (!self->cf) - return NULL; - return px_config_file_get_value(self->cf, PX_CONFIG_FILE_DEFAULT_SECTION, "ignore"); -} +class system_file_config_module : public config_module { +public: + PX_MODULE_ID("config_file_system"); + PX_MODULE_CONFIG_CATEGORY(config_module::CATEGORY_SYSTEM); -static bool -_get_credentials(pxConfigModule *s, pxURL *proxy, char **username, char **password) -{ - pxFileConfigModule *self = (pxFileConfigModule *) self; - - return false; -} + system_file_config_module() { + this->cf.load(this->get_filename()); + } -static bool -_set_credentials(pxConfigModule *s, pxURL *proxy, const char *username, const char *password) -{ - pxFileConfigModule *self = (pxFileConfigModule *) self; + url get_config(url url) throw (runtime_error) { + if (this->cf.is_stale()) + this->cf.load(this->get_filename()); + return this->cf.get_value("proxy"); + } - return false; -} + string get_ignore(url& url) { + if (this->cf.is_stale()) + this->cf.load(this->get_filename()); + return this->cf.get_value("ignore"); + } -static void * -_system_constructor() -{ - pxFileConfigModule *self = (pxFileConfigModule *) px_malloc0(sizeof(pxFileConfigModule)); - PX_CONFIG_MODULE_BUILD(self, PX_CONFIG_MODULE_CATEGORY_SYSTEM, _get_config, _get_ignore, _get_credentials, _set_credentials); - self->filename = px_strdup(SYSCONFDIR "proxy.conf"); +protected: + virtual string get_filename() { return SYSCONFDIR "proxy.conf"; } - return self; -} +private: + config_file cf; +}; -static void * -_user_constructor() -{ - pxFileConfigModule *self = (pxFileConfigModule *) px_malloc0(sizeof(pxFileConfigModule)); - PX_CONFIG_MODULE_BUILD(self, PX_CONFIG_MODULE_CATEGORY_USER, _get_config, _get_ignore, _get_credentials, _set_credentials); - self->filename = px_strcat(getenv("HOME"), "/", ".proxy.conf", NULL); +class user_file_config_module : public system_file_config_module { +public: + PX_MODULE_ID("config_file_user"); + PX_MODULE_CONFIG_CATEGORY(config_module::CATEGORY_USER); - if (!self->filename || !strcmp(self->filename, "")) - { - _destructor((void *) self); - return NULL; - } - return self; -} +protected: + virtual string get_filename() { return string(getenv("HOME")) + string("/.proxy.conf"); } +}; -bool -px_module_load(pxModuleManager *self) -{ - bool a = px_module_manager_register_module_with_name(self, pxConfigFile, "config_file_system", _system_constructor, _destructor); - bool b = px_module_manager_register_module_with_name(self, pxConfigFile, "config_file_user", _user_constructor, _destructor); - return (a || b); +extern "C" bool px_module_load(module_manager& mm) { + bool success = mm.register_module<config_module>(new user_file_config_module); + return mm.register_module<config_module>(new system_file_config_module) || success; } diff --git a/libproxy/modules/config_gnome.cpp b/libproxy/modules/config_gnome.cpp index 91907ae..3675924 100644 --- a/libproxy/modules/config_gnome.cpp +++ b/libproxy/modules/config_gnome.cpp @@ -17,261 +17,220 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ******************************************************************************/ -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <stdint.h> -#include <time.h> - -#include "../misc.hpp" -#include "../modules.hpp" -#include "../strdict.hpp" -#include "xhasclient.cpp" - -#define BUFFERSIZE 10240 -#define CACHETIME 5 - -typedef struct _pxGConfConfigModule { - PX_MODULE_SUBCLASS(pxConfigModule); - FILE *pipe; - pxStrDict *data; - time_t last; -} pxGConfConfigModule; +#include <cstdio> // For fileno(), fread(), pclose(), popen(), sscanf() +#include <sys/select.h> // For select(...) +#include <fcntl.h> // For fcntl(...) +#include "xhasclient.cpp" // For xhasclient(...) -static const char *_all_keys[] = { - "/system/proxy/mode", "/system/proxy/autoconfig_url", - "/system/http_proxy/host", "/system/http_proxy/port", - "/system/proxy/secure_host", "/system/proxy/secure_port", - "/system/proxy/ftp_host", "/system/proxy/ftp_port", - "/system/proxy/socks_host", "/system/proxy/socks_port", - "/system/http_proxy/ignore_hosts", - "/system/http_proxy/use_authentication", - "/system/http_proxy/authentication_user", - "/system/http_proxy/authentication_password", NULL -}; +/* +int popen2(const char *program, FILE **read, FILE **write) { + int wpipe[2]; + + if (!read || !write || !program || !*program) + return EINVAL; + + *read = NULL; + *write = NULL; + + if (pipe(wpipe) < 0) + return errno; + + switch (pid = vfork()) { + case -1: // Error + close(wpipe[0]); + close(wpipe[1]); + return ASOIMWE; + case 0: // Child + close(wpipe[1]); + dup2(wpipe[0], STDIN_FILENO); + close(wpipe[0]); -static FILE * -_start_get_config() -{ - char buffer[BUFFERSIZE] = ""; - - // Build our command - if (strlen(GCONFTOOLBIN " -g") + 1 > BUFFERSIZE) - return NULL; - strcpy(buffer, GCONFTOOLBIN " -g"); - for (int i=0 ; _all_keys[i] ; i++) - { - if (strlen(buffer) + strlen(_all_keys[i]) + 2 > BUFFERSIZE) - return NULL; - strcat(buffer, " "); - strcat(buffer, _all_keys[i]); - } - if (strlen(buffer) + strlen(" 2>&1") + 1 > BUFFERSIZE) - return NULL; - strcat(buffer, " 2>&1"); - // Open our pipe - return popen(buffer, "r"); -} -static pxStrDict * -_finish_get_config(FILE *pipe) -{ - char buffer[BUFFERSIZE] = ""; - char **values = NULL; - pxStrDict *kv = NULL; - - if (!pipe) return NULL; - - // Read the output and split it into its separate values (one per line) - if (fread(buffer, sizeof(char), BUFFERSIZE, pipe) == 0) goto error; - if (!(values = px_strsplit(buffer, "\n"))) goto error; - - // Build up our dictionary with the values - kv = px_strdict_new((pxStrDictItemCallback) px_free); - for (int i=0 ; _all_keys[i] ; i++) - { - if (!values[i]) - goto error; - if (strchr(values[i], ' ')) - strcpy(values[i], ""); - if (!px_strdict_set(kv, _all_keys[i], px_strdup(values[i]))) - goto error; + execl(_PATH_BSHELL, "sh", "-c", program, (char *)NULL); + _exit(127); + // NOTREACHED + } } - // Cleanup - px_strfreev(values); - if (pclose(pipe) < 0) - { - px_strdict_free(kv); - return NULL; + // Parent; assume fdopen can't fail. + if (*type == 'r') { + iop = fdopen(pdes[0], type); + (void)close(pdes[1]); + } else { + iop = fdopen(pdes[1], type); + (void)close(pdes[0]); } - return kv; - error: - pclose(pipe); - px_strfreev(values); - px_strdict_free(kv); - return NULL; -} + // Link into list of file descriptors. + cur->fp = iop; + cur->pid = pid; + cur->next = pidlist; + pidlist = cur; -static void -_destructor(void *s) -{ - pxGConfConfigModule *self = (pxGConfConfigModule *) s; + return (iop); +}*/ - if (self->pipe) pclose(self->pipe); - px_strdict_free(self->data); - px_free(self); -} +#include "../module_types.hpp" +using namespace com::googlecode::libproxy; -static char * -_get_config(pxConfigModule *s, pxURL *url) -{ - pxGConfConfigModule *self = (pxGConfConfigModule *) s; - - // Update our config if possible - if (self->pipe) - { - pxStrDict *tmp = _finish_get_config(self->pipe); - self->pipe = NULL; - if (tmp) - { - px_strdict_free(self->data); - self->data = tmp; - self->last = time(NULL); +static const char *_all_keys[] = { + "/system/proxy/mode", "/system/proxy/autoconfig_url", + "/system/http_proxy/host", "/system/http_proxy/port", + "/system/proxy/secure_host", "/system/proxy/secure_port", + "/system/proxy/ftp_host", "/system/proxy/ftp_port", + "/system/proxy/socks_host", "/system/proxy/socks_port", + "/system/http_proxy/ignore_hosts", + "/system/http_proxy/use_authentication", + "/system/http_proxy/authentication_user", + "/system/http_proxy/authentication_password", + NULL +}; + +class gnome_config_module : public config_module { +public: + PX_MODULE_ID(NULL); + PX_MODULE_CONFIG_CATEGORY(config_module::CATEGORY_SESSION); + + gnome_config_module() { + int count; + string cmd = LIBEXECDIR "pxgconf"; + for (count=0 ; _all_keys[count] ; count++) + cmd += string(" ", 1) + _all_keys[count]; + + this->pipe = popen(cmd.c_str(), "r"); + if (!this->pipe) + throw io_error("Unable to open gconf helper!"); + if (fcntl(fileno(this->pipe), F_SETFL, FNONBLOCK) == -1) { + pclose(this->pipe); + throw io_error("Unable to set pipe to non-blocking!"); } + + this->update_data(count); } - if (!px_strdict_get(self->data, "/system/proxy/mode")) - return NULL; + ~gnome_config_module() { + if (this->pipe) + pclose(this->pipe); + } - char *curl = NULL; + url get_config(url dest) throw (runtime_error) { + // Check for changes in the config + if (this->pipe) this->update_data(); - // Mode is direct:// - if (!strcmp((const char *) px_strdict_get(self->data, "/system/proxy/mode"), "none")) - curl = px_strdup("direct://"); + // Mode is wpad:// or pac+http://... + if (this->data["/system/proxy/mode"] == "auto") { + string pac = this->data["/system/proxy/autoconfig_url"]; + return url::is_valid(pac) ? url(string("pac+") + pac) : url("wpad://"); + } - // Mode is wpad:// or pac+http://... - else if (!strcmp((const char *) px_strdict_get(self->data, "/system/proxy/mode"), "auto")) - { - if (px_url_is_valid((const char *) px_strdict_get(self->data, "/system/proxy/autoconfig_url"))) - curl = px_strcat("pac+", px_strdict_get(self->data, "/system/proxy/autoconfig_url"), NULL); - else - curl = px_strdup("wpad://"); - } + // Mode is http://... or socks://... + else if (this->data["/system/proxy/mode"] == "manual") { + string type = "http", host, port; + bool auth = this->data["/system/http_proxy/use_authentication"] == "true"; + string username = this->data["/system/http_proxy/authentication_user"]; + string password = this->data["/system/http_proxy/authentication_password"]; + uint16_t p = 0; + + // Get the per-scheme proxy settings + if (dest.get_scheme() == "https") { + host = this->data["/system/proxy/secure_host"]; + port = this->data["/system/proxy/secure_port"]; + if (sscanf(port.c_str(), "%hu", &p) != 1) p = 0; + } + else if (dest.get_scheme() == "ftp") { + host = this->data["/system/proxy/ftp_host"]; + port = this->data["/system/proxy/ftp_port"]; + if (sscanf(port.c_str(), "%hu", &p) != 1) p = 0; + } + if (host == "" || p == 0) + { + host = this->data["/system/http_proxy/host"]; + port = this->data["/system/http_proxy/port"]; + if (sscanf(port.c_str(), "%hu", &p) != 1) p = 0; + } - // Mode is http://... or socks://... - else if (!strcmp((const char *) px_strdict_get(self->data, "/system/proxy/mode"), "manual")) - { - char *type = px_strdup("http"); - char *host = NULL; - char *port = NULL; - char *username = NULL; - char *password = NULL; - - uint16_t p = 0; - - // Get the per-scheme proxy settings - if (!strcmp(px_url_get_scheme(url), "https")) - { - host = px_strdup((const char *) px_strdict_get(self->data, "/system/proxy/secure_host")); - port = px_strdup((const char *) px_strdict_get(self->data, "/system/proxy/secure_port")); - if (!port || sscanf(port, "%hu", &p) != 1) p = 0; - } - else if (!strcmp(px_url_get_scheme(url), "ftp")) - { - host = px_strdup((const char *) px_strdict_get(self->data, "/system/proxy/ftp_host")); - port = px_strdup((const char *) px_strdict_get(self->data, "/system/proxy/ftp_port")); - if (!port || sscanf(port, "%hu", &p) != 1) p = 0; - } - if (!host || !strcmp(host, "") || !p) - { - px_free(host); - px_free(port); - - host = px_strdup((const char *) px_strdict_get(self->data, "/system/http_proxy/host")); - port = px_strdup((const char *) px_strdict_get(self->data, "/system/http_proxy/port")); - if (!strcmp((const char *) px_strdict_get(self->data, "/system/http_proxy/use_authentication"), "true")) { - username = px_strdup((const char *) px_strdict_get(self->data, "/system/http_proxy/authentication_user")); - password = px_strdup((const char *) px_strdict_get(self->data, "/system/http_proxy/authentication_password")); + // If http(s)/ftp proxy is not set, try socks + if (host == "" || p == 0) + { + host = this->data["/system/proxy/socks_host"]; + port = this->data["/system/proxy/socks_port"]; + if (sscanf(port.c_str(), "%hu", &p) != 1) p = 0; } - if (!port || sscanf(port, "%hu", &p) != 1) p = 0; - } - // If http(s)/ftp proxy is not set, try socks - if (!host || !strcmp(host, "") || !p) - { - px_free(type); - px_free(host); - px_free(port); - - type = px_strdup("socks"); - host = px_strdup((const char *) px_strdict_get(self->data, "/system/proxy/socks_host")); - port = px_strdup((const char *) px_strdict_get(self->data, "/system/proxy/socks_port")); - if (!port || sscanf(port, "%hu", &p) != 1) p = 0; + // If host and port were found, build config url + if (host != "" && p != 0) { + string tmp = type + "://"; + if (auth) + tmp += username + ":" + password + "@"; + tmp += host + ":" + port; + return url(tmp); + } } - // If host and port were found, build config url - if (host && strcmp(host, "") && p) - curl = px_strcat(type, "://", username && password ? px_strcat(username, ":", password, "@", NULL) : "", host, ":", port, NULL); + // Mode is direct:// + return url("direct://"); + } - px_free(type); - px_free(host); - px_free(port); - px_free(username); - px_free(password); + string get_ignore(url url) { + return this->data["/system/http_proxy/ignore_hosts"]; } - // Start a refresh in the background - if (time(NULL) - self->last > CACHETIME) - self->pipe = _start_get_config(); +private: + FILE *pipe; + map<string, string> data; - return curl; -} + string readline(string buffer="") { + char c; -static char * -_get_ignore(pxConfigModule *s, pxURL *url) -{ - pxGConfConfigModule *self = (pxGConfConfigModule *) s; - - char *ignores = px_strdup((const char *) px_strdict_get(self->data, "/system/http_proxy/ignore_hosts")); - if (ignores && ignores[strlen(ignores)-1] == ']' && ignores[0] == '[') - { - char *tmp = px_strndup(ignores+1, strlen(ignores+1)-1); - px_free(ignores); - ignores = tmp; - } - - return ignores ? ignores : px_strdup(""); -} + // If the fread() call would block, an error occurred or + // we are at the end of the line, we're done + if (fread(&c, sizeof(char), 1, this->pipe) != 1 || c == '\n') + return buffer; -static bool -_get_credentials(pxConfigModule *self, pxURL *proxy, char **username, char **password) -{ - return false; -} + // Process the next character + return this->readline(buffer + string(&c, 1)); + } -static bool -_set_credentials(pxConfigModule *self, pxURL *proxy, const char *username, const char *password) -{ - return false; -} + // This method attempts to update data + // If called with no arguments, it will check for new data (sleeping for <=1000 + // useconds) and returning true or false depending on if at least one line of + // data was found. + // However, if req > 0, we will keep checking for new lines (at 1000 usec ivals) + // until enough lines are found. This allows us to wait for *all* the initial + // values to be read in before we start processing gconf requests. + bool update_data(int req=0, int found=0) { + // If we have collected the correct number of lines, return true + if (req > 0 && found >= req) + return true; + + // We need the pipe to be open + if (!this->pipe) return false; + + fd_set rfds; + struct timeval timeout = { 0, 1000 }; + FD_ZERO(&rfds); + FD_SET(fileno(this->pipe), &rfds); + if (select(fileno(this->pipe)+1, &rfds, NULL, NULL, &timeout) < 1) + return req > 0 ? this->update_data(req, found) : false; // If we still haven't met + // our req quota, try again + + bool retval = false; + for (string line = this->readline() ; line != "" ; line = this->readline()) { + string key = line.substr(0, line.find("\t")); + string val = line.substr(line.find("\t")+1); + this->data[key] = val; + retval = ++found > req; + } -static void * -_constructor() -{ - pxGConfConfigModule *self = (pxGConfConfigModule *) px_malloc0(sizeof(pxGConfConfigModule)); - PX_CONFIG_MODULE_BUILD(self, PX_CONFIG_MODULE_CATEGORY_SESSION, _get_config, _get_ignore, _get_credentials, _set_credentials); - self->pipe = _start_get_config(); - return self; -} + return (this->update_data(req, found) || retval); + } +}; -bool -px_module_load(pxModuleManager *self) -{ - // If we are running in GNOME, then make sure this plugin is registered. - if (!x_has_client("gnome-session", "gnome-settings-daemon", "gnome-panel", NULL)) - return false; - return px_module_manager_register_module(self, pxConfigModule, _constructor, _destructor); +// If we are running in GNOME, then make sure this plugin is registered. +extern "C" bool px_module_load(module_manager& mm) { + if (xhasclient("gnome-session", "gnome-settings-daemon", "gnome-panel", NULL)) { + try { return mm.register_module<config_module>(new gnome_config_module); } + catch (io_error) { return false; } + } } diff --git a/libproxy/modules/config_kde4.cpp b/libproxy/modules/config_kde4.cpp index afa3720..b5e8684 100644 --- a/libproxy/modules/config_kde4.cpp +++ b/libproxy/modules/config_kde4.cpp @@ -17,122 +17,63 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ******************************************************************************/ -#include <stdlib.h> -#include <string.h> -#include <stdarg.h> -#include <stdio.h> +#include <kstandarddirs.h> // For KStandardDirs +#include "xhasclient.cpp" // For xhasclient(...) -#include "../misc.hpp" -#include "../modules.hpp" #include "../config_file.hpp" - -#include <kstandarddirs.h> - -typedef struct _pxKConfigConfigModule { - PX_MODULE_SUBCLASS(pxConfigModule); - pxConfigFile *cf; -} pxKConfigConfigModule; - -static void -_destructor(void *s) -{ - pxKConfigConfigModule *self = (pxKConfigConfigModule *) s; - - px_config_file_free(self->cf); - px_free(self); -} - -static char * -_get_config(pxConfigModule *s, pxURL *url) -{ - pxKConfigConfigModule *self = (pxKConfigConfigModule *) s; - - // TODO: make ignores work w/ KDE - char *curl = NULL, *tmp = NULL; - - // Open the config file - pxConfigFile *cf = self->cf; - if (!cf || px_config_file_is_stale(cf)) - { - if (cf) px_config_file_free(cf); - QString localdir = KStandardDirs().localkdedir(); - QByteArray ba = localdir.toLatin1(); - tmp = px_strcat(ba.data(), "/share/config/kioslaverc", NULL); - cf = px_config_file_new(tmp); - px_free(tmp); - self->cf = cf; - } - if (!cf) goto out; - - // Read the config file to find out what type of proxy to use - tmp = px_config_file_get_value(cf, "Proxy Settings", "ProxyType"); - if (!tmp) goto out; - - // Don't use any proxy - if (!strcmp(tmp, "0")) - curl = px_strdup("direct://"); - - // Use a manual proxy - else if (!strcmp(tmp, "1")) - curl = px_config_file_get_value(cf, "Proxy Settings", "httpProxy"); - - // Use a manual PAC - else if (!strcmp(tmp, "2")) - { - px_free(tmp); - tmp = px_config_file_get_value(cf, "Proxy Settings", "Proxy Config Script"); - if (tmp) curl = px_strcat("pac+", tmp); - else curl = px_strdup("wpad://"); +#include "../module_types.hpp" +using namespace com::googlecode::libproxy; + +class kde_config_module : public config_module { +public: + PX_MODULE_ID(NULL); + PX_MODULE_CONFIG_CATEGORY(config_module::CATEGORY_SESSION); + + url get_config(url url) throw (runtime_error) { + // Open the config file + if (this->cf.is_stale()) + { + QString localdir = KStandardDirs().localkdedir(); + QByteArray ba = localdir.toLatin1(); + if (!cf.load(string(ba.data()) + "/share/config/kioslaverc")) + throw runtime_error("Unable to load kde config file!"); + } + + try { + // Read the config file to find out what type of proxy to use + string ptype = this->cf.get_value("Proxy Settings", "ProxyType"); + + // Use a manual proxy + if (ptype == "1") + return com::googlecode::libproxy::url(this->cf.get_value("Proxy Settings", "httpProxy")); + + // Use a manual PAC + else if (ptype == "2") + { + string tmp = ""; + try { tmp = this->cf.get_value("Proxy Settings", "Proxy Config Script"); } + catch (key_error&) {} + + if (tmp != "") return com::googlecode::libproxy::url(string("pac+") + tmp); + else return com::googlecode::libproxy::url("wpad://"); + } + + // Use WPAD + else if (ptype == "3") + return com::googlecode::libproxy::url("wpad://"); + + // Use envvar + else if (ptype == "4") + throw runtime_error("User config_envvar"); // We'll bypass this config plugin and let the envvar plugin work + } + catch (key_error&) { } + + // Don't use any proxy + return com::googlecode::libproxy::url("direct://"); } - // Use WPAD - else if (!strcmp(tmp, "3")) - curl = px_strdup("wpad://"); - - // Use envvar - else if (!strcmp(tmp, "4")) - curl = NULL; // We'll bypass this config plugin and let the envvar plugin work - - // Cleanup - px_free(tmp); - - out: - return curl; -} +private: + config_file cf; +}; -static char * -_get_ignore(pxConfigModule *self, pxURL *url) -{ - return px_strdup(""); -} - -static bool -_get_credentials(pxConfigModule *self, pxURL *proxy, char **username, char **password) -{ - return false; -} - -static bool -_set_credentials(pxConfigModule *self, pxURL *proxy, const char *username, const char *password) -{ - return false; -} - -static void * -_constructor() -{ - pxKConfigConfigModule *self = (pxKConfigConfigModule *)px_malloc0(sizeof(pxKConfigConfigModule)); - PX_CONFIG_MODULE_BUILD(self, PX_CONFIG_MODULE_CATEGORY_SESSION, _get_config, _get_ignore, _get_credentials, _set_credentials); - return self; -} - -extern "C" bool -px_module_load(pxModuleManager *self) -{ - // If we are running in KDE, then make sure this plugin is registered. - char *tmp = getenv("KDE_FULL_SESSION"); - if (tmp == NULL) { - return false; - } - return px_module_manager_register_module(self, pxConfigModule, _constructor, _destructor); -} +PX_MODULE_LOAD(config_module, kde, xhasclient("kicker", NULL)); diff --git a/libproxy/modules/config_w32reg.cpp b/libproxy/modules/config_w32reg.cpp index 95321fc..3f3ac95 100644 --- a/libproxy/modules/config_w32reg.cpp +++ b/libproxy/modules/config_w32reg.cpp @@ -18,19 +18,14 @@ #include <windows.h> -#include <stdlib.h> -#include <string.h> - -#include "../misc.hpp" -#include "../modules.hpp" +#include "../module_types.hpp" +using namespace com::googlecode::libproxy; #define W32REG_OFFSET_PAC (1 << 2) #define W32REG_OFFSET_WPAD (1 << 3) #define W32REG_BASEKEY "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings" -static bool -_get_registry(const char *key, const char *name, uchar **sval, uint32_t *slen, uint32_t *ival) -{ +static bool _get_registry(const char *key, const char *name, uchar **sval, uint32_t *slen, uint32_t *ival) { HKEY hkey; LONG result; DWORD type; @@ -40,7 +35,7 @@ _get_registry(const char *key, const char *name, uchar **sval, uint32_t *slen, u // Don't allow the caller to specify both sval and ival if (sval && ival) return false; - + // Open the key if (RegOpenKeyExA(HKEY_CURRENT_USER, key, 0, KEY_READ, &hkey) != ERROR_SUCCESS) return false; @@ -61,7 +56,7 @@ _get_registry(const char *key, const char *name, uchar **sval, uint32_t *slen, u case REG_SZ: if (!sval) return false; if (slen) *slen = buflen; - *sval = px_malloc(buflen); + *sval = new char[buflen]; return !memcpy_s(*sval, buflen, buffer, buflen); case REG_DWORD: if (ival) return !memcpy_s(ival, sizeof(uint32_t), buffer, buflen); @@ -69,10 +64,7 @@ _get_registry(const char *key, const char *name, uchar **sval, uint32_t *slen, u return false; } - -static bool -_is_enabled(uint8_t type) -{ +static bool _is_enabled(uint8_t type) { uchar *data = NULL; uint32_t dlen = 0; bool result = false; @@ -85,127 +77,81 @@ _is_enabled(uint8_t type) if (dlen >= 9) result = data[8] & type == type; // Check to see if the bit is set - px_free(data); + delete data; return result; } -static char * -_get_pac() -{ - char *pac = NULL; - char *url = NULL; - - if (!_is_enabled(W32REG_OFFSET_PAC)) return NULL; - if (!_get_registry(W32REG_BASEKEY, "AutoConfigURL", &pac, NULL, NULL)) return NULL; - - url = px_strcat("pac+", pac, NULL); - px_free(pac); - return url; -} - -static char * -_get_manual(pxURL *url) -{ - char *val = NULL; - char *url = NULL; - char **vals = NULL; - uint32_t enabled = 0; - - // Check to see if we are enabled - if (!_get_registry(W32REG_BASEKEY, "ProxyEnable", NULL, NULL, &enabled) || !enabled) return NULL; - - // Get the value of ProxyServer - if (!_get_registry(W32REG_BASEKEY, "ProxyServer", &val, NULL, NULL)) return NULL; - +static map<string, string> _parse_manual(string data) { // ProxyServer comes in two formats: // 1.2.3.4:8080 or ftp=1.2.3.4:8080;https=1.2.3.4:8080... - // If we have the first format, just prepend "http://" and we're done - if (!strchr(val, ';')) - { - url = px_strcat("http://", val, NULL); - px_free(val); - return url; - } - - // Ok, now we have the more difficult format... - // ... so split up all the various proxies - vals = px_strsplit(val, ";"); - px_free(val); + map<string, url> rval; - // First we look for an exact match - for (int i=0 ; !url && vals[i] ; i++) - { - char *tmp = px_strcat(px_url_get_scheme(url), "=", NULL); - - // If we've found an exact match, use it - if (!strncmp(tmp, vals[i], strlen(tmp))) - url = px_strcat(px_url_get_scheme(url), "://", vals[i]+strlen(tmp), NULL); - - px_free(tmp); + // If we have the second format, do recursive parsing, + // then handle just the first entry + if (data.find(";") != string::npos) { + rval = _parse_manual(data.substr(data.find(";")+1)); + data = data.substr(0, data.find(";")); } - // Second we look for http= - for (int i=0 ; !url && vals[i] ; i++) - if (!strncmp("http=", vals[i], strlen("http="))) - url = px_strcat("http://", vals[i]+strlen("http="), NULL); - - // Last we look for socks= - for (int i=0 ; !url && vals[i] ; i++) - if (!strncmp("socks=", vals[i], strlen("socks="))) - url = px_strcat("socks://", vals[i]+strlen("socks="), NULL); - - return url; -} - -static char * -_get_config(pxConfigModule *self, pxURL *url) -{ - char *config = NULL; - - // WPAD - if (_is_enabled(W32REG_OFFSET_WPAD)) - return px_strdup("wpad://"); - - // PAC - if ((config = _get_pac())) - return config; - - // Manual proxy - if ((config = _get_manual(url))) - return config; - - // Direct - return px_strdup("direct://"); -} - -static char * -_get_ignore(pxConfigModule *self, pxURL *url) -{ - return px_strdup(""); -} + // If we have the first format, just assign HTTP and we're done + if (data.find("=") == string::npos) { + rval["http"] = data; + return rval; + } -static bool -_get_credentials(pxConfigModule *self, pxURL *url, char **username, char **password) -{ - return false; -} + // Otherwise set the value for this single entry and return + string protocol = data.substr(0, data.find("=")); + try { rval[protocol] = url(protocol + "://" + data.substr(data.find("=")+1)); } + catch (parse_error&) {} -static bool -_set_credentials(pxConfigModule *self, pxURL *url, const char *username, const char *password) -{ - return false; + return rval; } -static void * -_constructor() -{ - pxConfigModule *self = px_malloc0(sizeof(pxConfigModule)); - PX_CONFIG_MODULE_BUILD(self, PX_CONFIG_MODULE_CATEGORY_USER, _get_config, _get_ignore, _get_credentials, _set_credentials); - return self; +class w32reg_config_module : public config_module { +public: + PX_MODULE_ID(NULL); + PX_MODULE_CONFIG_CATEGORY(config_module::CATEGORY_SYSTEM); + + url get_config(url dst) throw (runtime_error) { + char *tmp = NULL; + uint32_t enabled = 0; + + // WPAD + if (_is_enabled(W32REG_OFFSET_WPAD)) + return url("wpad://"); + + // PAC + if (_is_enabled(W32REG_OFFSET_PAC) && + _get_registry(W32REG_BASEKEY, "AutoConfigURL", &tmp, NULL, NULL) && + url::is_valid(string("pac+") + tmp)) { + url cfg(string("pac+") + tmp); + delete tmp; + return cfg; + } + + // Manual proxy + // Check to see if we are enabled and get the value of ProxyServer + if (_get_registry(W32REG_BASEKEY, "ProxyEnable", NULL, NULL, &enabled) && enabled && + _get_registry(W32REG_BASEKEY, "ProxyServer", &tmp, NULL, NULL)) { + map<string, string> manual = _parse_manual(tmp); + delete tmp; + + // First we look for an exact match + if (manual.find(dst.get_scheme()) != map<string, url>::end) + return manual[dst.get_scheme()]; + + // Next we look for http + else if (manual.find("http") != map<string, url>::end) + return manual["http"]; + + // Last we look for socks + else if (manual.find("socks") != map<string, url>::end) + return manual["socks"]; + } + + // Direct + return url("direct://"); + } } -bool -px_module_load(pxModuleManager *self) -{ - return px_module_manager_register_module(self, pxConfigModule, _constructor, px_free); -} +PX_MODULE_LOAD(config_module, w32reg, true); diff --git a/libproxy/modules/config_wpad.cpp b/libproxy/modules/config_wpad.cpp index d194e4b..ef440a4 100644 --- a/libproxy/modules/config_wpad.cpp +++ b/libproxy/modules/config_wpad.cpp @@ -17,46 +17,17 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ******************************************************************************/ -#include <stdlib.h> -#include <string.h> +#include "../module_types.hpp" +using namespace com::googlecode::libproxy; -#include "../misc.hpp" -#include "../modules.hpp" +class wpad_config_module : public config_module { +public: + PX_MODULE_ID(NULL); + PX_MODULE_CONFIG_CATEGORY(config_module::CATEGORY_NONE); -static char * -_get_config(pxConfigModule *self, pxURL *url) -{ - return px_strdup("wpad://"); -} + url get_config(url dst) throw (runtime_error) { + return url("wpad://"); + } +}; -static char * -_get_ignore(pxConfigModule *self, pxURL *url) -{ - return px_strdup(""); -} - -static bool -_get_credentials(pxConfigModule *self, pxURL *url, char **username, char **password) -{ - return false; -} - -static bool -_set_credentials(pxConfigModule *self, pxURL *url, const char *username, const char *password) -{ - return false; -} - -static void * -_constructor() -{ - pxConfigModule *self = (pxConfigModule *) px_malloc0(sizeof(pxConfigModule)); - PX_CONFIG_MODULE_BUILD(self, PX_CONFIG_MODULE_CATEGORY_NONE, _get_config, _get_ignore, _get_credentials, _set_credentials); - return self; -} - -bool -px_module_load(pxModuleManager *self) -{ - return px_module_manager_register_module(self, pxConfigModule, _constructor, px_free); -} +PX_MODULE_LOAD(config_module, wpad, true); diff --git a/libproxy/modules/ignore_domain.cpp b/libproxy/modules/ignore_domain.cpp index ceca7d5..b9bd990 100644 --- a/libproxy/modules/ignore_domain.cpp +++ b/libproxy/modules/ignore_domain.cpp @@ -17,81 +17,46 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ******************************************************************************/ -#include <stdlib.h> -#include <stdio.h> -#include <string.h> +#include <cstdio> -#include "../misc.hpp" -#include "../modules.hpp" +#include "../module_types.hpp" -static inline bool -_endswith(char *string, char *suffix) -{ - int st_len = strlen(string); - int su_len = strlen(suffix); +using namespace com::googlecode::libproxy; - return (st_len >= su_len && !strcmp(string + (st_len-su_len), suffix)); -} +class domain_ignore_module : public ignore_module { +public: + PX_MODULE_ID(NULL); -static bool -_ignore(pxIgnoreModule *self, pxURL *url, const char *ignore) -{ - if (!url || !ignore) - return false; + virtual bool ignore(url& url, string ignorestr) { + /* Get our URL's hostname and port */ + string host = url.get_host(); + int port = url.get_port(); - /* Get our URL's hostname and port */ - char *host = px_strdup(px_url_get_host(url)); - int port = px_url_get_port(url); + /* Get our ignore pattern's hostname and port */ + string ihost = ignorestr; + int iport = 0; + if (ihost.find(':') != string::npos) { + if (sscanf(ignorestr.substr(ihost.find(':')+1).c_str(), "%d", &iport) == 1) + ihost = ihost.substr(0, ihost.find(':')); + else + iport = 0; + } - /* Get our ignore pattern's hostname and port */ - char *ihost = px_strdup(ignore); - int iport = 0; - if (strchr(ihost, ':')) - { - char *tmp = strchr(ihost, ':'); - if (sscanf(tmp+1, "%d", &iport) == 1) - *tmp = '\0'; - else - iport = 0; - } - - /* Hostname match (domain.com or domain.com:80) */ - if (!strcmp(host, ihost)) - if (!iport || port == iport) - goto match; - - /* Endswith (.domain.com or .domain.com:80) */ - if (ihost[0] == '.' && _endswith(host, ihost)) - if (!iport || port == iport) - goto match; + /* Hostname match (domain.com or domain.com:80) */ + if (host == ihost) + return (iport == 0 || port == iport); - /* Glob (*.domain.com or *.domain.com:80) */ - if (ihost[0] == '*' && _endswith(host, ihost+1)) - if (!iport || port == iport) - goto match; + /* Endswith (.domain.com or .domain.com:80) */ + if (ihost[0] == '.' && host.find(ihost) == host.size() - ihost.size()) + return (iport == 0 || port == iport); - /* No match was found */ - px_free(host); - px_free(ihost); - return false; + /* Glob (*.domain.com or *.domain.com:80) */ + if (ihost[0] == '*' && host.find(ihost.substr(1)) == host.size() - ihost.substr(1).size()) + return (iport == 0 || port == iport); - /* A match was found */ - match: - px_free(host); - px_free(ihost); - return true; -} - -static void * -_constructor() -{ - pxIgnoreModule *self = (pxIgnoreModule *) px_malloc0(sizeof(pxIgnoreModule)); - self->ignore = _ignore; - return self; -} + /* No match was found */ + return false; + } +}; -bool -px_module_load(pxModuleManager *self) -{ - return px_module_manager_register_module(self, pxIgnoreModule, _constructor, px_free); -} +PX_MODULE_LOAD(ignore_module, domain, true); diff --git a/libproxy/modules/ignore_ip.cpp b/libproxy/modules/ignore_ip.cpp index 2ea20ae..81be231 100644 --- a/libproxy/modules/ignore_ip.cpp +++ b/libproxy/modules/ignore_ip.cpp @@ -17,10 +17,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ******************************************************************************/ -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <stdint.h> +#include <cstdio> +#include <cstring> #ifdef _WIN32 #define _WIN32_WINNT 0x0501 @@ -35,183 +33,161 @@ typedef unsigned short int sa_family_t; #include <netinet/in.h> #endif -#include "../misc.hpp" -#include "../modules.hpp" +#include "../module_types.hpp" -static bool +using namespace com::googlecode::libproxy; + +static inline bool _sockaddr_equals(const struct sockaddr *ip_a, const struct sockaddr *ip_b, const struct sockaddr *nm) { - if (!ip_a || !ip_b) return false; - if (ip_a->sa_family != ip_b->sa_family) return false; - if (nm && ip_a->sa_family != nm->sa_family) return false; - - /* Setup the arrays */ - uint8_t bytes = 0, *a_data = NULL, *b_data = NULL, *nm_data = NULL; - if (ip_a->sa_family == AF_INET) - { - bytes = 32 / 8; - a_data = (uint8_t *) &((struct sockaddr_in *) ip_a)->sin_addr; - b_data = (uint8_t *) &((struct sockaddr_in *) ip_b)->sin_addr; - nm_data = nm ? (uint8_t *) &((struct sockaddr_in *) nm)->sin_addr : NULL; - } - else if (ip_a->sa_family == AF_INET6) - { - bytes = 128 / 8; - a_data = (uint8_t *) &((struct sockaddr_in6 *) ip_a)->sin6_addr; - b_data = (uint8_t *) &((struct sockaddr_in6 *) ip_b)->sin6_addr; - nm_data = nm ? (uint8_t *) &((struct sockaddr_in6 *) nm)->sin6_addr : NULL; - } - else - return false; - - for (int i=0 ; i < bytes ; i++) - { - if (nm && (a_data[i] & nm_data[i]) != (b_data[i] & nm_data[i])) - return false; - else if (!nm && (a_data[i] != b_data[i])) - return false; - } - return true; + if (!ip_a || !ip_b) return false; + if (ip_a->sa_family != ip_b->sa_family) return false; + if (nm && ip_a->sa_family != nm->sa_family) return false; + + /* Setup the arrays */ + uint8_t bytes = 0, *a_data = NULL, *b_data = NULL, *nm_data = NULL; + if (ip_a->sa_family == AF_INET) + { + bytes = 32 / 8; + a_data = (uint8_t *) &((struct sockaddr_in *) ip_a)->sin_addr; + b_data = (uint8_t *) &((struct sockaddr_in *) ip_b)->sin_addr; + nm_data = nm ? (uint8_t *) &((struct sockaddr_in *) nm)->sin_addr : NULL; + } + else if (ip_a->sa_family == AF_INET6) + { + bytes = 128 / 8; + a_data = (uint8_t *) &((struct sockaddr_in6 *) ip_a)->sin6_addr; + b_data = (uint8_t *) &((struct sockaddr_in6 *) ip_b)->sin6_addr; + nm_data = nm ? (uint8_t *) &((struct sockaddr_in6 *) nm)->sin6_addr : NULL; + } + else + return false; + + for (int i=0 ; i < bytes ; i++) + { + if (nm && (a_data[i] & nm_data[i]) != (b_data[i] & nm_data[i])) + return false; + else if (!nm && (a_data[i] != b_data[i])) + return false; + } + return true; } -static struct sockaddr * -_sockaddr_from_string(const char *ip, int len) +static inline sockaddr * +_sockaddr_from_string(string ip) { - if (!ip) return NULL; - struct sockaddr *result = NULL; - - /* Copy the string */ - if (len >= 0) - ip = px_strndup(ip, len); - else - ip = px_strdup(ip); - - /* Try to parse */ - struct addrinfo *info = NULL; - struct addrinfo flags; - flags.ai_family = AF_UNSPEC; - flags.ai_socktype = 0; - flags.ai_protocol = 0; - flags.ai_flags = AI_NUMERICHOST; - if (getaddrinfo(ip, NULL, &flags, &info) != 0 || !info) goto out; - - /* Copy the results into our buffer */ - result = (struct sockaddr *) px_malloc0(info->ai_addrlen); - memcpy(result, info->ai_addr, info->ai_addrlen); - - out: - px_free((char *) ip); - return result; + struct sockaddr *result = NULL; + + /* Try to parse */ + struct addrinfo *info = NULL; + struct addrinfo flags; + flags.ai_family = AF_UNSPEC; + flags.ai_socktype = 0; + flags.ai_protocol = 0; + flags.ai_flags = AI_NUMERICHOST; + if (getaddrinfo(ip.c_str(), NULL, &flags, &info) != 0 || !info) return result; + + /* Copy the results into our buffer */ + if (!(result = (sockaddr *) new char[info->ai_addrlen])) return result; + memcpy(result, info->ai_addr, info->ai_addrlen); + return result; } -static struct sockaddr * +static inline sockaddr * _sockaddr_from_cidr(sa_family_t af, uint8_t cidr) { - /* IPv4 */ - if (af == AF_INET) - { - struct sockaddr_in *mask = (sockaddr_in *) px_malloc0(sizeof(struct sockaddr_in)); - mask->sin_family = af; - mask->sin_addr.s_addr = htonl(~0 << (32 - (cidr > 32 ? 32 : cidr))); - - return (struct sockaddr *) mask; - } - - /* IPv6 */ - else if (af == AF_INET6) - { - struct sockaddr_in6 *mask = (sockaddr_in6 *) px_malloc0(sizeof(struct sockaddr_in6)); - mask->sin6_family = af; - for (uint8_t i=0 ; i < sizeof(mask->sin6_addr) ; i++) - mask->sin6_addr.s6_addr[i] = ~0 << (8 - (8*i > cidr ? 0 : cidr-8*i < 8 ? cidr-8*i : 8) ); - - return (struct sockaddr *) mask; - } - - return NULL; + /* IPv4 */ + if (af == AF_INET) + { + sockaddr_in *mask = new sockaddr_in; + mask->sin_family = af; + mask->sin_addr.s_addr = htonl(~0 << (32 - (cidr > 32 ? 32 : cidr))); + + return (struct sockaddr *) mask; + } + + /* IPv6 */ + else if (af == AF_INET6) + { + sockaddr_in6 *mask = new sockaddr_in6; + mask->sin6_family = af; + for (uint8_t i=0 ; i < sizeof(mask->sin6_addr) ; i++) + mask->sin6_addr.s6_addr[i] = ~0 << (8 - (8*i > cidr ? 0 : cidr-8*i < 8 ? cidr-8*i : 8) ); + + return (sockaddr *) mask; + } + + return NULL; } -static bool -_ignore(struct _pxIgnoreModule *self, pxURL *url, const char *ignore) -{ - if (!url || !ignore) return false; - - - bool result = false; - uint32_t port = 0; - const struct sockaddr **dst_ips = px_url_get_ips(url, false); - const struct sockaddr *dst_ip = dst_ips && dst_ips[0] ? dst_ips[0] : NULL; - struct sockaddr *ign_ip = NULL, *net_ip = NULL; - - /* - * IPv4 - * IPv6 - */ - if ((ign_ip = _sockaddr_from_string(ignore, -1))) - goto out; - - /* - * IPv4/CIDR - * IPv4/IPv4 - * IPv6/CIDR - * IPv6/IPv6 - */ - if (strchr(ignore, '/')) - { - ign_ip = _sockaddr_from_string(ignore, strchr(ignore, '/') - ignore); - net_ip = _sockaddr_from_string(strchr(ignore, '/') + 1, -1); - - /* If CIDR notation was used, get the netmask */ - if (ign_ip && !net_ip) - { - uint32_t cidr = 0; - if (sscanf(strchr(ignore, '/') + 1, "%d", &cidr) == 1) - net_ip = _sockaddr_from_cidr(ign_ip->sa_family, cidr); - } - - if (ign_ip && net_ip && ign_ip->sa_family == net_ip->sa_family) - goto out; - - px_free(ign_ip); - px_free(net_ip); - ign_ip = NULL; - net_ip = NULL; - } - - /* - * IPv4:port - * [IPv6]:port - */ - if (strrchr(ignore, ':') && sscanf(strrchr(ignore, ':'), ":%u", &port) == 1 && port > 0) - { - ign_ip = _sockaddr_from_string(ignore, strrchr(ignore, ':') - ignore); - - /* Make sure this really is just a port and not just an IPv6 address */ - if (ign_ip && (ign_ip->sa_family != AF_INET6 || ignore[0] == '[')) - goto out; - - px_free(ign_ip); - ign_ip = NULL; - port = 0; - } - - out: - result = _sockaddr_equals(dst_ip, ign_ip, net_ip); - px_free(ign_ip); - px_free(net_ip); - return port != 0 ? (port == px_url_get_port(url) && result): result; -} - -static void * -_constructor() -{ - pxIgnoreModule *self = (pxIgnoreModule*) px_malloc0(sizeof(pxIgnoreModule)); - self->ignore = _ignore; - return self; -} - -bool -px_module_load(pxModuleManager *self) -{ - return px_module_manager_register_module(self, pxIgnoreModule, _constructor, px_free); -} +class ip_ignore_module : public ignore_module { +public: + PX_MODULE_ID(NULL); + + virtual bool ignore(url& url, string ignore) { + bool result = false; + uint32_t port = 0; + const struct sockaddr *dst_ip = url.get_ips(false)->size() > 0 ? (*url.get_ips(false))[0] : NULL; + struct sockaddr *ign_ip = NULL, *net_ip = NULL; + + /* + * IPv4 + * IPv6 + */ + if ((ign_ip = _sockaddr_from_string(ignore))) + goto out; + + /* + * IPv4/CIDR + * IPv4/IPv4 + * IPv6/CIDR + * IPv6/IPv6 + */ + if (ignore.find('/') != string::npos) + { + ign_ip = _sockaddr_from_string(ignore.substr(0, ignore.find('/'))); + net_ip = _sockaddr_from_string(ignore.substr(ignore.find('/') + 1)); + + /* If CIDR notation was used, get the netmask */ + if (ign_ip && !net_ip) + { + uint32_t cidr = 0; + if (sscanf(ignore.substr(ignore.find('/') + 1).c_str(), "%d", &cidr) == 1) + net_ip = _sockaddr_from_cidr(ign_ip->sa_family, cidr); + } + + if (ign_ip && net_ip && ign_ip->sa_family == net_ip->sa_family) + goto out; + + delete ign_ip; + delete net_ip; + ign_ip = NULL; + net_ip = NULL; + } + + /* + * IPv4:port + * [IPv6]:port + */ + if (ignore.rfind(':') != string::npos && sscanf(ignore.substr(ignore.rfind(':')).c_str(), ":%u", &port) == 1 && port > 0) + { + ign_ip = _sockaddr_from_string(ignore.substr(ignore.rfind(':')).c_str()); + + /* Make sure this really is just a port and not just an IPv6 address */ + if (ign_ip && (ign_ip->sa_family != AF_INET6 || ignore[0] == '[')) + goto out; + + delete ign_ip; + ign_ip = NULL; + port = 0; + } + + out: + result = _sockaddr_equals(dst_ip, ign_ip, net_ip); + free(ign_ip); + free(net_ip); + return port != 0 ? (port == url.get_port() && result) : result; + } +}; + +PX_MODULE_LOAD(ignore_module, ip, true); diff --git a/libproxy/modules/network_networkmanager.cpp b/libproxy/modules/network_networkmanager.cpp index 40b98df..e37a4c7 100644 --- a/libproxy/modules/network_networkmanager.cpp +++ b/libproxy/modules/network_networkmanager.cpp @@ -17,94 +17,77 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ******************************************************************************/ -#include <stdlib.h> -#include <string.h> -#include <stdint.h> - -#include "../misc.hpp" -#include "../modules.hpp" +#include "../module_types.hpp" #include <dbus/dbus.h> #include <NetworkManager/NetworkManager.h> -typedef struct _pxNetworkManagerNetworkModule { - PX_MODULE_SUBCLASS(pxNetworkModule); - DBusConnection *conn; -} pxNetworkManagerNetworkModule; - -static void -_destructor(void *s) -{ - pxNetworkManagerNetworkModule *self = (pxNetworkManagerNetworkModule *) s; - - dbus_connection_close(self->conn); - px_free(self); -} - -static bool -_changed(pxNetworkModule *s) -{ - pxNetworkManagerNetworkModule *self = (pxNetworkManagerNetworkModule *) s; - - // Make sure we have a valid connection with a proper match - DBusConnection *conn = self->conn; - if (!conn || !dbus_connection_get_is_connected(conn)) - { - // If the connection was disconnected, - // close it an clear the queue - if (conn) +using namespace com::googlecode::libproxy; + +class networkmanager_network_module : public network_module { +public: + PX_MODULE_ID(NULL); + + networkmanager_network_module() { + this->conn = NULL; + } + + ~networkmanager_network_module() { + if (this->conn) dbus_connection_close(this->conn); + } + + bool changed() { + // Make sure we have a valid connection with a proper match + DBusConnection *conn = this->conn; + if (!conn || !dbus_connection_get_is_connected(conn)) { - dbus_connection_close(conn); - dbus_connection_read_write(conn, 0); - for (DBusMessage *msg=NULL ; (msg = dbus_connection_pop_message(conn)) ; dbus_message_unref(msg)); + // If the connection was disconnected, + // close it an clear the queue + if (conn) + { + dbus_connection_close(conn); + dbus_connection_read_write(conn, 0); + for (DBusMessage *msg=NULL ; (msg = dbus_connection_pop_message(conn)) ; dbus_message_unref(msg)); + } + + // Create a new connections + conn = dbus_bus_get_private(DBUS_BUS_SYSTEM, NULL); + this->conn = conn; + if (!conn) return false; + + // If connection was successful, set it up + dbus_connection_set_exit_on_disconnect(conn, false); + dbus_bus_add_match(conn, "type='signal',interface='" NM_DBUS_INTERFACE "',member='StateChange'", NULL); + dbus_connection_flush(conn); } - // Create a new connections - conn = dbus_bus_get_private(DBUS_BUS_SYSTEM, NULL); - self->conn = conn; - if (!conn) return false; + // We are guaranteed a connection, + // so check for incoming messages + bool changed = false; + while (true) + { + DBusMessage *msg = NULL; + uint32_t state; - // If connection was successful, set it up - dbus_connection_set_exit_on_disconnect(conn, false); - dbus_bus_add_match(conn, "type='signal',interface='" NM_DBUS_INTERFACE "',member='StateChange'", NULL); - dbus_connection_flush(conn); - } + // Pull messages off the queue + dbus_connection_read_write(conn, 0); + if (!(msg = dbus_connection_pop_message(conn))) + break; + + // If a message is the right type and value, + // we'll reset the network + if (dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &state, DBUS_TYPE_INVALID)) + if (state == NM_STATE_CONNECTED) + changed = true; - // We are guaranteed a connection, - // so check for incoming messages - bool changed = false; - while (true) - { - DBusMessage *msg = NULL; - uint32_t state; - - // Pull messages off the queue - dbus_connection_read_write(conn, 0); - if (!(msg = dbus_connection_pop_message(conn))) - break; - - // If a message is the right type and value, - // we'll reset the network - if (dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &state, DBUS_TYPE_INVALID)) - if (state == NM_STATE_CONNECTED) - changed = true; - - dbus_message_unref(msg); + dbus_message_unref(msg); + } + + return changed; } - return changed; -} - -static void * -_constructor() -{ - pxNetworkManagerNetworkModule *self = (pxNetworkManagerNetworkModule*) px_malloc0(sizeof(pxNetworkManagerNetworkModule)); - self->__parent__.changed = _changed; - return self; -} - -bool -px_module_load(pxModuleManager *self) -{ - return px_module_manager_register_module(self, pxNetworkModule, _constructor, _destructor); -} +private: + DBusConnection *conn; +}; + +PX_MODULE_LOAD(network_module, networkmanager, true); diff --git a/libproxy/modules/pacrunner_mozjs.cpp b/libproxy/modules/pacrunner_mozjs.cpp index d24dea1..74cbeaa 100644 --- a/libproxy/modules/pacrunner_mozjs.cpp +++ b/libproxy/modules/pacrunner_mozjs.cpp @@ -17,18 +17,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ******************************************************************************/ -#include <stdlib.h> -#include <string.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <netdb.h> -#include <arpa/inet.h> -#include <netinet/in.h> -#define __USE_BSD -#include <unistd.h> - -#include "../misc.hpp" -#include "../modules.hpp" +#include <cstring> // ? + +#include "../module_types.hpp" +using namespace com::googlecode::libproxy; #include <jsapi.h> #include "pacutils.h" @@ -41,21 +33,9 @@ #define INET6_ADDRSTRLEN 46 #endif -typedef struct { - JSRuntime *run; - JSContext *ctx; - JSClass *cls; - char *pac; -} ctxStore; - -typedef struct _pxMozillaPACRunnerModule { - PX_MODULE_SUBCLASS(pxPACRunnerModule); - ctxStore *ctxs; -} pxMozillaPACRunnerModule; - static JSBool dnsResolve(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { // Get hostname argument - char *tmp = px_strdup(JS_GetStringBytes(JS_ValueToString(cx, argv[0]))); + char *tmp = JS_strdup(cx, JS_GetStringBytes(JS_ValueToString(cx, argv[0]))); // Set the default return value *rval = JSVAL_NULL; @@ -66,8 +46,9 @@ static JSBool dnsResolve(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, goto out; // Allocate the IP address - px_free(tmp); - tmp = (char *) px_malloc0(INET6_ADDRSTRLEN+1); + JS_free(cx, tmp); + tmp = (char *) JS_malloc(cx, INET6_ADDRSTRLEN+1); + memset(tmp, 0, INET6_ADDRSTRLEN+1); // Try for IPv4 and IPv6 if (!inet_ntop(info->ai_family, @@ -84,7 +65,7 @@ static JSBool dnsResolve(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, out: if (info) freeaddrinfo(info); - px_free(tmp); + JS_free(cx, tmp); return true; } @@ -95,136 +76,87 @@ static JSBool myIpAddress(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval arg = STRING_TO_JSVAL(myhost); return dnsResolve(cx, obj, 1, &arg, rval); } - px_free(hostname); + JS_free(cx, hostname); *rval = JSVAL_NULL; return true; } -static void ctxs_free(ctxStore *self) -{ - if (!self) return; - if (self->ctx) JS_DestroyContext(self->ctx); - if (self->run) JS_DestroyRuntime(self->run); - if (self->cls) px_free(self->cls); - px_free(self->pac); - px_free(self); -} - -static ctxStore *ctxs_new(pxPAC *pac) -{ - JSObject *global = NULL; - jsval rval; - - // Create the basic context - ctxStore *self = (ctxStore*) px_malloc0(sizeof(ctxStore)); - - // Setup Javascript global class - self->cls = (JSClass*) px_malloc0(sizeof(JSClass)); - self->cls->name = "global"; - self->cls->flags = 0; - self->cls->addProperty = JS_PropertyStub; - self->cls->delProperty = JS_PropertyStub; - self->cls->getProperty = JS_PropertyStub; - self->cls->setProperty = JS_PropertyStub; - self->cls->enumerate = JS_EnumerateStub; - self->cls->resolve = JS_ResolveStub; - self->cls->convert = JS_ConvertStub; - self->cls->finalize = JS_FinalizeStub; - - // Initialize Javascript runtime environment - if (!(self->run = JS_NewRuntime(1024 * 1024))) goto error; - if (!(self->ctx = JS_NewContext(self->run, 1024 * 1024))) goto error; - if (!(global = JS_NewObject(self->ctx, self->cls, NULL, NULL))) goto error; - JS_InitStandardClasses(self->ctx, global); - - // Define Javascript functions - JS_DefineFunction(self->ctx, global, "dnsResolve", dnsResolve, 1, 0); - JS_DefineFunction(self->ctx, global, "myIpAddress", myIpAddress, 0, 0); - JS_EvaluateScript(self->ctx, global, JAVASCRIPT_ROUTINES, - strlen(JAVASCRIPT_ROUTINES), "pacutils.js", 0, &rval); - - // Add PAC to the environment - JS_EvaluateScript(self->ctx, global, px_pac_to_string(pac), - strlen(px_pac_to_string(pac)), - px_url_to_string((pxURL *) px_pac_get_url(pac)), - 0, &rval); - - // Save the pac - self->pac = px_strdup(px_pac_to_string(pac)); - return self; - -error: - ctxs_free(self); - return NULL; -} - -static void -_destructor(void *s) -{ - pxMozillaPACRunnerModule * self = (pxMozillaPACRunnerModule *) s; - - ctxs_free(self->ctxs); - px_free(self); -} - -static char * -_run(pxPACRunnerModule *self, pxPAC *pac, pxURL *url) -{ - // Make sure we have the pac file and url - if (!pac) return NULL; - if (!url) return NULL; - if (!px_pac_to_string(pac) && !px_pac_reload(pac)) return NULL; - - // Get the cached context - ctxStore *ctxs = ((pxMozillaPACRunnerModule *) self)->ctxs; - - // If there is a cached context, make sure it is the same pac - if (ctxs && strcmp(ctxs->pac, px_pac_to_string(pac))) - { - ctxs_free(ctxs); - ctxs = NULL; - ((pxMozillaPACRunnerModule *) self)->ctxs = NULL; +class mozjs_pacrunner : public pacrunner { +public: + mozjs_pacrunner(const pac pac) throw (bad_alloc) { + jsval rval; + + // Set defaults + this->jsrun = NULL; + this->jsctx = NULL; + + // Setup Javascript global class + JSClass cls = { + "global", JSCLASS_GLOBAL_FLAGS, + JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub + }; + + // Initialize Javascript runtime environment + if (!(this->jsrun = JS_NewRuntime(1024 * 1024))) goto error; + if (!(this->jsctx = JS_NewContext(this->jsrun, 1024 * 1024))) goto error; + //JS_SetOptions(this->jsctx, JSOPTION_VAROBJFIX); + //JS_SetVersion(this->jsctx, JSVERSION_LATEST); + //JS_SetErrorReporter(cx, reportError); + if (!(this->jsglb = JS_NewObject(this->jsctx, &cls, NULL, NULL))) goto error; + if (!JS_InitStandardClasses(this->jsctx, this->jsglb)) goto error; + + // Define Javascript functions + JS_DefineFunction(this->jsctx, this->jsglb, "dnsResolve", dnsResolve, 1, 0); + JS_DefineFunction(this->jsctx, this->jsglb, "myIpAddress", myIpAddress, 0, 0); + JS_EvaluateScript(this->jsctx, this->jsglb, JAVASCRIPT_ROUTINES, + strlen(JAVASCRIPT_ROUTINES), "pacutils.js", 0, &rval); + + // Add PAC to the environment + JS_EvaluateScript(this->jsctx, this->jsglb, pac.to_string().c_str(), + strlen(pac.to_string().c_str()), + pac.get_url().to_string().c_str(), 0, &rval); + return; + + error: + if (this->jsctx) JS_DestroyContext(this->jsctx); + if (this->jsrun) JS_DestroyRuntime(this->jsrun); + throw bad_alloc(); } - // If no context exists (or if the pac was changed), create one - if (!ctxs) - { - if ((ctxs = ctxs_new(pac))) - ((pxMozillaPACRunnerModule *) self)->ctxs = ctxs; - else - return NULL; + ~mozjs_pacrunner() { + if (this->jsctx) JS_DestroyContext(this->jsctx); + if (this->jsrun) JS_DestroyRuntime(this->jsrun); + // JS_ShutDown()? } - // Build arguments to the FindProxyForURL() function - char *tmpurl = px_strdup(px_url_to_string(url)); - char *tmphost = px_strdup(px_url_get_host(url)); - jsval args[2] = { - STRING_TO_JSVAL(JS_NewString(ctxs->ctx, tmpurl, strlen(tmpurl))), - STRING_TO_JSVAL(JS_NewString(ctxs->ctx, tmphost, strlen(tmphost))) - }; - - // Find the proxy (call FindProxyForURL()) - jsval rval; - JSBool result = JS_CallFunctionName(ctxs->ctx, JS_GetGlobalObject(ctxs->ctx), "FindProxyForURL", 2, args, &rval); - if (!result) return NULL; - char *answer = px_strdup(JS_GetStringBytes(JS_ValueToString(ctxs->ctx, rval))); - if (!answer || !strcmp(answer, "undefined")) { - px_free(answer); - return NULL; + string run(const url url) throw (bad_alloc) { + // Build arguments to the FindProxyForURL() function + char *tmpurl = JS_strdup(this->jsctx, url.to_string().c_str()); + char *tmphost = JS_strdup(this->jsctx, url.get_host().c_str()); + if (!tmpurl || !tmphost) { + if (tmpurl) JS_free(this->jsctx, tmpurl); + if (tmphost) JS_free(this->jsctx, tmphost); + throw bad_alloc(); + } + jsval args[2] = { + STRING_TO_JSVAL(JS_NewString(this->jsctx, tmpurl, strlen(tmpurl))), + STRING_TO_JSVAL(JS_NewString(this->jsctx, tmphost, strlen(tmphost))) + }; + + // Find the proxy (call FindProxyForURL()) + jsval rval; + JSBool result = JS_CallFunctionName(this->jsctx, this->jsglb, "FindProxyForURL", 2, args, &rval); + if (!result) return ""; + string answer = string(JS_GetStringBytes(JS_ValueToString(this->jsctx, rval))); + if (answer == "undefined") return ""; + return answer; } - return answer; -} -static void * -_constructor() -{ - pxMozillaPACRunnerModule *self = (pxMozillaPACRunnerModule*) px_malloc0(sizeof(pxMozillaPACRunnerModule)); - self->__parent__.run = _run; - return self; -} +private: + JSRuntime *jsrun; + JSContext *jsctx; + JSObject *jsglb; +}; -bool -px_module_load(pxModuleManager *self) -{ - return px_module_manager_register_module(self, pxPACRunnerModule, _constructor, _destructor); -} +PX_DEFINE_PACRUNNER_MODULE(mozjs, true); diff --git a/libproxy/modules/pacrunner_webkit.cpp b/libproxy/modules/pacrunner_webkit.cpp index eb7d661..592bbae 100644 --- a/libproxy/modules/pacrunner_webkit.cpp +++ b/libproxy/modules/pacrunner_webkit.cpp @@ -17,25 +17,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ******************************************************************************/ -#include <stdlib.h> -#include <string.h> -#include <sys/types.h> -#ifdef _WIN32 -#define _WIN32_WINNT 0x0501 -#include <winsock2.h> -#include <ws2tcpip.h> -#include <../platform/win32/inet.h> -#else -#include <sys/socket.h> -#include <netdb.h> -#include <arpa/inet.h> -#include <netinet/in.h> -#endif -#define __USE_BSD -#include <unistd.h> - -#include "../misc.hpp" -#include "../modules.hpp" +#include "../module_types.hpp" +using namespace com::googlecode::libproxy; #include <JavaScriptCore/JavaScript.h> #include "pacutils.h" @@ -48,19 +31,9 @@ #define INET6_ADDRSTRLEN 46 #endif -typedef struct { - JSGlobalContextRef ctx; - char *pac; -} ctxStore; - -typedef struct _pxWebKitPACRunnerModule { - PX_MODULE_SUBCLASS(pxPACRunnerModule); - ctxStore *ctxs; -} pxWebKitPACRunnerModule; - -static char *jstr2str(JSStringRef str, bool release) +static char *jstr2str(JSStringRef str, bool release) throw (bad_alloc) { - char *tmp = (char*) px_malloc0(JSStringGetMaximumUTF8CStringSize(str)+1); + char *tmp = new char[JSStringGetMaximumUTF8CStringSize(str)+1]; JSStringGetUTF8CString(str, tmp, JSStringGetMaximumUTF8CStringSize(str)+1); if (release) JSStringRelease(str); return tmp; @@ -78,10 +51,10 @@ static JSValueRef dnsResolve(JSContextRef ctx, JSObjectRef func, JSObjectRef sel struct addrinfo *info; if (getaddrinfo(tmp, NULL, NULL, &info)) return NULL; - px_free(tmp); + delete tmp; // Try for IPv4 - tmp = (char*) px_malloc0(INET6_ADDRSTRLEN+1); + tmp = new char[INET6_ADDRSTRLEN+1]; if (!inet_ntop(info->ai_family, &((struct sockaddr_in *) info->ai_addr)->sin_addr, tmp, INET_ADDRSTRLEN+1) > 0) @@ -91,7 +64,7 @@ static JSValueRef dnsResolve(JSContextRef ctx, JSObjectRef func, JSObjectRef sel tmp, INET6_ADDRSTRLEN+1) > 0) { freeaddrinfo(info); - px_free(tmp); + delete tmp; return NULL; } freeaddrinfo(info); @@ -100,7 +73,7 @@ static JSValueRef dnsResolve(JSContextRef ctx, JSObjectRef func, JSObjectRef sel JSStringRef str = JSStringCreateWithUTF8CString(tmp); JSValueRef ret = JSValueMakeString(ctx, str); JSStringRelease(str); - px_free(tmp); + delete tmp; return ret; } @@ -118,125 +91,77 @@ static JSValueRef myIpAddress(JSContextRef ctx, JSObjectRef func, JSObjectRef se return NULL; } -static void ctxs_free(ctxStore *self) -{ - if (!self) return; - JSGarbageCollect(self->ctx); - JSGlobalContextRelease(self->ctx); - px_free(self->pac); - px_free(self); -} - -static ctxStore *ctxs_new(pxPAC *pac) -{ - JSStringRef str = NULL; - JSObjectRef func = NULL; - - // Create the basic context - ctxStore *self = (ctxStore*) px_malloc0(sizeof(ctxStore)); - self->pac = px_strdup(px_pac_to_string(pac)); - if (!(self->ctx = JSGlobalContextCreate(NULL))) goto error; - - // Add dnsResolve into the context - str = JSStringCreateWithUTF8CString("dnsResolve"); - func = JSObjectMakeFunctionWithCallback(self->ctx, str, dnsResolve); - JSObjectSetProperty(self->ctx, JSContextGetGlobalObject(self->ctx), str, func, kJSPropertyAttributeNone, NULL); - JSStringRelease(str); - - // Add myIpAddress into the context - str = JSStringCreateWithUTF8CString("myIpAddress"); - func = JSObjectMakeFunctionWithCallback(self->ctx, str, myIpAddress); - JSObjectSetProperty(self->ctx, JSContextGetGlobalObject(self->ctx), str, func, kJSPropertyAttributeNone, NULL); - JSStringRelease(str); +class webkit_pacrunner : public pacrunner { +public: + ~webkit_pacrunner() { + JSGarbageCollect(this->jsctx); + JSGlobalContextRelease(this->jsctx); + } - // Add all other routines into the context - str = JSStringCreateWithUTF8CString(JAVASCRIPT_ROUTINES); - if (!JSCheckScriptSyntax(self->ctx, str, NULL, 0, NULL)) goto error; - JSEvaluateScript(self->ctx, str, NULL, NULL, 1, NULL); - JSStringRelease(str); + webkit_pacrunner(const pac pac) throw (bad_alloc) { + JSStringRef str = NULL; + JSObjectRef func = NULL; - // Add the PAC into the context - str = JSStringCreateWithUTF8CString(self->pac); - if (!JSCheckScriptSyntax(self->ctx, str, NULL, 0, NULL)) goto error; - JSEvaluateScript(self->ctx, str, NULL, NULL, 1, NULL); - JSStringRelease(str); + // Create the basic context + if (!(this->jsctx = JSGlobalContextCreate(NULL))) goto error; - return self; - -error: - if (str) JSStringRelease(str); - ctxs_free(self); - return NULL; -} + // Add dnsResolve into the context + str = JSStringCreateWithUTF8CString("dnsResolve"); + func = JSObjectMakeFunctionWithCallback(this->jsctx, str, dnsResolve); + JSObjectSetProperty(this->jsctx, JSContextGetGlobalObject(this->jsctx), str, func, kJSPropertyAttributeNone, NULL); + JSStringRelease(str); -static void -_destructor(void *s) -{ - pxWebKitPACRunnerModule *self = (pxWebKitPACRunnerModule *) s; + // Add myIpAddress into the context + str = JSStringCreateWithUTF8CString("myIpAddress"); + func = JSObjectMakeFunctionWithCallback(this->jsctx, str, myIpAddress); + JSObjectSetProperty(this->jsctx, JSContextGetGlobalObject(this->jsctx), str, func, kJSPropertyAttributeNone, NULL); + JSStringRelease(str); - ctxs_free(self->ctxs); - px_free(self); -} + // Add all other routines into the context + str = JSStringCreateWithUTF8CString(JAVASCRIPT_ROUTINES); + if (!JSCheckScriptSyntax(this->jsctx, str, NULL, 0, NULL)) goto error; + JSEvaluateScript(this->jsctx, str, NULL, NULL, 1, NULL); + JSStringRelease(str); -static char * -_run(pxPACRunnerModule *self, pxPAC *pac, pxURL *url) -{ - JSStringRef str = NULL; - JSValueRef val = NULL; - char *tmp = NULL; - - // Make sure we have the pac file and url - if (!pac) return NULL; - if (!url) return NULL; - if (!px_pac_to_string(pac) && !px_pac_reload(pac)) return NULL; - - // Get the cached context - ctxStore *ctxs = ((pxWebKitPACRunnerModule *) self)->ctxs; - - // If there is a cached context, make sure it is the same pac - if (ctxs && strcmp(ctxs->pac, px_pac_to_string(pac))) - { - ctxs_free(ctxs); - ctxs = NULL; - } + // Add the PAC into the context + str = JSStringCreateWithUTF8CString(pac.to_string().c_str()); + if (!JSCheckScriptSyntax(this->jsctx, str, NULL, 0, NULL)) goto error; + JSEvaluateScript(this->jsctx, str, NULL, NULL, 1, NULL); + JSStringRelease(str); + return; - // If no context exists (or if the pac was changed), create one - if (!ctxs) - { - if ((ctxs = ctxs_new(pac))) - ((pxWebKitPACRunnerModule *) self)->ctxs = ctxs; - else - return NULL; + error: + if (str) JSStringRelease(str); + if (this->jsctx) { + JSGarbageCollect(this->jsctx); + JSGlobalContextRelease(this->jsctx); + } + throw bad_alloc(); } - // Run the PAC - tmp = px_strcat("FindProxyForURL(\"", px_url_to_string(url), "\", \"", px_url_get_host(url), "\");", NULL); - str = JSStringCreateWithUTF8CString(tmp); - px_free(tmp); tmp = NULL; - if (!JSCheckScriptSyntax(ctxs->ctx, str, NULL, 0, NULL)) goto error; - if (!(val = JSEvaluateScript(ctxs->ctx, str, NULL, NULL, 1, NULL))) goto error; - if (!JSValueIsString(ctxs->ctx, val)) goto error; - JSStringRelease(str); + string run(const url url) throw (bad_alloc) { + JSStringRef str = NULL; + JSValueRef val = NULL; + string tmp; + + // Run the PAC + tmp = string("FindProxyForURL(\"") + url.to_string() + string("\", \"") + url.get_host() + "\");"; + str = JSStringCreateWithUTF8CString(tmp.c_str()); + if (!JSCheckScriptSyntax(this->jsctx, str, NULL, 0, NULL)) goto error; + if (!(val = JSEvaluateScript(this->jsctx, str, NULL, NULL, 1, NULL))) goto error; + if (!JSValueIsString(this->jsctx, val)) goto error; + JSStringRelease(str); - // Convert the return value to a string - return jstr2str(JSValueToStringCopy(ctxs->ctx, val, NULL), true); + // Convert the return value to a string + return jstr2str(JSValueToStringCopy(this->jsctx, val, NULL), true); -error: - if (str) JSStringRelease(str); - ctxs_free(ctxs); - return tmp; -} + error: + if (str) JSStringRelease(str); + throw bad_alloc(); + } -static void * -_constructor() -{ - pxWebKitPACRunnerModule *self = (pxWebKitPACRunnerModule*) px_malloc0(sizeof(pxWebKitPACRunnerModule)); - self->__parent__.run = _run; - return self; -} +private: + JSGlobalContextRef jsctx; +}; -bool -px_module_load(pxModuleManager *self) -{ - return px_module_manager_register_module(self, pxPACRunnerModule, _constructor, _destructor); -} +PX_DEFINE_PACRUNNER_MODULE(webkit, true); diff --git a/libproxy/modules/pxgconf.cpp b/libproxy/modules/pxgconf.cpp new file mode 100644 index 0000000..0164413 --- /dev/null +++ b/libproxy/modules/pxgconf.cpp @@ -0,0 +1,180 @@ +#include <cstdio> +#include <unistd.h> +#include <signal.h> + +#include <glib.h> +#include <gconf/gconf.h> +#include <gconf/gconf-client.h> + +using namespace std; + +static GMainLoop* loop = NULL; + +static int _print_value(const GConfValue *value, const char *suffix) { + int count = 0; + GSList* cursor = NULL; + + if (!value) return 0; + + switch (value->type) { + case GCONF_VALUE_STRING: + return printf("%s%s", gconf_value_get_string(value), suffix); + case GCONF_VALUE_INT: + return printf("%d%s", gconf_value_get_int(value), suffix); + case GCONF_VALUE_FLOAT: + return printf("%f%s", gconf_value_get_float(value), suffix); + case GCONF_VALUE_BOOL: + if (gconf_value_get_bool(value)) + return printf("true%s", suffix); + return printf("false%s", suffix); + case GCONF_VALUE_LIST: + cursor = gconf_value_get_list(value); + for ( ; cursor ; cursor = g_slist_next(cursor)) + count += _print_value((const GConfValue *) cursor->data, cursor->next ? "," : suffix); + return count; + case GCONF_VALUE_PAIR: + return _print_value(gconf_value_get_car(value), ",") + + _print_value(gconf_value_get_cdr(value), suffix); + } + return 0; +} + +static void _on_value_change(GConfClient *client, guint cnxn_id, GConfEntry *entry, void *user_data) { + printf("%s\t", gconf_entry_get_key(entry)); + _print_value(gconf_entry_get_value(entry), "\n"); +} + +static void _on_sig(int signal) { + g_main_loop_quit(loop); +} + +static gboolean _error(GIOChannel *source, GIOCondition condition, gpointer data) { + g_main_loop_quit(loop); + return false; +} + +static gboolean _set_key(const char *key, const char *val) { + gboolean error = false; + GConfClient *client = gconf_client_get_default(); + GConfValue *value = gconf_client_get(client, key, NULL); + GConfValueType type = value ? value->type : GCONF_VALUE_STRING; + gconf_value_free(value); + + switch (type) { + case GCONF_VALUE_STRING: + error = !gconf_client_set_string(client, key, val, NULL); + break; + case GCONF_VALUE_INT: + int ival; + error = sscanf(val, "%d", &ival) != 1; + error = error || !gconf_client_set_int(client, key, ival, NULL); + break; + case GCONF_VALUE_FLOAT: + int fval; + error = sscanf(val, "%f", &fval) != 1; + error = error || !gconf_client_set_float(client, key, fval, NULL); + break; + case GCONF_VALUE_BOOL: + error = !gconf_client_set_float(client, key, !g_strcmp0(val, "true"), NULL); + break; + case GCONF_VALUE_LIST: + case GCONF_VALUE_PAIR: + default: + g_critical("Invalid value type!"); + error = true; + } + + g_object_unref(client); + return !error; +} + +static gboolean _stdin(GIOChannel *source, GIOCondition condition, gpointer data) { + gchar *key, *val; + GIOStatus st = g_io_channel_read_line(source, &key, NULL, NULL, NULL); + + // Remove the trailing '\n' + for (int i=0 ; key && key[i] ; i++) + if (key[i] == '\n') + key[i] = NULL; + + // If we were successful + if (key && st == G_IO_STATUS_NORMAL) { + if (!g_strrstr(key, "\t")) + goto exit; + + val = g_strrstr(key, "\t") + 1; + *(val-1) = NULL; + + if (!_set_key(key, val)) + goto exit; + + g_free(key); + return true; + } + else if (key && st == G_IO_STATUS_AGAIN) { + g_free(key); + return _stdin(source, condition, data); + } + +exit: + g_free(key); + return _error(source, condition, data); +} + +int main(int argc, char **argv) { + if (argc < 2) return 1; + + // Register sighup handler + if (signal(SIGHUP, _on_sig) == SIG_ERR || signal(SIGPIPE, _on_sig) == SIG_ERR) { + fprintf(stderr, "Unable to trap signals!"); + return 2; + } + + // Switch stdout to line buffering + if (setvbuf(stdout, NULL, _IOLBF, 0)) { + fprintf(stderr, "Unable to switch stdout to line buffering!"); + return 3; + } + + // Switch stdin to line buffering + if (setvbuf(stdin, NULL, _IOLBF, 0)) { + fprintf(stderr, "Unable to switch stdin to line buffering!"); + return 4; + } + + // Init + g_type_init(); + + // Get the main loop + loop = g_main_loop_new(NULL, false); + + // Setup our GIO Channels + GIOChannel* inchan = g_io_channel_unix_new(fileno(stdin)); + GIOChannel* outchan = g_io_channel_unix_new(fileno(stdout)); + g_io_add_watch(inchan, G_IO_IN, _stdin, NULL); + g_io_add_watch(inchan, G_IO_PRI, _stdin, NULL); + g_io_add_watch(inchan, G_IO_ERR, _error, NULL); + g_io_add_watch(inchan, G_IO_HUP, _error, NULL); + g_io_add_watch(outchan, G_IO_ERR, _error, NULL); + g_io_add_watch(outchan, G_IO_HUP, _error, NULL); + + // Get GConf client + GConfClient* client = gconf_client_get_default(); + + // Add server notifications for all keys + for (int i=1 ; i < argc ; i++) { + gconf_client_add_dir(client, argv[i], GCONF_CLIENT_PRELOAD_NONE, NULL); + gconf_client_notify_add(client, argv[i], _on_value_change, NULL, NULL, NULL); + gconf_client_notify(client, argv[i]); + } + + g_main_loop_run(loop); + + // Cleanup + g_object_unref(client); + g_io_channel_shutdown(inchan, FALSE, NULL); + g_io_channel_shutdown(outchan, FALSE, NULL); + g_io_channel_unref(inchan); + g_io_channel_unref(outchan); + g_main_loop_unref(loop); +} diff --git a/libproxy/modules/wpad_dns.cpp b/libproxy/modules/wpad_dns.cpp index a8858e5..8918560 100644 --- a/libproxy/modules/wpad_dns.cpp +++ b/libproxy/modules/wpad_dns.cpp @@ -17,50 +17,37 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ******************************************************************************/ -#include <stdlib.h> -#include <string.h> +#include "../module_types.hpp" -#include "../misc.hpp" -#include "../modules.hpp" -#include "../pac.hpp" +using namespace com::googlecode::libproxy; -typedef struct _pxDNSWPADModule { - PX_MODULE_SUBCLASS(pxWPADModule); - bool rewound; -} pxDNSWPADModule; +class dns_wpad_module : public wpad_module { +public: + PX_MODULE_ID(NULL); -static pxPAC * -_next(pxWPADModule *self) -{ - if (((pxDNSWPADModule *) self)->rewound) - { - pxPAC *pac = px_pac_new_from_string("http://wpad/wpad.dat"); - self->found = pac != NULL; - return pac; + dns_wpad_module() { + this->last = NULL; } - else - return NULL; -} -static void -_rewind(pxWPADModule *self) -{ - ((pxDNSWPADModule *) self)->rewound = true; -} + bool found() { + return this->last != NULL; + } + + pac* next() { + if (this->last) return NULL; + + try { this->last = new pac(url("http://wpad/wpad.dat")); } + catch (io_error& e) { } + + return this->last; + } + + void rewind() { + this->last = NULL; + } -static void * -_constructor() -{ - pxDNSWPADModule *self = (pxDNSWPADModule*) px_malloc0(sizeof(pxDNSWPADModule)); - self->rewound = true; - self->__parent__.found = false; - self->__parent__.next = _next; - self->__parent__.rewind = _rewind; - return self; -} +private: + pac* last; +}; -bool -px_module_load(pxModuleManager *self) -{ - return px_module_manager_register_module(self, pxWPADModule, _constructor, px_free); -} +PX_MODULE_LOAD(wpad_module, dns, true); diff --git a/libproxy/modules/wpad_dnsdevolution.cpp b/libproxy/modules/wpad_dnsdevolution.cpp index 05019b7..37e7770 100644 --- a/libproxy/modules/wpad_dnsdevolution.cpp +++ b/libproxy/modules/wpad_dnsdevolution.cpp @@ -17,165 +17,88 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ******************************************************************************/ -#include <string.h> -#include <errno.h> -#include <stdio.h> -#define __USE_BSD -#include <unistd.h> - -#ifdef _WIN32 -#include <winsock2.h> -#else -#include <netdb.h> -#endif - -#include "../misc.hpp" -#include "../array.hpp" -#include "../modules.hpp" -#include "../pac.hpp" - -/* The top-level domain blacklist */ +#include <cstring> + +#include "../module_types.hpp" +using namespace com::googlecode::libproxy; + +/* The domain blacklist */ /* TODO: Make this not suck */ -static char *tld[] = { - /* General top-level domains */ - "arpa", "root", "aero", "biz", "cat", "com", "coop", "edu", "gov", "info", - "int", "jobs", "mil", "mobi", "museum", "name", "net", "org", "pro", "travel", - - /* Country codes */ - "ac", "ad", "ae", "af", "ag", "ai", "al", "am", "an", "ao", "aq", "ar", - "as", "at", "au", "aw", "ax", "az", "ba", "bb", "bd", "be", "bf", "bg", - "bh", "bi", "bj", "bm", "bn", "bo", "br", "bs", "bt", "bv", "bw", "by", - "bz", "ca", "cc", "cd", "cf", "cg", "ch", "ci", "ck", "cl", "cm", "cn", - "co", "cr", "cu", "cv", "cx", "cy", "cz", "de", "dj", "dk", "dm", "do", - "dz", "ec", "ee", "eg", "er", "es", "et", "eu", "fi", "fj", "fk", "fm", - "fo", "fr", "ga", "gb", "gd", "ge", "gf", "gg", "gh", "gi", "gl", "gm", - "gn", "gp", "gq", "gr", "gs", "gt", "gu", "gw", "gy", "hk", "hm", "hn", - "hr", "ht", "hu", "id", "ie", "il", "im", "in", "io", "iq", "ir", "is", - "it", "je", "jm", "jo", "jp", "ke", "kg", "kh", "ki", "km", "kn", "kr", - "kw", "ky", "kz", "la", "lb", "lc", "li", "lk", "lr", "ls", "lt", "lu", - "lv", "ly", "ma", "mc", "md", "mg", "mh", "mk", "ml", "mm", "mn", "mo", - "mp", "mq", "mr", "ms", "mt", "mu", "mv", "mw", "mx", "my", "mz", "na", - "nc", "ne", "nf", "ng", "ni", "nl", "no", "np", "nr", "nu", "nz", "om", - "pa", "pe", "pf", "pg", "ph", "pk", "pl", "pm", "pn", "pr", "ps", "pt", - "pw", "py", "qa", "re", "ro", "ru", "rw", "sa", "sb", "sc", "sd", "se", - "sg", "sh", "si", "sj", "sk", "sl", "sm", "sn", "sr", "st", "su", "sv", - "sy", "sz", "tc", "td", "tf", "tg", "th", "tj", "tk", "tl", "tm", "tn", - "to", "tp", "tr", "tt", "tv", "tw", "tz", "ua", "ug", "uk", "um", "us", - "uy", "uz", "va", "vc", "ve", "vg", "vi", "vn", "vu", "wf", "ws", "ye", - "yt", "yu", "za", "zm", "zw", - - /* Other domains to blacklist */ +/* Is there a list of 'public' domains somewhere? */ +static const char *blacklist[] = { "co.uk", "com.au", /* Terminator */ NULL }; -typedef struct _pxDNSDevolutionWPADModule { - PX_MODULE_SUBCLASS(pxWPADModule); - pxArray *urls; - int next; -} pxDNSDevolutionWPADModule; - -static char * -_get_domain_name() +static string +_get_fqdn() { - /* Get the hostname */ - char *hostname = (char *) px_malloc0(128); - for (int i = 0 ; gethostname(hostname, (i + 1) * 128) && errno == ENAMETOOLONG ; ) - hostname = (char *) px_malloc0((++i + 1) * 128); +#define BUFLEN 512 + char hostname[BUFLEN]; + + // Zero out the buffer + memset(hostname, 0, BUFLEN); + + // Get the hostname + if (gethostname(hostname, BUFLEN)) return ""; /* Lookup the hostname */ /* TODO: Make this whole process not suck */ struct hostent *host_info = gethostbyname(hostname); if (host_info) - { - px_free(hostname); - hostname = px_strdup(host_info->h_name); - } + strncpy(hostname, host_info->h_name, BUFLEN-1); - /* Get domain portion */ - if (!strchr(hostname, '.')) return NULL; - if (!strcmp(".", strchr(hostname, '.'))) return NULL; - char *tmp = px_strdup(strchr(hostname, '.') + 1); - px_free(hostname); - return tmp; + try { return string(hostname).substr(string(hostname).find(".")).substr(1); } + catch (out_of_range& e) { return ""; } } -static pxArray * -_get_urls() -{ - char *domain = _get_domain_name(); - if (!domain) return NULL; - - /* Split up the domain */ - char **domainv = px_strsplit(domain, "."); - px_free(domain); - if (!domainv) return NULL; - - pxArray *urls = px_array_new(NULL, px_free, false, false); - for (int i=1 ; domainv[i] ; i++) - { - /* Check the domain against the blacklist */ - domain = px_strjoin((const char **) (domainv + i), "."); - for (int k=0; tld[k] ; k++) - if (!strcmp(domain, tld[k])) { px_free(domain); domain = NULL; break; } - if (!domain) continue; - - /* Create a URL */ - char *url = px_strcat("http://wpad.", domain, "/wpad.dat", NULL); - px_array_add(urls, url); - px_free(domain); +class dnsdevolution_wpad_module : public wpad_module { +public: + PX_MODULE_ID(NULL); + + dnsdevolution_wpad_module() { + this->rewind(); } - return urls; -} + bool found() { + return this->lpac != NULL; + } -static pxPAC * -_next(pxWPADModule *self) -{ - pxDNSDevolutionWPADModule *dnsd = (pxDNSDevolutionWPADModule *) self; - if (!dnsd->urls) - dnsd->urls = _get_urls(); - if (!dnsd->urls) - return NULL; - - pxPAC *pac = px_pac_new_from_string((char *) px_array_get(dnsd->urls, dnsd->next++)); - if (pac) - self->found = true; - return pac; -} + pac* next() { + // If we have rewound start the new count + if (this->last == "") + this->last = _get_fqdn(); -static void -_rewind(pxWPADModule *s) -{ - pxDNSDevolutionWPADModule * self = (pxDNSDevolutionWPADModule *) s; + // Get the 'next' segment + if (this->last.find(".") == string::npos) return NULL; + this->last = this->last.substr(this->last.find(".")+1); - px_array_free(self->urls); - self->urls = NULL; - self->next = 0; - self->__parent__.found = false; -} + // Don't do TLD's + if (this->last.find(".") == string::npos) return NULL; -static void -_destructor(void *s) -{ - _rewind((pxWPADModule *) s); - px_free(s); -} + // Process blacklist + for (int i=0 ; blacklist[i] ; i++) + if (this->last == blacklist[i]) + return NULL; -static void * -_constructor() -{ - pxDNSDevolutionWPADModule *self = (pxDNSDevolutionWPADModule*) px_malloc0(sizeof(pxDNSDevolutionWPADModule)); - self->__parent__.next = _next; - self->__parent__.rewind = _rewind; - _rewind((pxWPADModule *) self); - return self; -} + // Try to load + try { this->lpac = new pac(url(string("http://wpad.") + this->last + "/wpad.dat")); } + catch (parse_error& e) { } + catch (io_error& e) { } -bool -px_module_load(pxModuleManager *self) -{ - return px_module_manager_register_module(self, pxWPADModule, _constructor, _destructor); -} + return this->lpac; + } + + void rewind() { + this->last = ""; + } + + +private: + string last; + pac* lpac; +}; + +PX_MODULE_LOAD(wpad_module, dnsdevolution, true); diff --git a/libproxy/modules/xhasclient.cpp b/libproxy/modules/xhasclient.cpp index 85c563a..af829f4 100644 --- a/libproxy/modules/xhasclient.cpp +++ b/libproxy/modules/xhasclient.cpp @@ -1,6 +1,6 @@ /* * - * + * Copyright 1989, 1998 The Open Group Permission to use, copy, modify, distribute, and sell this software and its @@ -31,54 +31,46 @@ in this Software without prior written authorization from The Open Group. * Reworked by Nathaniel McCallum, 2007 */ -#include <stdbool.h> #include <stdarg.h> #include <string.h> #include <X11/Xlib.h> #include <X11/Xmu/WinUtil.h> -bool -x_has_client(char *prog, ...) -{ +bool xhasclient(const char *prog, ...) { va_list ap; - + // Open display Display *display = XOpenDisplay(NULL); if (!display) return false; - + // For each screen... - for (int i=0; i < ScreenCount(display); i++) - { + for (int i=0; i < ScreenCount(display); i++) { Window dummy, *children = NULL; unsigned int nchildren = 0; - + // Get the root window's children if (!XQueryTree(display, RootWindow(display, i), &dummy, &dummy, &children, &nchildren)) continue; - + // For each child on the screen... - for (int j=0; j < nchildren; j++) - { + for (int j=0; j < nchildren; j++) { // If we can get their client info... Window client; - if ((client = XmuClientWindow(display, children[j])) != None) - { + if ((client = XmuClientWindow(display, children[j])) != None) { int argc; char **argv; - + // ... and if we can find out their command ... if (!XGetCommand (display, client, &argv, &argc) || argc == 0) continue; - + // ... check the commands against our list va_start(ap, prog); - for (char *s = prog ; s ; s = va_arg(ap, char *)) - { + for (const char *s = prog ; s ; s = va_arg(ap, char *)) { // We've found a match, return... - if (!strcmp(argv[0], s)) - { + if (!strcmp(argv[0], s)) { va_end(ap); XCloseDisplay(display); return true; @@ -88,7 +80,7 @@ x_has_client(char *prog, ...) } } } - + // Close the display XCloseDisplay(display); return false; diff --git a/libproxy/pac.cpp b/libproxy/pac.cpp index bd533a7..c842537 100644 --- a/libproxy/pac.cpp +++ b/libproxy/pac.cpp @@ -17,177 +17,125 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ******************************************************************************/ -#include <unistd.h> -#include <string.h> -#include <time.h> -#include <sys/types.h> -#include <sys/stat.h> +#include <cstdlib> // For atoi(...) +#include <sys/stat.h> // For stat(...) +#include <cstdio> // For sscanf(...) #ifdef _WIN32 #include <winsock2.h> +#define pfsize(st) (st.st_size) #else #include <sys/socket.h> +#define pfsize(st) (st.st_blksize * st.st_blocks) #endif -#include "url.hpp" -#include "misc.hpp" #include "pac.hpp" +// This mime type should be reported by the web server #define PAC_MIME_TYPE "application/x-ns-proxy-autoconfig" +// Fall back to checking for this mime type, which servers often report wrong +#define PAC_MIME_TYPE_FB "text/plain" -/** - * ProxyAutoConfig object. All fields are private. - */ -struct _pxPAC { - pxURL *url; - char *cache; - time_t expires; -}; - -/** - * Frees memory used by the ProxyAutoConfig. - */ -void -px_pac_free(pxPAC *self) -{ - if (!self) return; - px_url_free(self->url); - px_free(self->cache); - px_free(self); -} +// This is the maximum pac size (to avoid memory attacks) +#define PAC_MAX_SIZE 102400 -/** - * Get the URL which the pxPAC uses. - * @return The URL that the pxPAC came from - */ -const pxURL * -px_pac_get_url(pxPAC *self) -{ - return self->url; -} +namespace com { +namespace googlecode { +namespace libproxy { +using namespace std; -/** - * Create a new ProxyAutoConfig. - * @url The URL where the PAC file is found - * @return A new ProxyAutoConfig or NULL on error - */ -pxPAC * -px_pac_new(pxURL *url) +static inline string _readline(int fd) { - if (!url) return NULL; - - /* Allocate the object */ - pxPAC *self = (pxPAC *) px_malloc0(sizeof(pxPAC)); - - /* Copy the given URL */ - self->url = px_url_new(px_url_to_string(url)); /* Always returns valid value */ - - /* Make sure we have a real pxPAC */ - if (!px_pac_reload(self)) { px_pac_free(self); return NULL; } - - return self; + // Read a character. + // If we don't get a character, return empty string. + // If we are at the end of the line, return empty string. + char c = '\0'; + if (read(fd, &c, 1) != 1 || c == '\n') return ""; + return string(1, c) + _readline(fd); } -/** - * Create a new ProxyAutoConfig (from a string for convenience). - * @url The url (string) where the PAC file is found - * @return A new ProxyAutoConfig or NULL on error - */ -pxPAC * -px_pac_new_from_string(char *url) -{ - /* Create temporary URL */ - pxURL *tmpurl = px_url_new(url); - if (!tmpurl) return NULL; - - /* Create pac */ - pxPAC *self = px_pac_new(tmpurl); - px_url_free(tmpurl); /* Free no longer used URL */ - if (!self) return NULL; - return self; +pac::~pac() { + delete this->pacurl; } -/** - * Returns the Javascript code which the pxPAC uses. - * @return The Javascript code used by the pxPAC - */ -const char * -px_pac_to_string(pxPAC *self) -{ - return self->cache; +pac::pac(const pac& pac) { + this->pacurl = new libproxy::url(*pac.pacurl); + this->cache = pac.cache; } -/** - * Download the latest version of the pxPAC file - * @return Whether the download was successful or not - */ -bool -px_pac_reload(pxPAC *self) -{ +pac::pac(const url& url) throw (io_error) { int sock; - char *line = NULL; - const char *headers[3] = { "Accept: " PAC_MIME_TYPE, "Connection: close", NULL }; bool correct_mime_type; - unsigned long int content_length = 0; + unsigned long int content_length = 0, status = 0; + + this->pacurl = new libproxy::url(url.to_string().find("pac+") == 0 ? url.to_string().substr(4) : url); /* Get the pxPAC */ - sock = px_url_get(self->url, headers); - if (sock < 0) return false; + map<string, string> headers; + headers["Accept"] = PAC_MIME_TYPE; + headers["Connection"] = "close"; + sock = this->pacurl->open(headers); + if (sock < 0) throw io_error("Unable to connect: " + url.to_string()); - if (strcmp(px_url_get_scheme(self->url),"file")) + if (url.get_scheme() != "file") { /* Verify status line */ - line = px_readline(sock, NULL, 0); - if (!line) goto error; - if (strncmp(line, "HTTP", strlen("HTTP"))) goto error; /* Check valid HTTP response */ - if (!strchr(line, ' ') || atoi(strchr(line, ' ') + 1) != 200) goto error; /* Check status code */ + string line = _readline(sock); + if (sscanf(line.c_str(), "HTTP/1.%*d %d", &status) != 1 || status != 200) goto error; /* Check for correct mime type and content length */ - while (strcmp(line, "\r")) { - /* Check for content type */ - if (strstr(line, "Content-Type: ") == line && strstr(line, PAC_MIME_TYPE)) + for (line = _readline(sock) ; line != "\r" && line != "" ; line = _readline(sock)) { + // Check for content type + if (line.find("Content-Type: ") == 0 && + line.find(PAC_MIME_TYPE) != string::npos || + line.find(PAC_MIME_TYPE_FB) != string::npos) correct_mime_type = true; - /* Check for content length */ - else if (strstr(line, "Content-Length: ") == line) - content_length = atoi(line + strlen("Content-Length: ")); - - /* Get new line */ - px_free(line); - line = px_readline(sock, NULL, 0); - if (!line) goto error; + // Check for content length + else if (content_length == 0) + sscanf(line.c_str(), "Content-Length: %lu", &content_length); } - /* Get content */ - if (!content_length || !correct_mime_type) goto error; - px_free(line); line = NULL; - px_free(self->cache); - self->cache = (char *) px_malloc0(content_length+1); - for (int recvd=0 ; recvd != content_length ; ) - recvd += recv(sock, self->cache + recvd, content_length - recvd, 0); + // Get content + if (!content_length || content_length > PAC_MAX_SIZE || !correct_mime_type) goto error; + char *buffer = new char[content_length]; + for (int recvd=0 ; recvd < content_length ; ) + recvd += recv(sock, buffer + recvd, content_length - recvd, 0); + this->cache = buffer; + delete buffer; } else { /* file:// url */ - struct stat buffer; + struct stat st; int status; - if (fstat(sock, &buffer)) goto error; -#ifdef _WIN32 - self->cache = (char *) px_malloc0(buffer.st_size + 1); - status = read(sock, self->cache, buffer.st_size); -#else - self->cache = (char *) px_malloc0(buffer.st_blksize * buffer.st_blocks + 1); - status = read(sock, self->cache, buffer.st_blksize * buffer.st_blocks); -#endif + if (fstat(sock, &st) || pfsize(st) > PAC_MAX_SIZE) goto error; + char *buffer = new char[pfsize(st)+1]; + if (read(sock, buffer, pfsize(st)) == 0) { + delete buffer; + goto error; + } + this->cache = buffer; + delete buffer; } - /* Clean up */ + // Clean up close(sock); - return true; + return; + +error: + if (sock >= 0) close(sock); + throw io_error("Unable to read PAC from " + url.to_string()); +} - error: - px_free(self->cache); self->cache = NULL; - if (sock >= 0) close(sock); - px_free(line); - return false; +url pac::get_url() const { + return *(this->pacurl); +} + +string pac::to_string() const { + return this->cache; +} + +} +} } diff --git a/libproxy/pac.hpp b/libproxy/pac.hpp index 4a29b83..8c3030d 100644 --- a/libproxy/pac.hpp +++ b/libproxy/pac.hpp @@ -1,72 +1,55 @@ /******************************************************************************* * libproxy - A library for proxy configuration * Copyright (C) 2006 Nathaniel McCallum <nathaniel@natemccallum.com> - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. - * + * * This library 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 * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ******************************************************************************/ -#ifndef PAC_H_ -#define PAC_H_ +#ifndef PAC_HPP_ +#define PAC_HPP_ -#include "url.hpp" - -/** - * pxPAC object. All fields are private. - */ -typedef struct _pxPAC pxPAC; - -/** - * Frees memory used by the ProxyAutoConfig. - */ -void px_pac_free(pxPAC *self); - -/** - * Get the URL which the pxPAC uses. - * @return The URL that the pxPAC came from - */ -__attribute__ ((visibility("default"))) -const pxURL *px_pac_get_url(pxPAC *self); +#include <stdexcept> -/** - * Create a new ProxyAutoConfig. - * @url The URL where the PAC file is found - * @return A new ProxyAutoConfig or NULL on error - */ -pxPAC *px_pac_new(pxURL *url); - -/** - * Create a new ProxyAutoConfig (from a string for convenience). - * @url The url (string) where the PAC file is found - * @return A new ProxyAutoConfig or NULL on error - */ -__attribute__ ((visibility("default"))) -pxPAC *px_pac_new_from_string(char *url); - -/** - * Returns the Javascript code which the pxPAC uses. - * @return The Javascript code used by the pxPAC - */ -__attribute__ ((visibility("default"))) -const char *px_pac_to_string(pxPAC *self); - -/** - * Download the latest version of the pxPAC file - * @return Whether the download was successful or not - */ -__attribute__ ((visibility("default"))) -bool px_pac_reload(pxPAC *self); +#include "url.hpp" -#endif /*PAC_H_*/ +namespace com { +namespace googlecode { +namespace libproxy { +using namespace std; + +class io_error : public runtime_error { +public: + io_error(const string& __arg): runtime_error(__arg) {} +}; + +class pac { +public: + ~pac(); + pac(const url& url) throw (io_error); + pac(const pac& pac); + url get_url() const; + string to_string() const; + +private: + url* pacurl; + string cache; +}; + +} +} +} + +#endif /*PAC_HPP_*/ diff --git a/libproxy/proxy.cpp b/libproxy/proxy.cpp index c410f7f..40466a8 100644 --- a/libproxy/proxy.cpp +++ b/libproxy/proxy.cpp @@ -18,10 +18,10 @@ ******************************************************************************/ #define _BSD_SOURCE -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <sys/types.h> +#include <algorithm> +#include <iostream> +#include <cstring> + #include <pthread.h> #ifdef _WIN32 @@ -29,418 +29,302 @@ #define setenv(name, value, overwrite) SetEnvironmentVariable(name, value) #endif -#include "misc.hpp" -#include "proxy.h" #include "config_file.hpp" -#include "array.hpp" -#include "strdict.hpp" -#include "module_manager.hpp" -#include "modules.hpp" - -struct _pxProxyFactory { - pthread_mutex_t mutex; - pxModuleManager *mm; - pxPAC *pac; - bool wpad; +#include "module_types.hpp" + +namespace com { +namespace googlecode { +namespace libproxy { +using namespace std; + +class proxy_factory { +public: + proxy_factory(); + ~proxy_factory(); + vector<string> get_proxies(string url); + +private: + pthread_mutex_t mutex; + module_manager mm; + libproxy::pac* pac; + bool wpad; }; -/* Convert the PAC formatted response into our proxy URL array response */ -static char ** -_format_pac_response(char *response) -{ - char **chain, *tmp; +bool istringcmp(string a, string b) { + transform( a.begin(), a.end(), a.begin(), ::tolower ); + transform( b.begin(), b.end(), b.begin(), ::tolower ); + return ( a == b ); +} - if (!response) return px_strsplit("direct://", ";"); - chain = px_strsplit(response, ";"); - px_free(response); +// Convert the PAC formatted response into our proxy URL array response +static vector<string> +_format_pac_response(string response) +{ + vector<string> retval; - for (int i=0 ; chain[i] ; i++) - { - tmp = px_strstrip(chain[i]); - px_free(chain[i]); - - if (!strncmp(tmp, "PROXY", 5) || !strncmp(tmp, "SOCKS", 5)) - { - char *hostport = px_strstrip(tmp + 5); - if (!strncmp(tmp, "PROXY", 5)) - chain[i] = px_strcat("http://", hostport, NULL); - else - chain[i] = px_strcat("socks://", hostport, NULL); - px_free(hostport); - } - else - chain[i] = px_strdup("direct://"); + // Skip ahead one character if we start with ';' + if (response[0] == ';') + return _format_pac_response(response.substr(1)); - px_free(tmp); + // If the string contains a delimiter (';') + if (response.find(';') != string::npos) { + retval = _format_pac_response(response.substr(response.find(';')+1)); + response = response.substr(0, response.find(';')); } - return chain; -} - -static inline int -_px_wpad_module_findpos(const char *name) -{ - int pos = 0; - - char **orderv = px_strsplit("wpad_dhcp,wpad_slp,wpad_dns,wpad_dnsdevolution", ","); - for (pos = 0 ; orderv[pos] ; pos++) - if (!strcmp(name, orderv[pos])) - goto do_return; + // Strip whitespace + response = response.substr(response.find_first_not_of(" \t"), response.find_last_not_of(" \t")+1); + + // Get the method and the server + string method = ""; + string server = ""; + if (response.find_first_of(" \t") == string::npos) + method = response; + else { + method = response.substr(0, response.find_first_of(" \t")); + server = response.substr(response.find_first_of(" \t") + 1); + } - do_return: - px_strfreev(orderv); - return pos; -} + // Insert our url value + if (istringcmp(method, "proxy") && url::is_valid("http://" + server)) + retval.insert(retval.begin(), string("http://") + server); + else if (istringcmp(method, "socks") && url::is_valid("http://" + server)) + retval.insert(retval.begin(), string("socks://") + server); + else if (istringcmp(method, "direct")) + retval.insert(retval.begin(), string("direct://")); -static int -_px_wpad_module_cmp(pxModuleRegistration **a, pxModuleRegistration **b) -{ - if (!a || !*a) return 0; - if (!b || !*b) return 0; - return _px_wpad_module_findpos((*a)->name) - _px_wpad_module_findpos((*b)->name); + return retval; } -static inline int -_px_config_module_findpos(pxConfigModuleCategory category, const char *name) -{ - int pos = 0; - - /* Attempt to get config order */ - char *fileorder = getenv("_PX_CONFIG_ORDER"); - char *envorder = getenv("PX_CONFIG_ORDER"); - - /* Create the config order */ - char *order = px_strcat(fileorder ? fileorder : "", ",", - envorder ? envorder : "", ",", - "USER,SESSION,SYSTEM,config_envvar,config_wpad,config_direct", - NULL); - - /* Create the config plugin order vector */ - char **orderv = px_strsplit(order, ","); - px_free(order); - - /* Get the config by searching the config order */ - for (pos=0 ; orderv[pos] ; pos++) - { - if ((!strcmp(orderv[pos], "USER") && PX_CONFIG_MODULE_CATEGORY_USER == category) || - (!strcmp(orderv[pos], "SESSION") && PX_CONFIG_MODULE_CATEGORY_SESSION == category) || - (!strcmp(orderv[pos], "SYSTEM") && PX_CONFIG_MODULE_CATEGORY_SYSTEM == category) || - (!strcmp(orderv[pos], name))) - break; - } - px_strfreev(orderv); - return pos; -} +proxy_factory::proxy_factory() { + pthread_mutex_init(&this->mutex, NULL); + pthread_mutex_lock(&this->mutex); + this->pac = NULL; + + // Register our singletons + this->mm.set_singleton<pacrunner_module>(true); + + // If we have a config file, load the config order from it + setenv("_PX_CONFIG_ORDER", "", 1); + config_file cf; + if (cf.load(SYSCONFDIR "proxy.conf")) { + try { + string tmp = cf.get_value("config_order"); + setenv("_PX_CONFIG_ORDER", tmp.c_str(), 1); + } + catch (key_error e) { } + } -static int -_px_config_module_cmp(pxModuleRegistration **a, pxModuleRegistration **b) -{ - if (!a || !*a) return 0; - if (!b || !*b) return 0; + // Load all modules + this->mm.load_dir(MODULEDIR); - return _px_config_module_findpos(((pxConfigModule *) (*a)->instance)->category, (*a)->name) - - _px_config_module_findpos(((pxConfigModule *) (*b)->instance)->category, (*b)->name); + pthread_mutex_unlock(&this->mutex); } -/** - * Creates a new pxProxyFactory instance. This instance should be kept - * around as long as possible as it contains cached data to increase - * performance. Memory usage should be minimal (cache is small) and the - * cache lifespan is handled automatically. - * - * @return A new pxProxyFactory instance or NULL on error - */ -pxProxyFactory * -px_proxy_factory_new () -{ - pxProxyFactory *self = (pxProxyFactory *) px_malloc0(sizeof(pxProxyFactory)); - self->mm = px_module_manager_new(); - pxConfigFile *cf = NULL; - char *tmp; - - /* Register our module types */ - if (!px_module_manager_register_type(self->mm, pxConfigModule, _px_config_module_cmp, false)) goto error; - if (!px_module_manager_register_type(self->mm, pxPACRunnerModule, NULL, true)) goto error; - if (!px_module_manager_register_type(self->mm, pxWPADModule, _px_wpad_module_cmp, false)) goto error; - - /* If we have a config file, load the config order from it */ - setenv("_PX_CONFIG_ORDER", "", 1); - cf = px_config_file_new(SYSCONFDIR "proxy.conf"); - if (cf) - { - tmp = px_config_file_get_value(cf, PX_CONFIG_FILE_DEFAULT_SECTION, "config_order"); - px_config_file_free(cf); - if (tmp && setenv("_PX_CONFIG_ORDER", tmp, 1)) - { - px_free(tmp); - goto error; - } - px_free(tmp); - } - - /* Load all modules */ - if (!px_module_manager_load_dir(self->mm, MODULEDIR)) goto error; - - pthread_mutex_init(&self->mutex, NULL); - return self; - - error: - px_proxy_factory_free(self); - return NULL; +proxy_factory::~proxy_factory() { + pthread_mutex_lock(&this->mutex); + if (this->pac) delete this->pac; + pthread_mutex_unlock(&this->mutex); + pthread_mutex_destroy(&this->mutex); } -/** - * Get which proxies to use for the specified URL. - * - * A NULL-terminated array of proxy strings is returned. - * If the first proxy fails, the second should be tried, etc... - * Don't forget to free the strings/array when you are done. - * In all cases, at least one entry in the array will be returned. - * There are no error conditions. - * - * Regarding performance: this method always blocks and may be called - * in a separate thread (is thread-safe). In most cases, the time - * required to complete this function call is simply the time required - * to read the configuration (i.e. from gconf, kconfig, etc). - * - * In the case of PAC, if no valid PAC is found in the cache (i.e. - * configuration has changed, cache is invalid, etc), the PAC file is - * downloaded and inserted into the cache. This is the most expensive - * operation as the PAC is retrieved over the network. Once a PAC exists - * in the cache, it is merely a javascript invocation to evaluate the PAC. - * One should note that DNS can be called from within a PAC during - * javascript invocation. - * - * In the case of WPAD, WPAD is used to automatically locate a PAC on the - * network. Currently, we only use DNS for this, but other methods may - * be implemented in the future. Once the PAC is located, normal PAC - * performance (described above) applies. - * - * The format of the returned proxy strings are as follows: - * - http://[username:password@]proxy:port - * - socks://[username:password@]proxy:port - * - direct:// - * Please note that the username and password in the above URLs are optional - * and should be use to authenticate the connection if present. - * - * @url The URL we are trying to reach - * @return A NULL-terminated array of proxy strings to use - */ -char ** -px_proxy_factory_get_proxies (pxProxyFactory *self, char *url) -{ - char **response = px_strsplit("direct://", ";"); - char *confurl = NULL; - char *confign = NULL; - pxConfigModule *config = NULL; - pxIgnoreModule **ignores = NULL; - pxConfigModule **configs = NULL; - pxNetworkModule **networks = NULL; - char **ignore_split = NULL; - - /* Verify some basic stuff */ - if (!self) return response; - pthread_mutex_lock(&self->mutex); - - /* Convert the URL */ - pxURL *realurl = px_url_new(url); - if (!realurl) goto do_return; - - /* Check to see if our network has changed */ - networks = px_module_manager_instantiate_type(self->mm, pxNetworkModule); - for (int i=0 ; networks && networks[i] ; i++) - { - if (networks[i]->changed(networks[i])) - { - pxWPADModule **wpads = px_module_manager_instantiate_type(self->mm, pxWPADModule); - for (int j=0 ; wpads[j] ; j++) - { - wpads[j]->rewind(wpads[j]); - } - px_free(wpads); - px_pac_free(self->pac); - self->pac = NULL; + +vector<string> proxy_factory::get_proxies(string __url) { + url* realurl = NULL; + url confurl("direct://"); + string confign; + config_module* config; + vector<network_module*> networks; + vector<config_module*> configs; + vector<ignore_module*> ignores; + vector<string> response; + + // Check to make sure our url is valid + if (!url::is_valid(__url)) + goto do_return; + realurl = new url(__url); + + // Lock the mutex + pthread_mutex_lock(&this->mutex); + + // Check to see if our network topology has changed... + networks = this->mm.get_modules<network_module>(); + for (vector<network_module*>::iterator i=networks.begin() ; i != networks.end() ; i++) { + // If it has, reset our wpad/pac setup and we'll retry our config + if ((*i)->changed()) { + vector<wpad_module*> wpads = this->mm.get_modules<wpad_module>(); + for (vector<wpad_module*>::iterator j=wpads.begin() ; j != wpads.end() ; j++) + (*j)->rewind(); + if (this->pac) delete this->pac; + this->pac = NULL; break; } } - px_free(networks); - /* Attempt to load a valid config */ - configs = px_module_manager_instantiate_type(self->mm, pxConfigModule); - for (int i=0 ; configs && configs[i] ; i++) - { - config = configs[i]; - confurl = config->get_config(config, realurl); - if (!confurl) - goto invalid; - confign = config->get_ignore(config, realurl); - - /* If the config plugin returned an invalid config type or malformed URL, mark as invalid */ - if (!(!strncmp(confurl, "http://", 7) || - !strncmp(confurl, "socks://", 8) || - !strncmp(confurl, "pac+", 4) || - !strcmp (confurl, "wpad://") || - !strcmp (confurl, "direct://"))) - goto invalid; - else if (!strncmp(confurl, "pac+", 4) && !px_url_is_valid(confurl + 4)) - goto invalid; - else if ((!strncmp(confurl, "http://", 7) || !strncmp(confurl, "socks://", 8)) && - !px_url_is_valid(confurl)) - goto invalid; - - config->valid = true; + configs = this->mm.get_modules<config_module>(); + for (vector<config_module*>::iterator i=configs.begin() ; i != configs.end() ; i++) { + config = *i; + + // Try to get the confurl + try { confurl = (config)->get_config(*realurl); } + catch (runtime_error e) { goto invalid_config; } + + // Validate the input + if (!(confurl.get_scheme() == "http" || + confurl.get_scheme() == "socks" || + confurl.get_scheme().substr(0, 4) == "pac+" || + confurl.get_scheme() == "wpad" || + confurl.get_scheme() == "direct")) + goto invalid_config; + + config->set_valid(true); break; - invalid: - px_free(confurl); confurl = NULL; - px_free(confign); confign = NULL; - config->valid = false; - config = NULL; + invalid_config: + confurl = "direct://"; + confign = ""; + (config)->set_valid(false); + config = NULL; } - px_free(configs); - if (!config) goto do_return; /* Check our ignore patterns */ - ignores = px_module_manager_instantiate_type(self->mm, pxIgnoreModule); - ignore_split = px_strsplit(confign, ","); - px_free(confign); confign = NULL; - for (int i=0 ; ignore_split && ignore_split[i] ; i++) - { - for (int j=0 ; ignores && ignores[j] ; j++) - { - if (ignores[j]->ignore(ignores[j], realurl, ignore_split[i])) - { - px_free(ignores); - px_strfreev(ignore_split); + ignores = this->mm.get_modules<ignore_module>(); + for (int i=-1 ; i < confign.size() ; i=confign.find(',')) { + for (vector<ignore_module*>::iterator it=ignores.begin() ; it != ignores.end() ; it++) + if ((*it)->ignore(*realurl, confign.substr(i+1, confign.find(',')))) goto do_return; - } - } } - px_free(ignores); - px_strfreev(ignore_split); /* If we have a wpad config */ - if (!strcmp(confurl, "wpad://")) - { + if (confurl.get_scheme() == "wpad") { /* If the config has just changed from PAC to WPAD, clear the PAC */ - if (!self->wpad) - { - px_pac_free(self->pac); - self->pac = NULL; - self->wpad = true; + if (!this->wpad) { + if (this->pac) delete this->pac; + this->pac = NULL; + this->wpad = true; } /* If we have no PAC, get one */ - if (!self->pac) - { - pxWPADModule **wpads = px_module_manager_instantiate_type(self->mm, pxWPADModule); - for (int i=0 ; wpads[i] ; i++) - if ((self->pac = wpads[i]->next(wpads[i]))) + if (!this->pac) { + vector<wpad_module*> wpads = this->mm.get_modules<wpad_module>(); + for (vector<wpad_module*>::iterator i=wpads.begin() ; i != wpads.end() ; i++) + if ((this->pac = (*i)->next())) break; /* If getting the PAC fails, but the WPAD cycle worked, restart the cycle */ - if (!self->pac) - { - for (int i=0 ; wpads[i] ; i++) - { - if (wpads[i]->found) - { + if (!this->pac) { + for (vector<wpad_module*>::iterator i=wpads.begin() ; i != wpads.end() ; i++) { + if ((*i)->found()) { /* Since a PAC was found at some point, * rewind all the WPADS to start from the beginning */ /* Yes, the reuse of 'i' here is intentional... * This is because if *any* of the wpads have found a pac, * we need to reset them all to keep consistent state. */ - for (i=0 ; wpads[i] ; i++) - wpads[i]->rewind(wpads[i]); + for (i=wpads.begin() ; i != wpads.end() ; i++) + (*i)->rewind(); - /* Attempt to find a PAC */ - for (i=0 ; wpads[i] ; i++) - if ((self->pac = wpads[i]->next(wpads[i]))) + // Attempt to find a PAC + for (i=wpads.begin() ; i != wpads.end() ; i++) + if ((this->pac = (*i)->next())) break; break; } } } - px_free(wpads); } } - /* If we have a PAC config */ - else if (!strncmp(confurl, "pac+", 4)) + // If we have a PAC config + else if (confurl.get_scheme().substr(0, 4) == "pac+") { /* Save the PAC config */ - if (self->wpad) - self->wpad = false; + if (this->wpad) + this->wpad = false; /* If a PAC already exists, but came from a different URL than the one specified, remove it */ - if (self->pac) - { - pxURL *urltmp = px_url_new(confurl + 4); - if (!urltmp) - goto do_return; - if (!px_url_equals(urltmp, px_pac_get_url(self->pac))) + if (this->pac) { + if (this->pac->get_url() == confurl) { - px_pac_free(self->pac); - self->pac = NULL; + delete this->pac; + this->pac = NULL; } - px_url_free(urltmp); } /* Try to load the PAC if it is not already loaded */ - if (!self->pac && !(self->pac = px_pac_new_from_string(confurl + 4))) + if (!this->pac && !(this->pac = new libproxy::pac(confurl))) goto do_return; } /* In case of either PAC or WPAD, we'll run the PAC */ - if (!strcmp(confurl, "wpad://") || !strncmp(confurl, "pac+", 4)) - { - pxPACRunnerModule **pacrunners = px_module_manager_instantiate_type(self->mm, pxPACRunnerModule); + if (this->pac && confurl.get_scheme() == "wpad" || confurl.get_scheme().substr(0, 4) == "pac+" ) { + vector<pacrunner_module*> pacrunners = this->mm.get_modules<pacrunner_module>(); /* No PAC runner found, fall back to direct */ - if (!pacrunners) - { - px_free(pacrunners); + if (pacrunners.size() == 0) goto do_return; - } /* Run the PAC, but only try one PACRunner */ - px_strfreev(response); - response = _format_pac_response(pacrunners[0]->run(pacrunners[0], self->pac, realurl)); - px_free(pacrunners); + response = _format_pac_response(pacrunners[0]->run(*this->pac, *realurl)); } /* If we have a manual config (http://..., socks://...) */ - else if (!strncmp(confurl, "http://", 7) || !strncmp(confurl, "socks://", 8)) + else if (confurl.get_scheme() == "http" || confurl.get_scheme() == "socks") { - self->wpad = false; - if (self->pac) { px_pac_free(self->pac); self->pac = NULL; } - px_strfreev(response); - response = px_strsplit(confurl, ";"); + this->wpad = false; + if (this->pac) { delete this->pac; this->pac = NULL; } + response.clear(); + response.push_back(confurl.to_string()); } /* Actually return, freeing misc stuff */ do_return: - px_free(confurl); - px_url_free(realurl); - pthread_mutex_unlock(&self->mutex); + pthread_mutex_unlock(&this->mutex); + if (realurl) + delete realurl; + if (response.size() == 0) + response.push_back("direct://"); return response; } -/** - * Frees the pxProxyFactory instance when no longer used. - */ -void -px_proxy_factory_free (pxProxyFactory *self) -{ - if (!self) return; +} +} +} - pthread_mutex_lock(&self->mutex); +struct _pxProxyFactory { + com::googlecode::libproxy::proxy_factory pf; +}; + +extern "C" struct _pxProxyFactory *px_proxy_factory_new(void) { + return new struct _pxProxyFactory; +} - /* Free the module manager */ - px_module_manager_free(self->mm); +extern "C" char** px_proxy_factory_get_proxies(struct _pxProxyFactory *self, const char *url) { + vector<string> proxies; + char** retval; + + // Call the main method + //try { + proxies = self->pf.get_proxies(url); + retval = new char*[proxies.size()+1]; + //} catch (exception&) { + // Return NULL on any exception + // return NULL; + //} + + // Copy the results into an array + // Return NULL on memory allocation failure + retval[proxies.size()] = NULL; + for (int i=0 ; i < proxies.size() ; i++) { + retval[i] = strdup(proxies[i].c_str()); + if (retval[i] == NULL) { + for (int j=i-1 ; j >= 0 ; j--) + free(retval[j]); + delete retval; + return NULL; + } + } + return retval; +} - /* Free everything else */ - px_pac_free(self->pac); - pthread_mutex_unlock(&self->mutex); - pthread_mutex_destroy(&self->mutex); - px_free(self); +extern "C" void px_proxy_factory_free(struct _pxProxyFactory *self) { + delete self; } diff --git a/libproxy/strdict.cpp b/libproxy/strdict.cpp deleted file mode 100644 index b773cf9..0000000 --- a/libproxy/strdict.cpp +++ /dev/null @@ -1,126 +0,0 @@ -/******************************************************************************* - * libproxy - A library for proxy configuration - * Copyright (C) 2006 Nathaniel McCallum <nathaniel@natemccallum.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - ******************************************************************************/ - -#include <stdint.h> -#include <string.h> - -#include "misc.hpp" -#include "array.hpp" -#include "strdict.hpp" - -struct _pxStrDict { - pxStrDictItemCallback free; - pxArray *data; -}; - -static bool -dict_equals(void *a, void *b) -{ - if (!a || !b) return false; - void **aa = (void **) a; - void **bb = (void **) b; - return (!strcmp((char *) *aa, (char *) *bb)); -} - -static void -dict_free(void *item) -{ - char *key = (char *) ((void **) item)[0]; - void **realitem = (void **) ((void **) item)[1]; - pxStrDictItemCallback do_free = (pxStrDictItemCallback) ((void **) item)[2]; - - do_free(realitem); - px_free(key); - px_free(item); -} - -static void -dict_foreach(void *item, void *misc) -{ - pxStrDictForeachCallback foreach = (pxStrDictForeachCallback) ((void **) misc)[0]; - char *key = (char *) ((void **) item)[0]; - void *val = ((void **) item)[1]; - void *arg = ((void **) misc)[1]; - foreach(key, val, arg); -} - -static void -do_nothing(void *item) -{ -} - -pxStrDict *px_strdict_new(pxStrDictItemCallback free) -{ - pxStrDict *self = (pxStrDict*) px_malloc0(sizeof(pxStrDict)); - self->free = free ? free : do_nothing; - self->data = px_array_new(dict_equals, dict_free, true, false); - return self; -} - -bool -px_strdict_set(pxStrDict *self, const char *key, void *value) -{ - if (!self || !key) return false; - - /* We are unseting the value */ - if (!value) - { - void *item[3] = { (void *) key, (void *) value, (void *) self->free }; - return px_array_del(self->data, item); - } - - void **item = (void **) px_malloc0(sizeof(void *) * 3); - item[0] = px_strdup(key); - item[1] = value; - item[2] = (void *) self->free; - - if (px_array_add(self->data, item)) - return true; - - px_free(*item); - px_free(item); - return false; -} - -const void * -px_strdict_get(pxStrDict *self, const char *key) -{ - if (!self || !key) return NULL; - - void *v[3] = { (void *) key, NULL, NULL }, **ret; - int i = px_array_find(self->data, v); - if (i < 0) return NULL; - ret = (void **) px_array_get(self->data, i); - return ret[1]; -} - -void -px_strdict_foreach(pxStrDict *self, pxStrDictForeachCallback *cb, void *arg) -{ - void *v[2] = { cb, arg }; - px_array_foreach(self->data, dict_foreach, v); -} - -void -px_strdict_free(pxStrDict *self) -{ - if (!self) return; - px_array_free(self->data); - px_free(self); -} diff --git a/libproxy/url.cpp b/libproxy/url.cpp index 8ee9992..b49aeb8 100644 --- a/libproxy/url.cpp +++ b/libproxy/url.cpp @@ -17,105 +17,203 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ******************************************************************************/ -#include <stdbool.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <sys/types.h> -#include <fcntl.h> - -#ifdef _WIN32 -#define _WIN32_WINNT 0x0501 -#include <winsock2.h> -#include <ws2tcpip.h> -#else -#include <sys/socket.h> -#include <netdb.h> -#include <arpa/inet.h> -#include <netinet/in.h> -#endif - -#include "misc.hpp" +#include <fcntl.h> // For ::open() +#include <cstring> // For memcpy() +#include <sstream> // For int/string conversion (using stringstream) +#include <cstdio> // For sscanf() + #include "url.hpp" -/** - * pxURL object. All fields are private. - */ -struct _pxURL { - char *url; - char *scheme; - char *username; - char *password; - char *host; - int port; - char *path; - struct sockaddr **ips; -}; - -/** - * @return Frees the pxURL - */ -void -px_url_free(pxURL *self) -{ - if (!self) return; - px_free(self->url); - px_free(self->scheme); - px_free(self->host); - px_free(self->path); - if (self->ips) +namespace com { +namespace googlecode { +namespace libproxy { +using namespace std; + +static inline int _get_default_port(string scheme) { + struct servent *serv; + if ((serv = getservbyname(scheme.c_str(), NULL))) return ntohs(serv->s_port); + return 0; +} + +template <class T> +static inline string _to_string (const T& t) { + stringstream ss; + ss << t; + return ss.str(); +} + +#define _copyaddr_t(type, addr) (sockaddr*) memcpy(new type, &(addr), sizeof(type)) +static inline sockaddr* _copyaddr(const struct sockaddr& addr) { + switch (addr.sa_family) { + case (AF_INET): + return _copyaddr_t(sockaddr_in, addr); + case (AF_INET6): + return _copyaddr_t(sockaddr_in6, addr); + default: + return NULL; + } +} + +bool url::is_valid(const string __url) { + url* tmp; + try { tmp = new url(__url); } + catch (parse_error& pe) { return false; } + delete tmp; + return true; +} + +url::url(const string url) throw(parse_error, logic_error) { + char *schm = new char[url.size()]; + char *auth = new char[url.size()]; + char *host = new char[url.size()]; + char *path = new char[url.size()]; + bool port_specified = false; + this->ips = NULL; + + // Break apart our url into 4 sections: scheme, auth (user/pass), host and path + // We'll do further parsing of auth and host a bit later + // NOTE: reset the unused variable after each scan or we get bleed-through + if (sscanf(url.c_str(), "%[^:]://%[^@]@%[^/]/%s", schm, auth, host, path) != 4 && !((*path = NULL)) && // URL with auth, host and path + sscanf(url.c_str(), "%[^:]://%[^@]@%[^/]", schm, auth, host) != 3 && !((*auth = NULL)) && // URL with auth, host + sscanf(url.c_str(), "%[^:]://%[^/]/%s", schm, host, path) != 3 && !((*path = NULL)) && // URL with host, path + sscanf(url.c_str(), "%[^:]://%[^/]", schm, host) != 2 && !((*host = NULL)) && // URL with host + !(sscanf(url.c_str(), "%[^:]://%s", schm, path) == 2 && string("file") == schm) && !((*path = NULL)) && // URL with path (ex: file:///foo) + !(sscanf(url.c_str(), "%[^:]://", schm) == 1 && (string("direct") == schm || string("wpad") == schm))) // URL with scheme-only (ex: wpad://, direct://) { - for (int i=0 ; self->ips[i] ; i++) - px_free(self->ips[i]); - px_free(self->ips); + delete schm; + delete auth; + delete host; + delete path; + throw parse_error("Invalid URL: " + url); + } + + // Set scheme and path + this->scheme = schm; + this->path = *path ? string("/") + path : ""; + *schm = NULL; + *path = NULL; + + // Parse auth further + if (*auth) { + this->user = auth; + if (string(auth).find(":") != string:: npos) { + this->pass = this->user.substr(this->user.find(":")+1); + this->user = this->user.substr(0, this->user.find(":")); + } + *auth = NULL; + } + + // Parse host further. Basically, we're looking for a port. + if (*host) { + this->host = host; + port_specified = sscanf(host, "%*[^:]:%d", &this->port) == 1; + if (port_specified) + this->host = this->host.substr(0, this->host.rfind(':')); + else + this->port = _get_default_port(this->scheme); + *host = NULL; } - px_free(self); + + // Cleanup + delete schm; + delete auth; + delete host; + delete path; + + // Verify by re-assembly + if (this->user != "" && this->pass != "") + this->orig = this->scheme + "://" + this->user + ":" + this->pass + "@" + this->host; + else + this->orig = this->scheme + "://" + this->host; + if (port_specified) + this->orig = this->orig + ":" + _to_string<int>(this->port) + this->path; + else + this->orig = this->orig + this->path; + if (this->orig != url) + throw logic_error("Re-assembly failed!"); +} + +url::url(const url &url) { + this->ips = NULL; + *this = url; +} + +url::~url() { + if (this->ips) { + for (vector<const sockaddr*>::iterator i = this->ips->begin() ; i != this->ips->end() ; i++) + delete *i; + delete this->ips; + } +} + +bool url::operator==(const url& url) const { + return this->orig == url.to_string(); } -/** - * Tells whether or not a pxURL string has valid syntax - * @return true if the pxURL is valid, otherwise false - */ -bool -px_url_is_valid(const char *url) -{ - pxURL *tmp = px_url_new(url); - if (!tmp) return false; - px_url_free(tmp); - return true; +url& url::operator=(const url& url) { + // Ensure these aren't the same objects + if (&url == this) + return *this; + + this->host = url.host; + this->orig = url.orig; + this->pass = url.pass; + this->path = url.path; + this->port = url.port; + this->scheme = url.scheme; + this->user = url.user; + + if (this->ips) { + // Free any existing ip cache + for (vector<const sockaddr*>::iterator i = this->ips->begin() ; i != this->ips->end() ; i++) + delete *i; + delete this->ips; + this->ips = NULL; + } + + if (url.ips) { + // Copy the new ip cache + this->ips = new vector<const sockaddr*>(); + for (vector<const sockaddr*>::iterator i = url.ips->begin() ; i != url.ips->end() ; i++) + this->ips->push_back(_copyaddr(**i)); + } + return *this; } -/** - * Sends a get request for the pxURL. - * @headers A list of headers to be included in the request. - * @return Socket to read the response on. - */ -int -px_url_get(pxURL *self, const char **headers) -{ - char *request = NULL; +url& url::operator=(string strurl) throw (parse_error) { + url* tmp = new url(strurl); + *this = *tmp; + delete tmp; + return *this; +} + +int url::open() { + map<string, string> headers; + return this->open(headers); +} + +int url::open(map<string, string> headers) { char *joined_headers = NULL; + string request; int sock = -1; - /* in case of a file:// url we open the file and return a hande to it */ - if (!strcmp(self->scheme,"file")) - return open(self->path, O_RDONLY); + // In case of a file:// url we open the file and return a handle to it + if (this->scheme == "file") + return ::open(this->path.c_str(), O_RDONLY); - /* DNS lookup of host */ - if (!px_url_get_ips(self, true)) goto error; + // DNS lookup of host + if (!this->get_ips(true)) goto error; - /* Iterate through each pxIP trying to make a connection */ - for (int i = 0 ; self->ips && self->ips[i] && sock < 0 ; i++) - { - sock = socket(self->ips[i]->sa_family, SOCK_STREAM, 0); + // Iterate through each IP trying to make a connection + for (vector<const sockaddr*>::iterator i = this->ips->begin() ; i != this->ips->end() ; i++) { + sock = socket((*i)->sa_family, SOCK_STREAM, 0); if (sock < 0) continue; - if (self->ips[i]->sa_family == AF_INET && - !connect(sock, self->ips[i], sizeof(struct sockaddr_in))) + if ((*i)->sa_family == AF_INET && + !connect(sock, *i, sizeof(struct sockaddr_in))) break; - else if (self->ips[i]->sa_family == AF_INET6 && - !connect(sock, self->ips[i], sizeof(struct sockaddr_in6))) + else if ((*i)->sa_family == AF_INET6 && + !connect(sock, *i, sizeof(struct sockaddr_in6))) break; close(sock); @@ -123,252 +221,90 @@ px_url_get(pxURL *self, const char **headers) } if (sock < 0) goto error; - /* Merge optional headers */ - if (headers) - { - joined_headers = px_strjoin(headers, "\r\n"); - if (!joined_headers) goto error; - } - else - joined_headers = px_strdup(""); + // Set any required headers + headers["Host"] = this->host; - /* Create request header */ - request = px_strcat("GET ", px_url_get_path(self), - " HTTP/1.1\r\nHost: ", px_url_get_host(self), - "\r\n", joined_headers, "\r\n\r\n", NULL); - px_free(joined_headers); + // Build the request string + request = "GET " + this->path + " HTTP/1.1\r\n"; + for (map<string, string>::iterator it = headers.begin() ; it != headers.end() ; it++) + request += it->first + ": " + it->second + "\r\n"; + request += "\r\n"; - /* Send HTTP request */ - if (send(sock, request, strlen(request), 0) != strlen(request)) goto error; - px_free(request); request = NULL; + // Send HTTP request + if (send(sock, request.c_str(), request.size(), 0) != request.size()) goto error; - /* Return the socket, which is ready for reading the response */ + // Return the socket, which is ready for reading the response return sock; error: if (sock >= 0) close(sock); - px_free(request); return -1; } -/** - * @return The default port for this type of pxURL - */ -static int -px_url_get_default_port(pxURL *self) -{ - struct servent *serv; - if ((serv = getservbyname(self->scheme, NULL))) return ntohs(serv->s_port); - return 0; -} - -/** - * @return Host portion of the pxURL - */ -const char * -px_url_get_host(pxURL *self) -{ - if (!self) return NULL; - return self->host; +string url::get_host() const { + return this->host; } -/** - * Get the IP addresses of the hostname in this pxURL. - * @usedns Should we look up hostnames in DNS? - * @return IP addresses of the host in the pxURL. - */ -const struct sockaddr ** -px_url_get_ips(pxURL *self, bool usedns) -{ - if (!self) return NULL; - - /* Check the cache */ - if (self->ips) return (const struct sockaddr **) self->ips; +const vector<const sockaddr*>* url::get_ips(bool usedns) { + // Check the cache + if (this->ips) return (const vector<const sockaddr*>*) this->ips; - /* Check without DNS first */ - if (usedns && px_url_get_ips(self, false)) return (const struct sockaddr **) self->ips; + // Check without DNS first + if (usedns && this->get_ips(false)) return (const vector<const sockaddr*>*) this->ips; - /* Check DNS for IPs */ - struct addrinfo *info; + // Check DNS for IPs + struct addrinfo* info; struct addrinfo flags; flags.ai_family = AF_UNSPEC; flags.ai_socktype = 0; flags.ai_protocol = 0; flags.ai_flags = AI_NUMERICHOST; - if (!getaddrinfo(px_url_get_host(self), NULL, usedns ? NULL : &flags, &info)) - { - struct addrinfo *first = info; - int count; - - /* Count how many IPs we got back */ - for (count=0 ; info ; info = info->ai_next) - count++; - - /* Copy the sockaddr's into self->ips */ - info = first; - self->ips = (struct sockaddr **) px_malloc0(sizeof(struct sockaddr *) * ++count); - for (int i=0 ; info ; info = info->ai_next) - { - if (info->ai_addr->sa_family == AF_INET) - { - self->ips[i] = (struct sockaddr *) px_malloc0(sizeof(struct sockaddr_in)); - memcpy(self->ips[i], info->ai_addr, sizeof(struct sockaddr_in)); - ((struct sockaddr_in *) self->ips[i++])->sin_port = htons(self->port); - } - else if (info->ai_addr->sa_family == AF_INET6) - { - self->ips[i] = (struct sockaddr *) px_malloc0(sizeof(struct sockaddr_in6)); - memcpy(self->ips[i], info->ai_addr, sizeof(struct sockaddr_in6)); - ((struct sockaddr_in6 *) self->ips[i++])->sin6_port = htons(self->port); + if (!getaddrinfo(this->host.c_str(), NULL, usedns ? NULL : &flags, &info)) { + struct addrinfo* first = info; + + // Create our vector since we actually have a result + this->ips = new vector<const sockaddr*>(); + + // Copy the sockaddr's into this->ips + for ( ; info ; info = info->ai_next) { + if (info->ai_addr->sa_family == AF_INET || info->ai_addr->sa_family == AF_INET6) { + this->ips->push_back(_copyaddr(*(info->ai_addr))); + ((sockaddr_in*)(*(this->ips))[this->ips->size()-1])->sin_port = htons(this->port); } } freeaddrinfo(first); - return (const struct sockaddr **) self->ips; + return (const vector<const sockaddr*>*) this->ips; } - /* No addresses found */ + // No addresses found return NULL; } -/** - * @return Password portion of the pxURL - */ -const char * -px_url_get_password(pxURL *self) -{ - if (!self) return NULL; - return self->password; +string url::get_password() const { + return this->pass; } -/** - * @return Path portion of the pxURL - */ -const char * -px_url_get_path(pxURL *self) -{ - if (!self) return NULL; - return self->path; +string url::get_path() const { + return this->path; } -/** - * @return Port portion of the pxURL - */ -int -px_url_get_port(pxURL *self) -{ - if (!self) return 0; - return self->port; +int url::get_port() const { + return this->port; } -/** - * @return Scheme portion of the pxURL - */ -__attribute__ ((visibility("default"))) -const char * -px_url_get_scheme(pxURL *self) -{ - if (!self) return NULL; - return self->scheme; +string url::get_scheme() const { + return this->scheme; } -/** - * @return Username portion of the pxURL - */ -const char * -px_url_get_username(pxURL *self) -{ - if (!self) return NULL; - return self->username; +string url::get_username() const { + return this->user; } -/** - * @url String used to create the new pxURL object - * @return New pxURL object - */ -pxURL * -px_url_new(const char *url) -{ - bool port_specified; - if (!url) return NULL; - const char *start = url; - - /* Allocate pxURL */ - pxURL *self = (pxURL *) px_malloc0(sizeof(pxURL)); - - /* Get scheme */ - if (!strstr(start, "://")) goto error; - self->scheme = px_strndup(start, strstr(start, "://") - start); - start += strlen(self->scheme) + 3; - - /* If we have a username and password */ - if (strchr(start, '@') && (strchr(start, '/') > strchr(start, '@') || strchr(start, '/') == NULL)) - { - if (!strchr(start, ':')) goto error; // Can't find user/pass delimiter - self->username = px_strndup(start, strchr(start, ':') - start); - start += strlen(self->username) + 1; - self->password = px_strndup(start, strchr(start, '@') - start); - start += strlen(self->password) + 1; - } - - /* Get host */ - self->host = px_strdup(start); - - /* Get path */ - self->path = px_strdup(strchr(self->host, '/')); - if (self->path) - self->host[strlen(self->host) - strlen(self->path)] = 0; - else - self->path = px_strdup(""); - - /* Get the port */ - port_specified = false; - if (strchr(self->host, ':')) { - if (!atoi(strchr(self->host, ':')+1)) goto error; - self->port = atoi(strchr(self->host, ':')+1); - *(strchr(self->host, ':')) = 0; - port_specified = true; - } - else - self->port = px_url_get_default_port(self); - - /* Make sure we have a real host */ - if (!strcmp(self->host, "") && strcmp(self->scheme, "file")) goto error; - - /* Verify by re-assembly */ - self->url = (char *) px_malloc0(strlen(url) + 1); - if (self->username && self->password) - snprintf(self->url, strlen(url) + 1, "%s://%s:%s@%s", self->scheme, self->username, self->password, self->host); - else - snprintf(self->url, strlen(url) + 1, "%s://%s", self->scheme, self->host); - if (port_specified) - snprintf(self->url + strlen(self->url), strlen(url) + 1 - strlen(self->url), ":%d%s", self->port, self->path); - else - snprintf(self->url + strlen(self->url), strlen(url) + 1 - strlen(self->url), "%s", self->path); - if (strcmp(self->url, url)) goto error; - - return self; - - error: - px_url_free(self); - return NULL; +string url::to_string() const { + return this->orig; } -/** - * @return String representation of the pxURL - */ -const char * -px_url_to_string(pxURL *self) -{ - if (!self) return NULL; - return self->url; } - -/** - * @return true if the URLs are the same, else false - */ -bool -px_url_equals(pxURL *self, const pxURL *other) -{ - return !strcmp(px_url_to_string(self), px_url_to_string((pxURL*) other)); +} } diff --git a/libproxy/url.hpp b/libproxy/url.hpp index d12fc22..27b4711 100644 --- a/libproxy/url.hpp +++ b/libproxy/url.hpp @@ -17,91 +17,72 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ******************************************************************************/ -#ifndef URL_H_ -#define URL_H_ - -#include "stdbool.h" /* For type bool */ - -/** - * WPAD object. All fields are private. - */ -typedef struct _pxURL pxURL; - -/** - * @return Frees the pxURL - */ -void px_url_free(pxURL *self); - -/** - * Tells whether or not a pxURL string has valid syntax - * @return true if the pxURL is valid, otherwise false - */ -__attribute__ ((visibility("default"))) -bool px_url_is_valid(const char *url); - -/** - * Sends a get request for the pxURL. - * @headers A list of headers to be included in the request. - * @return Socket to read the response on. - */ -int px_url_get(pxURL *self, const char **headers); - -/** - * @return Host portion of the pxURL - */ -__attribute__ ((visibility("default"))) -const char *px_url_get_host(pxURL *self); - -/** - * Get the IP addresses of the hostname in this pxURL. - * @usedns Should we look up hostnames in DNS? - * @return IP addresses of the host in the pxURL. - */ -__attribute__ ((visibility("default"))) -const struct sockaddr **px_url_get_ips(pxURL *self, bool usedns); - -/** - * @return Password portion of the pxURL - */ -const char *px_url_get_password(pxURL *self); - -/** - * @return Path portion of the pxURL - */ -const char *px_url_get_path(pxURL *self); - -/** - * @return Port portion of the pxURL - */ -__attribute__ ((visibility("default"))) -int px_url_get_port(pxURL *self); - -/** - * @return Scheme portion of the pxURL - */ -__attribute__ ((visibility("default"))) -const char *px_url_get_scheme(pxURL *self); - -/** - * @return Username portion of the pxURL - */ -const char *px_url_get_username(pxURL *self); - -/** - * @url String used to create the new pxURL object - * @return New pxURL object - */ -pxURL *px_url_new(const char *url); - -/** - * @return String representation of the pxURL - */ -__attribute__ ((visibility("default"))) -const char *px_url_to_string(pxURL *self); - -/** - * @return true if the URLs are the same, else false - */ -bool px_url_equals(pxURL *self, const pxURL *other); - -#endif /*URL_H_*/ +#ifndef URL_HPP_ +#define URL_HPP_ + +#ifdef _WIN32 +#define _WIN32_WINNT 0x0501 +#include <winsock2.h> +#include <ws2tcpip.h> +#else +#include <sys/socket.h> +#include <netdb.h> +#include <arpa/inet.h> +#include <netinet/in.h> +#endif + +#include <map> +#include <stdexcept> +#include <string> +#include <vector> + +namespace com { +namespace googlecode { +namespace libproxy { + +using namespace std; + +class parse_error : public runtime_error { +public: + parse_error(const string& __arg): runtime_error(__arg) {} +}; + +class url { +public: + static bool is_valid(const string url); + + ~url(); + url(const url& url); + url(string url) throw (parse_error, logic_error); + bool operator==(const url& url) const; + url& operator=(const url& url); + url& operator=(string url) throw (parse_error); + + int open(); + int open(map<string, string> headers); + + string get_host() const; + const vector<const sockaddr*>* get_ips(bool usedns); + string get_password() const; + string get_path() const; + int get_port() const; + string get_scheme() const; + string get_username() const; + string to_string() const; + +private: + string host; + vector<const sockaddr*>* ips; + string pass; + string path; + int port; + string scheme; + string orig; + string user; +}; + +} +} +} + +#endif /*URL_HPP_*/ diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt index 4f27eb7..eebe337 100644 --- a/utils/CMakeLists.txt +++ b/utils/CMakeLists.txt @@ -5,8 +5,5 @@ add_executable(proxy proxy.c) target_link_libraries(proxy libproxy) install(TARGETS proxy RUNTIME DESTINATION ${rbindir}) -add_executable(iniparse iniparse.c) -target_link_libraries(iniparse libproxy) - -set_target_properties(proxy iniparse PROPERTIES COMPILE_FLAGS "-g -std=c99") +set_target_properties(proxy PROPERTIES COMPILE_FLAGS "-g -std=c99") diff --git a/utils/iniparse.c b/utils/iniparse.c deleted file mode 100644 index 211f835..0000000 --- a/utils/iniparse.c +++ /dev/null @@ -1,23 +0,0 @@ -#include <stdio.h> - -#include "../libproxy/strdict.h" -#include "../libproxy/config_file.h" - -int main(int argc, char **argv) { - if (argc != 4) { - printf("You started with %d parameters.\n", argc); - printf("Wrong invocation. Start with 3 parameters:\n"); - printf("1. path to config file\n2. Section name in conf file.\n3. Keyname to read.\n"); - printf("iniparse will return \"key = value\" if found\n."); - return 2; - } - pxConfigFile* cf = px_config_file_new(argv[1]); - if (!cf) { - printf("Could not find conf file.\n."); - return 1; - } - char* val1 = px_config_file_get_value(cf, argv[2], argv[3]); - printf("%s = %s", argv[3] == NULL ? "NULL" : argv[3], val1 == NULL ? "NULL" : val1); - px_config_file_free(cf); - return 0; -} |