#include "config.hpp"
#include "common.hpp"
#include <getopt.h>
static bool add_proxy(const char* p, std::vector<proxy_t>& proxies) {
proxy_t proxy;
if (strncmp(p, "http://", 7) == 0) {
p += 7;
proxy.type = proxy_t::PROXY_TYPE_HTTP;
} else if (strncmp(p, "socks4://", 9) == 0) {
p += 9;
proxy.type = proxy_t::PROXY_TYPE_SOCKS;
} else {
LOG("unsupported type for '%s'", p);
return false;
}
if (!str2addr(p, &proxy.addr, true)) {
LOG("cannot parse address '%s'", p);
return false;
}
strcpy(proxy.addrstr, addr2str(&proxy.addr, true));
for (std::vector<proxy_t>::iterator it = proxies.begin(); it != proxies.end(); ++it) {
if (it->type == proxy.type && strcmp(it->addrstr, proxy.addrstr) == 0) {
LOG("skipping duplicate '%s'", p);
return true;
}
}
static unsigned id = 0;
proxy.id = id++;
proxies.push_back(proxy);
return true;
}
static bool load_proxies(const char* fn, std::vector<proxy_t>& proxies) {
FILE* fp = fopen(fn, "r");
if (!fp) {
LOG_ERRNO("cannot open '%s'", fn);
return false;
}
char* line = NULL;
size_t len = 0;
while (getline(&line, &len, fp) != -1) {
char* p = line;
while (*p == ' ' || *p == '\t') ++p;
if (*p == '\0' || *p == '#' || *p == '\n') continue;
char* e = strchrnul(p, '\n');
while (e != p && (*e == '\n' || *e == '\r' || *e == ' ')) { *e = '\0'; --e; }
if (!add_proxy(p, proxies)) {
free(line);
fclose(fp);
return false;
}
}
free(line);
fclose(fp);
return true;
}
bool parse_config(config_t& config, in_port_t& port, int argc, char** argv) {
static struct option long_options[] = {
{"port", required_argument, 0, 'p'},
{"min", required_argument, 0, 'm'},
{"pool", required_argument, 0, 'o'},
{"proxies", required_argument, 0, 'f'},
{0, 0, 0, 0}
};
port = 0;
config.mode = config_t::MODE_CHAIN;
int min_proxies = -1;
const char* conffile = NULL;
while (1) {
int i;
int c = getopt_long(argc, argv, "p:m:o:f:", long_options, &i);
if (c == -1) break;
switch (c) {
case 'p':
i = atoi(optarg);
if (i < 1 || i > 0xffff) return false;
port = i;
break;
case 'o':
config.mode = config_t::MODE_POOL;
// fall thru
case 'm':
if (min_proxies >= 0) return false;
min_proxies = atoi(optarg);
if (min_proxies < 0 || (!min_proxies && strcmp(optarg, "0"))) return false;
break;
case 'f':
if (conffile) return false;
conffile = optarg;
break;
default:
return false;
break;
}
}
if (conffile != NULL) {
if (!load_proxies(conffile, config.proxies)) {
return false;
}
}
while (optind < argc) {
if (!add_proxy(argv[optind++], config.proxies)) {
return false;
}
}
if (min_proxies < 0) {
config.min_proxies = (config.mode == config_t::MODE_CHAIN)? config.proxies.size(): 1; // default
} else {
config.min_proxies = (unsigned)min_proxies;
}
if (!port) return false;
if (config.min_proxies > config.proxies.size()) return false;
if (!config.min_proxies && config.mode == config_t::MODE_POOL) return false;
if (config.proxies.empty()) {
LOG("WARNING: no proxies configured!");
} else if (config.mode == config_t::MODE_CHAIN) {
LOG("Will use at least %u proxies of %zu", config.min_proxies, config.proxies.size());
} else {
LOG("Will use at least %u proxies out of %zu", config.min_proxies, config.proxies.size());
}
return true;
}