diff options
author | npmccallum <npmccallum@c587cffe-e639-0410-9787-d7902ae8ed56> | 2008-06-05 20:56:04 +0000 |
---|---|---|
committer | npmccallum <npmccallum@c587cffe-e639-0410-9787-d7902ae8ed56> | 2008-06-05 20:56:04 +0000 |
commit | 9a401f3d7392134859a809905b11b7bcfaeea50b (patch) | |
tree | f34c169d4e4f43546bd4404af8c69be09e30ea55 /src/lib/proxy_factory.c | |
parent | 197ba7edc0ce6f6758b198821a9c6bf7c1fd1932 (diff) | |
download | libproxy-git-libproxy-0.2.3.tar.gz |
The real 0.2.3 releaselibproxy-0.2.3
Diffstat (limited to 'src/lib/proxy_factory.c')
-rw-r--r-- | src/lib/proxy_factory.c | 402 |
1 files changed, 264 insertions, 138 deletions
diff --git a/src/lib/proxy_factory.c b/src/lib/proxy_factory.c index 1376563..5591c9c 100644 --- a/src/lib/proxy_factory.c +++ b/src/lib/proxy_factory.c @@ -34,8 +34,6 @@ #include "proxy_factory.h" #include "wpad.h" #include "config_file.h" -#include "array.h" -#include "strdict.h" #define DEFAULT_CONFIG_ORDER "USER,SESSION,SYSTEM" @@ -46,19 +44,25 @@ struct _pxProxyFactoryConfig { }; typedef struct _pxProxyFactoryConfig pxProxyFactoryConfig; +struct _pxKeyVal { + char *key; + void *value; +}; +typedef struct _pxKeyVal pxKeyVal; + struct _pxProxyFactory { - pthread_mutex_t mutex; - pxArray *plugins; - pxProxyFactoryConfig **configs; - pxStrDict *misc; - pxArray *on_get_proxies; - pxPACRunnerCallback pac_runner; - pxPAC *pac; - pxWPAD *wpad; - pxConfigFile *cf; + pthread_mutex_t mutex; + void **plugins; + pxProxyFactoryConfig **configs; + pxKeyVal **misc; + pxProxyFactoryVoidCallback *on_get_proxy; + pxPACRunnerCallback pac_runner; + pxPAC *pac; + pxWPAD *wpad; + pxConfigFile *cf; }; -/* Convert the PAC formatted response into our proxy URL array response */ +// Convert the PAC formatted response into our proxy URL array response static char ** _format_pac_response(char *response) { @@ -107,7 +111,7 @@ _sockaddr_equals(const struct sockaddr *ip_a, const struct sockaddr *ip_b, const 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 */ + // Setup the arrays uint8_t bytes = 0, *a_data = NULL, *b_data = NULL, *nm_data = NULL; if (ip_a->sa_family == AF_INET) { @@ -142,26 +146,26 @@ _sockaddr_from_string(const char *ip, int len) if (!ip) return NULL; struct sockaddr *result = NULL; - /* Copy the string */ + // Copy the string if (len >= 0) ip = px_strndup(ip, len); else ip = px_strdup(ip); - /* Try to parse IPv4 */ + // Try to parse IPv4 result = px_malloc0(sizeof(struct sockaddr_in)); result->sa_family = AF_INET; if (inet_pton(AF_INET, ip, &((struct sockaddr_in *) result)->sin_addr) > 0) goto out; - /* Try to parse IPv6 */ + // Try to parse IPv6 px_free(result); result = px_malloc0(sizeof(struct sockaddr_in6)); result->sa_family = AF_INET6; if (inet_pton(AF_INET6, ip, &((struct sockaddr_in6 *) result)->sin6_addr) > 0) goto out; - /* No address found */ + // No address found px_free(result); result = NULL; out: @@ -172,7 +176,7 @@ _sockaddr_from_string(const char *ip, int len) static struct sockaddr * _sockaddr_from_cidr(int af, int cidr) { - /* TODO: Support CIDR notation */ + // TODO: Support CIDR notation return NULL; } @@ -186,25 +190,21 @@ _ip_ignore(pxURL *url, char *ignore) const struct sockaddr *dst_ip = px_url_get_ip_no_dns(url); struct sockaddr *ign_ip = NULL, *net_ip = NULL; - /* - * IPv4 - * IPv6 - */ + // IPv4 + // IPv6 if ((ign_ip = _sockaddr_from_string(ignore, -1))) goto out; - /* - * IPv4/CIDR - * IPv4/IPv4 - * IPv6/CIDR - * IPv6/IPv6 - */ + // 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 CIDR notation was used, get the netmask if (ign_ip && !net_ip) { uint32_t cidr = 0; @@ -221,15 +221,13 @@ _ip_ignore(pxURL *url, char *ignore) net_ip = NULL; } - /* - * IPv4:port - * [IPv6]:port - */ + // 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 */ + // 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; @@ -251,11 +249,11 @@ _domain_ignore(pxURL *url, char *ignore) if (!url || !ignore) return false; - /* Get our URL's hostname and 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 */ + // Get our ignore pattern's hostname and port char *ihost = px_strdup(ignore); int iport = 0; if (strchr(ihost, ':')) @@ -267,49 +265,33 @@ _domain_ignore(pxURL *url, char *ignore) iport = 0; } - /* Hostname match (domain.com or domain.com:80) */ + // 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) */ + // Endswith (.domain.com or .domain.com:80) if (ihost[0] == '.' && _endswith(host, ihost)) if (!iport || port == iport) goto match; - /* Glob (*.domain.com or *.domain.com:80) */ + // Glob (*.domain.com or *.domain.com:80) if (ihost[0] == '*' && _endswith(host, ihost+1)) if (!iport || port == iport) goto match; - /* No match was found */ + // No match was found px_free(host); px_free(ihost); return false; - /* A match was found */ + // A match was found match: px_free(host); px_free(ihost); return true; } -static void -destantiate_plugins(void *item, void *self) -{ - /* Call the destantiation hook */ - pxProxyFactoryVoidCallback destantiate; - destantiate = dlsym(item, "on_proxy_factory_destantiate"); - if (destantiate) - destantiate(self); -} - -static void -call_on_proxy_factory_get_proxies(void *item, void *self) -{ - ((pxProxyFactoryVoidCallback) item)(self); -} - /** * Creates a new pxProxyFactory instance. * @@ -319,33 +301,44 @@ pxProxyFactory * px_proxy_factory_new () { pxProxyFactory *self = px_malloc0(sizeof(pxProxyFactory)); + unsigned int i; + + // Create the mutex pthread_mutex_init(&self->mutex, NULL); - self->plugins = px_array_new(NULL, (void *) dlclose, true, false); - self->misc = px_strdict_new(NULL); - self->on_get_proxies = px_array_new(NULL, NULL, true, false); - /* Open the plugin dir */ + // Open the plugin dir DIR *plugindir = opendir(PLUGINDIR); if (!plugindir) return self; - /* For each plugin... */ + // Count the number of plugins + for (i=0 ; readdir(plugindir) ; i++); + self->plugins = (void **) px_malloc0(sizeof(void *) * (i + 1)); + rewinddir(plugindir); + + // For each plugin... struct dirent *ent; - for (int i=0 ; (ent = readdir(plugindir)) ; i++) + for (i=0 ; (ent = readdir(plugindir)) ; i++) { - /* Load the plugin */ + // Load the plugin char *tmp = px_strcat(PLUGINDIR, "/", ent->d_name, NULL); - void *plugin = dlopen(tmp, RTLD_NOW | RTLD_LOCAL); + self->plugins[i] = dlopen(tmp, RTLD_NOW | RTLD_LOCAL); px_free(tmp); - if (!plugin) + if (!(self->plugins[i])) + { + dlerror(); + i--; continue; + } - /* Call the instantiation hook */ + // Call the instantiation hook pxProxyFactoryBoolCallback instantiate; - instantiate = dlsym(plugin, "on_proxy_factory_instantiate"); + instantiate = dlsym(self->plugins[i], "on_proxy_factory_instantiate"); if (instantiate && !instantiate(self)) - dlclose(plugin); - else if (instantiate) - px_array_add(self->plugins, plugin); + { + dlclose(self->plugins[i]); + self->plugins[i--] = NULL; + continue; + } } closedir(plugindir); @@ -358,29 +351,27 @@ px_proxy_factory_config_add(pxProxyFactory *self, const char *name, pxConfigCate int count; pxProxyFactoryConfig **tmp; - /* Verify some basic stuff */ + // Verify some basic stuff if (!self) return false; if (!callback) return false; if (!name || !strcmp(name, "")) return false; - /* Allocate an empty config array if there is none */ + // Allocate an empty config array if there is none if (!self->configs) self->configs = px_malloc0(sizeof(pxProxyFactoryConfig *)); - /* - * Make sure that 'name' is unique - * Also, get a count of how many configs we have - */ + // Make sure that 'name' is unique + // Also, get a count of how many configs we have for (count=0 ; self->configs[count] ; count++) if (!strcmp(self->configs[count]->name, name)) return false; - /* Allocate new array, copy old values into it and free old array */ + // Allocate new array, copy old values into it and free old array tmp = px_malloc0(sizeof(pxProxyFactoryConfig *) * (count + 2)); memcpy(tmp, self->configs, sizeof(pxProxyFactoryConfig *) * count); px_free(self->configs); self->configs = tmp; - /* Add the new callback to the end */ + // Add the new callback to the end self->configs[count] = px_malloc0(sizeof(pxProxyFactoryConfig)); self->configs[count]->category = category; self->configs[count]->name = px_strdup(name); @@ -394,12 +385,12 @@ px_proxy_factory_config_del(pxProxyFactory *self, const char *name) { int i,j; - /* Verify some basic stuff */ + // Verify some basic stuff if (!self) return false; if (!name || !strcmp(name, "")) return false; if (!self->configs) return false; - /* Remove and shift all configs down (if found) */ + // Remove and shift all configs down (if found) for (i=0,j=0 ; self->configs[j]; i++,j++) { if (i != j) @@ -411,7 +402,7 @@ px_proxy_factory_config_del(pxProxyFactory *self, const char *name) } } - /* If we have an empty array, free it */ + // If we have an empty array, free it if (!self->configs[0]) { px_free(self->configs); @@ -424,21 +415,83 @@ px_proxy_factory_config_del(pxProxyFactory *self, const char *name) bool px_proxy_factory_misc_set(pxProxyFactory *self, const char *key, const void *value) { - /* Verify some basic stuff */ - if (!self) return false; - if (!key || !strcmp(key, "")) return false; - - return px_strdict_set(self->misc, key, (void *) value); + int count; + pxKeyVal **tmp; + + // Verify some basic stuff + if (!self) return false; + if (!key || !strcmp(key, "")) return false; + + // Allocate an empty config array if there is none + if (!self->misc) self->misc = px_malloc0(sizeof(pxKeyVal *)); + + // Count the number of values + for (count=0 ; self->misc[count] ; count++); + + // Unset value + if (!value) + { + // Remove the keyval, shifting downward + for (int i=0,j=0 ; self->misc[i] ; i++, j++) + { + // If the key is found, remove it + if (!strcmp(key, self->misc[i]->key)) + { + px_free(self->misc[i]->key); + px_free(self->misc[i]); + self->misc[i] = NULL; + count--; + j--; + } + + // Shift down + if (i > 0 && j > 0) + self->misc[j] = self->misc[i]; + } + + // Resize array + tmp = px_malloc0(sizeof(pxKeyVal *) * (count + 1)); + memcpy(tmp, self->misc, sizeof(pxKeyVal *) * count); + px_free(self->misc); + self->misc = tmp; + return true; + } + + // Attempt to update the value within the array + for (int i=0 ; self->misc[i] ; i++) + { + if (!strcmp(key, self->misc[i]->key)) + { + self->misc[i]->value = (void *) value; + return true; + } + } + + // The key was not found in the array, so add it + tmp = px_malloc0(sizeof(pxKeyVal *) * (count + 2)); + memcpy(tmp, self->misc, sizeof(pxKeyVal *) * count); + tmp[count] = px_malloc0(sizeof(pxKeyVal)); + tmp[count]->key = px_strdup(key); + tmp[count]->value = (void *) value; + px_free(self->misc); + self->misc = tmp; + return true; } void * px_proxy_factory_misc_get(pxProxyFactory *self, const char *key) { - /* Verify some basic stuff */ + // Verify some basic stuff if (!self) return NULL; if (!key || !strcmp(key, "")) return NULL; + if (!self->misc) return NULL; + + // Find the value listed + for (int i=0 ; self->misc[i] ; i++) + if (!strcmp(key, self->misc[i]->key)) + return self->misc[i]->value; - return (void *) px_strdict_get(self->misc, key); + return NULL; } /** @@ -446,9 +499,6 @@ px_proxy_factory_misc_get(pxProxyFactory *self, const char *key) * * 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. * * The format of the returned proxy strings are as follows: * - http://proxy:port @@ -465,47 +515,48 @@ px_proxy_factory_get_proxies (pxProxyFactory *self, char *url) char **response = px_strsplit("direct://", ";"); char *tmp = NULL, *order = NULL, **orderv = NULL; - /* Verify some basic stuff */ + // Verify some basic stuff if (!self) goto do_return; if (!url || !strcmp(url, "")) goto do_return; if (!realurl) goto do_return; - /* Lock mutex */ + // Lock mutex pthread_mutex_lock(&self->mutex); - /* Call the events */ - px_array_foreach(self->on_get_proxies, call_on_proxy_factory_get_proxies, self); + // Call the events + for (int i=0 ; self->on_get_proxy && self->on_get_proxy[i] ; i++) + self->on_get_proxy[i](self); - /* If our config file is stale, close it */ + // If our config file is stale, close it if (self->cf && px_config_file_is_stale(self->cf)) { px_config_file_free(self->cf); self->cf = NULL; } - /* Try to open our config file if we don't have one */ + // Try to open our config file if we don't have one if (!self->cf) self->cf = px_config_file_new(SYSCONFDIR "/proxy.conf"); - /* If we have a config file, load the order from it */ + // If we have a config file, load the order from it if (self->cf) tmp = px_config_file_get_value(self->cf, PX_CONFIG_FILE_DEFAULT_SECTION, "config_order"); - /* Attempt to get info from the environment */ + // Attempt to get info from the environment order = getenv("PX_CONFIG_ORDER"); - /* Create the config order */ + // Create the config order order = px_strcat(tmp ? tmp : "", ",", order ? order : "", ",", DEFAULT_CONFIG_ORDER, NULL); px_free(tmp); tmp = NULL; - /* Create the config plugin order vector */ + // Create the config plugin order vector orderv = px_strsplit(order, ","); px_free(order); - /* Get the config by searching the config order */ + // Get the config by searching the config order for (int i=0 ; orderv[i] && !config ; i++) { - /* Get the category (if applicable) */ + // Get the category (if applicable) pxConfigCategory category; if (!strcmp(orderv[i], "USER")) category = PX_CONFIG_CATEGORY_USER; @@ -526,11 +577,11 @@ px_proxy_factory_get_proxies (pxProxyFactory *self, char *url) } px_strfreev(orderv); - /* No config was found via search order, call all plugins */ + // No config was found via search order, call all plugins for (int i=0 ; self->configs && self->configs[i] && !config ; i++) config = self->configs[i]->callback(self); - /* No plugin returned a valid config, fall back to 'wpad://' */ + // No plugin returned a valid config, fall back to 'wpad://' if (!config) { fprintf(stderr, "*** Unable to locate valid config! Falling back to auto-detection...\n"); @@ -539,7 +590,7 @@ px_proxy_factory_get_proxies (pxProxyFactory *self, char *url) config->ignore = px_strdup(""); } - /* If the config plugin returned an invalid config type or malformed URL, fall back to 'wpad://' */ + // If the config plugin returned an invalid config type or malformed URL, fall back to 'wpad://' if (!(!strncmp(config->url, "http://", 7) || !strncmp(config->url, "socks://", 8) || !strncmp(config->url, "pac+", 4) || @@ -564,7 +615,7 @@ px_proxy_factory_get_proxies (pxProxyFactory *self, char *url) config->url = px_strdup("wpad://"); } - /* Check our ignore patterns */ + // Check our ignore patterns char **ignores = px_strsplit(config->ignore, ","); for (int i=0 ; ignores[i] ; i++) { @@ -576,10 +627,10 @@ px_proxy_factory_get_proxies (pxProxyFactory *self, char *url) } px_strfreev(ignores); - /* If we have a wpad config */ + // If we have a wpad config if (!strcmp(config->url, "wpad://")) { - /* Get the WPAD object if needed */ + // Get the WPAD object if needed if (!self->wpad) { if (self->pac) px_pac_free(self->pac); @@ -592,46 +643,45 @@ px_proxy_factory_get_proxies (pxProxyFactory *self, char *url) } } - /* - * If we have no PAC, get one - * If getting the PAC fails, but the WPAD cycle worked, restart the cycle - */ + // If we have no PAC, get one + // If getting the PAC fails, but the WPAD cycle worked, restart the cycle if (!self->pac && !(self->pac = px_wpad_next(self->wpad)) && px_wpad_pac_found(self->wpad)) { px_wpad_rewind(self->wpad); self->pac = px_wpad_next(self->wpad); } - /* If the WPAD cycle failed, fall back to direct */ + // If the WPAD cycle failed, fall back to direct if (!self->pac) { fprintf(stderr, "*** Unable to locate PAC! Falling back to direct...\n"); goto do_return; } - /* Run the PAC */ + // Run the PAC if (self->pac_runner) { px_strfreev(response); response = _format_pac_response(self->pac_runner(self, self->pac, realurl)); } - /* No PAC runner found, fall back to direct */ + // No PAC runner found, fall back to direct else fprintf(stderr, "*** PAC found, but no active PAC runner! Falling back to direct...\n"); } - /* If we have a PAC config */ + // If we have a PAC config else if (!strncmp(config->url, "pac+", 4)) { - /* Clear WPAD to indicate that this is a non-WPAD PAC */ + // Clear WPAD to indicate that this is a non-WPAD PAC if (self->wpad) { px_wpad_free(self->wpad); self->wpad = NULL; } - /* If a PAC already exists, but came from a different URL than the one specified, remove it */ + // If a PAC alread exists, but comes from a different URL than the one + // specified, remove it if (self->pac) { pxURL *urltmp = px_url_new(config->url + 4); @@ -648,14 +698,14 @@ px_proxy_factory_get_proxies (pxProxyFactory *self, char *url) px_url_free(urltmp); } - /* Try to load the PAC if it is not already loaded */ + // Try to load the PAC if it is not already loaded if (!self->pac && !(self->pac = px_pac_new_from_string(config->url + 4))) { fprintf(stderr, "*** Invalid PAC URL! Falling back to direct...\n"); goto do_return; } - /* Run the PAC */ + // Run the PAC if (self->pac_runner) { px_strfreev(response); @@ -665,7 +715,7 @@ px_proxy_factory_get_proxies (pxProxyFactory *self, char *url) fprintf(stderr, "*** PAC found, but no active PAC runner! Falling back to direct...\n"); } - /* If we have a manual config (http://..., socks://...) */ + // If we have a manual config (http://..., socks://...) else if (!strncmp(config->url, "http://", 7) || !strncmp(config->url, "socks://", 8)) { if (self->wpad) { px_wpad_free(self->wpad); self->wpad = NULL; } @@ -674,7 +724,7 @@ px_proxy_factory_get_proxies (pxProxyFactory *self, char *url) response = px_strsplit(config->url, ";"); } - /* Actually return, freeing misc stuff */ + // Actually return, freeing misc stuff do_return: if (config) { px_free(config->url); px_free(config->ignore); px_free(config); } if (realurl) px_url_free(realurl); @@ -683,15 +733,60 @@ px_proxy_factory_get_proxies (pxProxyFactory *self, char *url) } bool -px_proxy_factory_on_get_proxies_add (pxProxyFactory *self, pxProxyFactoryVoidCallback callback) +px_proxy_factory_on_get_proxy_add (pxProxyFactory *self, pxProxyFactoryVoidCallback callback) { - return self ? px_array_add(self->on_get_proxies, callback) : false; + int count; + pxProxyFactoryVoidCallback *tmp; + + // Verify some basic stuff + if (!self) return false; + if (!callback) return false; + + // Allocate an empty config array if there is none + if (!self->on_get_proxy) self->on_get_proxy = px_malloc0(sizeof(pxProxyFactoryVoidCallback)); + + // Get a count of how many callbacks we have + for (count=0 ; self->on_get_proxy[count] ; count++); + + // Allocate new array, copy old values into it and free old array + tmp = px_malloc0(sizeof(pxProxyFactoryVoidCallback) * (count + 2)); + memcpy(tmp, self->on_get_proxy, sizeof(pxProxyFactoryVoidCallback) * count); + px_free(self->on_get_proxy); + self->on_get_proxy = tmp; + + // Add the new callback to the end + self->on_get_proxy[count] = callback; + + return true; } bool -px_proxy_factory_on_get_proxies_del (pxProxyFactory *self, pxProxyFactoryVoidCallback callback) +px_proxy_factory_on_get_proxy_del (pxProxyFactory *self, pxProxyFactoryVoidCallback callback) { - return self ? px_array_del(self->on_get_proxies, callback) : false; + int i,j; + + // Verify some basic stuff + if (!self) return false; + if (!callback) return false; + if (!self->on_get_proxy) return false; + + // Remove and shift all callbacks down (if found) + for (i=0,j=0 ; self->on_get_proxy[j]; i++,j++) + { + if (i != j) + self->on_get_proxy[j] = self->on_get_proxy[i]; + else if (self->on_get_proxy[i] == callback) + self->on_get_proxy[j--] = NULL; + } + + // If we have an empty array, free it + if (!self->on_get_proxy[0]) + { + px_free(self->on_get_proxy); + self->on_get_proxy = NULL; + } + + return i != j ? true : false; } bool @@ -706,10 +801,17 @@ px_proxy_factory_pac_runner_set (pxProxyFactory *self, pxPACRunnerCallback callb void px_proxy_factory_network_changed(pxProxyFactory *self) { - px_wpad_free(self->wpad); - px_pac_free(self->pac); - self->wpad = NULL; - self->pac = NULL; + if (self->wpad) + { + px_wpad_free(self->wpad); + self->wpad = NULL; + } + + if (self->pac) + { + px_pac_free(self->pac); + self->pac = NULL; + } } /** @@ -718,18 +820,42 @@ px_proxy_factory_network_changed(pxProxyFactory *self) void px_proxy_factory_free (pxProxyFactory *self) { + unsigned int i; + if (!self) return; pthread_mutex_lock(&self->mutex); - /* Free the plugins */ - px_array_foreach(self->plugins, destantiate_plugins, self); - px_array_free(self->plugins); + // Free the plugins + if (self->plugins) + { + for (i=0 ; self->plugins[i] ; i++) + { + // Call the destantiation hook + pxProxyFactoryVoidCallback destantiate; + destantiate = dlsym(self->plugins[i], "on_proxy_factory_destantiate"); + if (destantiate) + destantiate(self); + + // Unload the plugin + dlclose(self->plugins[i]); + self->plugins[i] = NULL; + } + px_free(self->plugins); + } - /* Free misc */ - px_strdict_free(self->misc); + // Free misc + if (self->misc) + { + for (i=0 ; self->misc[i] ; i++) + { + px_free(self->misc[i]->key); + px_free(self->misc[i]); + } + px_free(self->misc); + } - /* Free everything else */ + // Free everything else px_pac_free(self->pac); px_wpad_free(self->wpad); px_config_file_free(self->cf); |