1 Star 0 Fork 0

MCai/polipo

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
util.c 17.77 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838
/*
Copyright (c) 2003-2007 by Juliusz Chroboczek
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "polipo.h"
/* Note that this is different from GNU's strndup(3). */
char *
strdup_n(const char *restrict buf, int n)
{
char *s;
s = malloc(n + 1);
if(s == NULL)
return NULL;
memcpy(s, buf, n);
s[n] = '\0';
return s;
}
int
snnprintf(char *restrict buf, int n, int len, const char *format, ...)
{
va_list args;
int rc;
va_start(args, format);
rc = snnvprintf(buf, n, len, format, args);
va_end(args);
return rc;
}
int
snnvprintf(char *restrict buf, int n, int len, const char *format, va_list args)
{
int rc = -1;
va_list args_copy;
if(n < 0) return -2;
if(n < len) {
va_copy(args_copy, args);
rc = vsnprintf(buf + n, len - n, format, args_copy);
va_end(args_copy);
}
if(rc >= 0 && n + rc <= len)
return n + rc;
else
return -1;
}
int
snnprint_n(char *restrict buf, int n, int len, const char *s, int slen)
{
int i = 0;
if(n < 0) return -2;
while(i < slen && n < len)
buf[n++] = s[i++];
if(n < len)
return n;
else
return -1;
}
int
letter(char c)
{
if(c >= 'A' && c <= 'Z') return 1;
if(c >= 'a' && c <= 'z') return 1;
return 0;
}
int
digit(char c)
{
if(c >= '0' && c <= '9')
return 1;
return 0;
}
char
lwr(char a)
{
if(a >= 'A' && a <= 'Z')
return a | 0x20;
else
return a;
}
char *
lwrcpy(char *restrict dst, const char *restrict src, int n)
{
int i;
for(i = 0; i < n; i++)
dst[i] = lwr(src[i]);
return dst;
}
int
lwrcmp(const char *as, const char *bs, int n)
{
int i;
for(i = 0; i < n; i++) {
char a = lwr(as[i]), b = lwr(bs[i]);
if(a < b)
return -1;
else if(a > b)
return 1;
}
return 0;
}
int
strcasecmp_n(const char *string, const char *buf, int n)
{
int i;
i = 0;
while(string[i] != '\0' && i < n) {
char a = lwr(string[i]), b = lwr(buf[i]);
if(a < b)
return -1;
else if(a > b)
return 1;
i++;
}
if(string[i] == '\0' && i == n)
return 0;
else if(i == n)
return 1;
else
return -1;
}
int
atoi_n(const char *restrict string, int n, int len, int *value_return)
{
int i = n;
int val = 0;
if(i >= len || !digit(string[i]))
return -1;
while(i < len && digit(string[i])) {
val = val * 10 + (string[i] - '0');
i++;
}
*value_return = val;
return i;
}
int
isWhitespace(const char *string)
{
while(*string != '\0') {
if(*string == ' ' || *string == '\t')
string++;
else
return 0;
}
return 1;
}
#ifndef HAVE_MEMRCHR
void *
memrchr(const void *s, int c, size_t n)
{
const unsigned char *ss = s;
unsigned char cc = c;
size_t i;
for(i = 1; i <= n; i++)
if(ss[n - i] == cc)
return (void*)(ss + n - i);
return NULL;
}
#endif
int
h2i(char h)
{
if(h >= '0' && h <= '9')
return h - '0';
else if(h >= 'a' && h <= 'f')
return h - 'a' + 10;
else if(h >= 'A' && h <= 'F')
return h - 'A' + 10;
else
return -1;
}
char
i2h(int i)
{
if(i < 0 || i >= 16)
return '?';
if(i < 10)
return i + '0';
else
return i - 10 + 'A';
}
/* floor(log2(x)) */
int
log2_floor(int x)
{
int i, j;
assert(x > 0);
i = 0;
j = 1;
while(2 * j <= x) {
i++;
j *= 2;
}
return i;
}
/* ceil(log2(x)) */
int
log2_ceil(int x)
{
int i, j;
assert(x > 0);
i = 0;
j = 1;
while(j < x) {
i++;
j *= 2;
}
return i;
}
#ifdef HAVE_ASPRINTF
char *
vsprintf_a(const char *f, va_list args)
{
char *r;
int rc;
va_list args_copy;
va_copy(args_copy, args);
rc = vasprintf(&r, f, args_copy);
va_end(args_copy);
if(rc < 0)
return NULL;
return r;
}
#else
char*
vsprintf_a(const char *f, va_list args)
{
int n, size;
char buf[64];
char *string;
va_list args_copy;
va_copy(args_copy, args);
n = vsnprintf(buf, 64, f, args_copy);
va_end(args_copy);
if(n >= 0 && n < 64) {
return strdup_n(buf, n);
}
if(n >= 64)
size = n + 1;
else
size = 96;
while(1) {
string = malloc(size);
if(!string)
return NULL;
va_copy(args_copy, args);
n = vsnprintf(string, size, f, args_copy);
va_end(args_copy);
if(n >= 0 && n < size) {
return string;
} else if(n >= size)
size = n + 1;
else
size = size * 3 / 2;
free(string);
if(size > 16 * 1024)
return NULL;
}
/* NOTREACHED */
}
#endif
char*
sprintf_a(const char *f, ...)
{
char *s;
va_list args;
va_start(args, f);
s = vsprintf_a(f, args);
va_end(args);
return s;
}
unsigned int
hash(unsigned int seed, const void *restrict key, int key_size,
unsigned int hash_size)
{
int i;
unsigned int h;
h = seed;
for(i = 0; i < key_size; i++)
h = (h << 5) + (h >> (hash_size - 5)) +
((unsigned char*)key)[i];
return h & ((1 << hash_size) - 1);
}
char *
pstrerror(int e)
{
char *s;
static char buf[20];
switch(e) {
case EDOSHUTDOWN: s = "Immediate shutdown requested"; break;
case EDOGRACEFUL: s = "Graceful shutdown requested"; break;
case EDOTIMEOUT: s = "Timeout"; break;
case ECLIENTRESET: s = "Connection reset by client"; break;
case ESYNTAX: s = "Incorrect syntax"; break;
case EREDIRECTOR: s = "Redirector error"; break;
case EDNS_HOST_NOT_FOUND: s = "Host not found"; break;
case EDNS_NO_ADDRESS: s = "No address"; break;
case EDNS_NO_RECOVERY: s = "Permanent name server failure"; break;
case EDNS_TRY_AGAIN: s = "Temporary name server failure"; break;
case EDNS_INVALID: s = "Invalid reply from name server"; break;
case EDNS_UNSUPPORTED: s = "Unsupported DNS reply"; break;
case EDNS_FORMAT: s = "Invalid DNS query"; break;
case EDNS_REFUSED: s = "DNS query refused by server"; break;
case EDNS_CNAME_LOOP: s = "DNS CNAME loop"; break;
#ifndef NO_SOCKS
case ESOCKS_PROTOCOL: s = "SOCKS protocol error"; break;
case ESOCKS_REJECT_FAIL: s = "SOCKS request rejected or failed"; break;
case ESOCKS_REJECT_IDENTD: s = "SOCKS request rejected: "
"server couldn't connect to identd";
break;
case ESOCKS_REJECT_UID_MISMATCH: s = "SOCKS request rejected: "
"uid mismatch";
break;
case ESOCKS5_BASE: s = "SOCKS success"; break;
case ESOCKS5_BASE + 1: s = "General SOCKS server failure"; break;
case ESOCKS5_BASE + 2: s = "SOCKS connection not allowed"; break;
case ESOCKS5_BASE + 3: s = "SOCKS error: network unreachable"; break;
case ESOCKS5_BASE + 4: s = "SOCKS error: host unreachable"; break;
case ESOCKS5_BASE + 5: s = "SOCKS error: connection refused"; break;
case ESOCKS5_BASE + 6: s = "SOCKS error: TTL expired"; break;
case ESOCKS5_BASE + 7: s = "SOCKS command not supported"; break;
case ESOCKS5_BASE + 8: s = "SOCKS error: address type not supported";
break;
#endif
case EUNKNOWN: s = "Unknown error"; break;
default: s = NULL; break;
}
if(!s) s = strerror(e);
#ifdef WIN32 /*MINGW*/
if(!s) {
if(e >= WSABASEERR && e <= WSABASEERR + 2000) {
/* This should be okay, as long as the caller discards the
pointer before another error occurs. */
snprintf(buf, 20, "Winsock error %d", e);
s = buf;
}
}
#endif
if(!s) {
snprintf(buf, 20, "Unknown error %d", e);
s = buf;
}
return s;
}
/* Like mktime(3), but UTC rather than local time */
#if defined(HAVE_TIMEGM)
time_t
mktime_gmt(struct tm *tm)
{
return timegm(tm);
}
#elif defined(HAVE_MKGMTIME)
time_t
mktime_gmt(struct tm *tm)
{
return _mkgmtime(tm);
}
#elif defined(HAVE_TM_GMTOFF)
time_t
mktime_gmt(struct tm *tm)
{
time_t t;
struct tm *ltm;
t = mktime(tm);
if(t < 0)
return -1;
ltm = localtime(&t);
if(ltm == NULL)
return -1;
return t + ltm->tm_gmtoff;
}
#elif defined(HAVE_TZSET)
#ifdef HAVE_SETENV
/* Taken from the Linux timegm(3) man page. */
time_t
mktime_gmt(struct tm *tm)
{
time_t t;
char *tz;
tz = getenv("TZ");
setenv("TZ", "GMT", 1);
tzset();
t = mktime(tm);
if(tz)
setenv("TZ", tz, 1);
else
unsetenv("TZ");
tzset();
return t;
}
#else
time_t
mktime_gmt(struct tm *tm)
{
time_t t;
char *tz;
static char *old_tz = NULL;
tz = getenv("TZ");
putenv("TZ=GMT");
tzset();
t = mktime(tm);
if(old_tz)
free(old_tz);
if(tz)
old_tz = sprintf_a("TZ=%s", tz);
else
old_tz = strdup("TZ"); /* XXX - non-portable? */
if(old_tz)
putenv(old_tz);
tzset();
return t;
}
#endif
#else
#error no mktime_gmt implementation on this platform
#endif
AtomPtr
expandTilde(AtomPtr filename)
{
char *buf;
char *home;
int len;
AtomPtr ret;
if(filename == NULL || filename->length < 1 ||
filename->string[0] != '~' || filename->string[1] != '/')
return filename;
home = getenv("HOME");
if(home == NULL) {
return NULL;
}
len = strlen(home);
buf = malloc(len + 1 + 1 + filename->length - 2);
if(buf == NULL) {
do_log(L_ERROR, "Could not allocate buffer.\n");
return NULL;
}
memcpy(buf, home, len);
if(buf[len - 1] != '/')
buf[len++] = '/';
memcpy(buf + len, filename->string + 2, filename->length - 2);
len += filename->length - 2;
ret = internAtomN(buf, len);
free(buf);
if(ret != NULL)
releaseAtom(filename);
return ret;
}
#ifdef HAVE_FORK
void
do_daemonise(int noclose)
{
int rc;
fflush(stdout);
fflush(stderr);
rc = fork();
if(rc < 0) {
do_log_error(L_ERROR, errno, "Couldn't fork");
exit(1);
}
if(rc > 0)
exit(0);
if(!noclose) {
int fd;
close(0);
close(1);
close(2);
/* Leaving the default file descriptors free is not a good
idea, as it will cause library functions such as abort to
thrash the on-disk cache. */
fd = open("/dev/null", O_RDONLY);
if(fd > 0) {
dup2(fd, 0);
close(fd);
}
fd = open("/dev/null", O_WRONLY);
if(fd >= 0) {
if(fd != 1)
dup2(fd, 1);
if(fd != 2)
dup2(fd, 2);
if(fd != 1 && fd != 2)
close(fd);
}
}
rc = setsid();
if(rc < 0) {
do_log_error(L_ERROR, errno, "Couldn't create new session");
exit(1);
}
}
#elif defined(WIN32)
void
do_daemonise(int noclose)
{
do_log(L_INFO, "Detaching console");
FreeConsole();
}
#else
void
do_daemonise(int noclose)
{
do_log(L_ERROR, "Cannot daemonise on this platform");
exit(1);
}
#endif
void
writePid(char *pidfile)
{
int fd, n, rc;
char buf[16];
fd = open(pidfile, O_WRONLY | O_CREAT | O_EXCL, 0666);
if(fd < 0) {
do_log_error(L_ERROR, errno,
"Couldn't create pid file %s", pidfile);
exit(1);
}
n = snprintf(buf, 16, "%ld\n", (long)getpid());
if(n < 0 || n >= 16) {
close(fd);
unlink(pidfile);
do_log(L_ERROR, "Couldn't format pid.\n");
exit(1);
}
rc = write(fd, buf, n);
if(rc != n) {
close(fd);
unlink(pidfile);
do_log_error(L_ERROR, errno, "Couldn't write pid");
exit(1);
}
close(fd);
return;
}
static const char b64[64] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/* "/" replaced with "-" */
static const char b64fss[64] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-";
int
b64cpy(char *restrict dst, const char *restrict src, int n, int fss)
{
const char *b = fss ? b64fss: b64;
int i, j;
j = 0;
for(i = 0; i < n; i += 3) {
unsigned char a0, a1, a2;
a0 = src[i];
a1 = i < n - 1 ? src[i + 1] : 0;
a2 = i < n - 2 ? src[i + 2] : 0;
dst[j++] = b[(a0 >> 2) & 0x3F];
dst[j++] = b[((a0 << 4) & 0x30) | ((a1 >> 4) & 0x0F)];
if(i < n - 1)
dst[j++] = b[((a1 << 2) & 0x3C) | ((a2 >> 6) & 0x03)];
else
dst[j++] = '=';
if(i < n - 2)
dst[j++] = b[a2 & 0x3F];
else
dst[j++] = '=';
}
return j;
}
int
b64cmp(const char *restrict a, int an, const char *restrict b, int bn)
{
char *buf;
int r;
if(an % 4 != 0)
return -1;
if((bn + 2) / 3 != an / 4)
return -1;
buf = malloc(an);
if(buf == NULL)
return -1;
b64cpy(buf, b, bn, 0);
r = memcmp(buf, a, an);
free(buf);
return r;
}
IntListPtr
makeIntList(int size)
{
IntListPtr list;
if(size <= 0)
size = 4;
list = malloc(sizeof(IntListRec));
if(list == NULL)
return NULL;
list->ranges = malloc(size * sizeof(IntRangeRec));
if(list->ranges == NULL) {
free(list);
return NULL;
}
list->length = 0;
list->size = size;
return list;
}
void
destroyIntList(IntListPtr list)
{
free(list->ranges);
free(list);
}
int
intListMember(int n, IntListPtr list)
{
int lo = 0, hi = list->length - 1;
int mid;
while(hi >= lo) {
mid = (hi + lo) / 2;
if(list->ranges[mid].from > n)
hi = mid - 1;
else if(list->ranges[mid].to < n)
lo = mid + 1;
else
return 1;
}
return 0;
}
static int
deleteRange(IntListPtr list, int i)
{
assert(list->length > i);
if(list->length > i + 1)
memmove(list->ranges + i, list->ranges + i + 1,
(list->length - i - 1) * sizeof(IntRangeRec));
list->length--;
return 1;
}
static int
insertRange(int from, int to, IntListPtr list, int i)
{
assert(i >= 0 && i <= list->length);
assert(i == 0 || list->ranges[i - 1].to < from - 1);
assert(i == list->length || list->ranges[i].from > to + 1);
if(list->length >= list->size) {
int newsize = list->size * 2 + 1;
IntRangePtr newranges =
realloc(list->ranges, newsize * sizeof(IntRangeRec));
if(newranges == NULL)
return -1;
list->size = newsize;
list->ranges = newranges;
}
if(i < list->length)
memmove(list->ranges + i + 1, list->ranges + i,
list->length - i);
list->length++;
list->ranges[i].from = from;
list->ranges[i].to = to;
return 1;
}
static int
maybeMergeRanges(IntListPtr list, int i)
{
int rc;
while(i > 0 && list->ranges[i].from <= list->ranges[i - 1].to + 1) {
list->ranges[i - 1].from =
MIN(list->ranges[i - 1].from, list->ranges[i].from);
list->ranges[i - 1].to =
MAX(list->ranges[i - 1].to, list->ranges[i].to);
rc = deleteRange(list, i);
if(rc < 0) return -1;
i--;
}
while(i < list->length - 1 &&
list->ranges[i].to >= list->ranges[i + 1].from - 1) {
list->ranges[i + 1].from =
MIN(list->ranges[i + 1].from, list->ranges[i].from);
list->ranges[i - 1].to =
MAX(list->ranges[i + 1].to, list->ranges[i].to);
rc = deleteRange(list, i);
if(rc < 0) return -1;
}
return 1;
}
int
intListCons(int from, int to, IntListPtr list)
{
int i;
/* Don't bother with the dichotomy. */
for(i = 0; i < list->length; i++) {
if(list->ranges[i].to >= from - 1)
break;
}
if(i < list->length &&
(from >= list->ranges[i].from - 1 || to <= list->ranges[i].to + 1)) {
if(from <= list->ranges[i].from)
list->ranges[i].from = from;
if(to >= list->ranges[i].to)
list->ranges[i].to = to;
return maybeMergeRanges(list, i);
}
return insertRange(from, to, list, i);
}
/* Return the amount of physical memory on the box, -1 if unknown or
over two gigs. */
#ifdef __linux
#include <sys/sysinfo.h>
int
physicalMemory()
{
int rc;
struct sysinfo info;
rc = sysinfo(&info);
if(rc < 0)
return -1;
if(info.totalram <= 0x7fffffff / info.mem_unit)
return (int)(info.totalram * info.mem_unit);
return -1;
}
#elif defined(__FreeBSD__)
#include <sys/sysctl.h>
int
physicalMemory()
{
unsigned long membytes;
size_t len;
int res;
len = sizeof(membytes);
res = sysctlbyname("hw.physmem", &membytes, &len, NULL, 0);
if (res || membytes > INT_MAX)
return -1;
return (int)membytes;
}
#else
int
physicalMemory()
{
return -1;
}
#endif
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/mcai33/polipo.git
git@gitee.com:mcai33/polipo.git
mcai33
polipo
polipo
master

搜索帮助