📄 util.c
字号:
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2008, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/* $Id$ */
const char util_c_id[] = "$Id$";
/**
* \file util.c
* \brief Common functions for strings, IO, network, data structures,
* process control.
**/
/* This is required on rh7 to make strptime not complain.
*/
#define _GNU_SOURCE
#include "orconfig.h"
#include "util.h"
#include "log.h"
#include "crypto.h"
#include "torint.h"
#include "container.h"
#ifdef MS_WINDOWS
#include <io.h>
#include <direct.h>
#include <process.h>
#else
#include <dirent.h>
#include <pwd.h>
#endif
#ifdef HAVE_CTYPE_H
#include <ctype.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#ifdef HAVE_SYS_FCNTL_H
#include <sys/fcntl.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef HAVE_TIME_H
#include <time.h>
#endif
#ifdef HAVE_MALLOC_MALLOC_H
#include <malloc/malloc.h>
#endif
#ifdef HAVE_MALLOC_H
#include <malloc.h>
#endif
/* =====
* Memory management
* ===== */
#ifdef USE_DMALLOC
#undef strndup
#include <dmalloc.h>
#define DMALLOC_FN_ARGS , file, line
#if defined(HAVE_DMALLOC_STRDUP)
/* the dmalloc_strdup should be fine as defined */
#elif defined(HAVE_DMALLOC_STRNDUP)
#define dmalloc_strdup(file, line, string, xalloc_b) \
dmalloc_strndup(file, line, (string), -1, xalloc_b)
#else
#error "No dmalloc_strdup or equivalent"
#endif
#else /* not using dmalloc */
#define dmalloc_strdup(file, line, string, xalloc_b) strdup(string)
#define dmalloc_malloc(file, line, size, func_id, alignment, xalloc_b) \
malloc(size)
#define DMALLOC_FUNC_MALLOC 0
#define dmalloc_realloc(file, line, old_pnt, new_size, func_id, xalloc_b) \
realloc((old_pnt), (new_size))
#define DMALLOC_FUNC_REALLOC 0
#define DMALLOC_FN_ARGS
#endif
/** Allocate a chunk of <b>size</b> bytes of memory, and return a pointer to
* result. On error, log and terminate the process. (Same as malloc(size),
* but never returns NULL.)
*
* <b>file</b> and <b>line</b> are used if dmalloc is enabled, and
* ignored otherwise.
*/
void *
_tor_malloc(size_t size DMALLOC_PARAMS)
{
void *result;
#ifndef MALLOC_ZERO_WORKS
/* Some libcs don't do the right thing on size==0. Override them. */
if (size==0) {
size=1;
}
#endif
result = dmalloc_malloc(file, line, size, DMALLOC_FUNC_MALLOC, 0, 0);
if (PREDICT_UNLIKELY(result == NULL)) {
log_err(LD_MM,"Out of memory on malloc(). Dying.");
/* If these functions die within a worker process, they won't call
* spawn_exit, but that's ok, since the parent will run out of memory soon
* anyway. */
exit(1);
}
return result;
}
/** Allocate a chunk of <b>size</b> bytes of memory, fill the memory with
* zero bytes, and return a pointer to the result. Log and terminate
* the process on error. (Same as calloc(size,1), but never returns NULL.)
*/
void *
_tor_malloc_zero(size_t size DMALLOC_PARAMS)
{
void *result = _tor_malloc(size DMALLOC_FN_ARGS);
memset(result, 0, size);
return result;
}
/** Change the size of the memory block pointed to by <b>ptr</b> to <b>size</b>
* bytes long; return the new memory block. On error, log and
* terminate. (Like realloc(ptr,size), but never returns NULL.)
*/
void *
_tor_realloc(void *ptr, size_t size DMALLOC_PARAMS)
{
void *result;
result = dmalloc_realloc(file, line, ptr, size, DMALLOC_FUNC_REALLOC, 0);
if (PREDICT_UNLIKELY(result == NULL)) {
log_err(LD_MM,"Out of memory on realloc(). Dying.");
exit(1);
}
return result;
}
/** Return a newly allocated copy of the NUL-terminated string s. On
* error, log and terminate. (Like strdup(s), but never returns
* NULL.)
*/
char *
_tor_strdup(const char *s DMALLOC_PARAMS)
{
char *dup;
tor_assert(s);
dup = dmalloc_strdup(file, line, s, 0);
if (PREDICT_UNLIKELY(dup == NULL)) {
log_err(LD_MM,"Out of memory on strdup(). Dying.");
exit(1);
}
return dup;
}
/** Allocate and return a new string containing the first <b>n</b>
* characters of <b>s</b>. If <b>s</b> is longer than <b>n</b>
* characters, only the first <b>n</b> are copied. The result is
* always NUL-terminated. (Like strndup(s,n), but never returns
* NULL.)
*/
char *
_tor_strndup(const char *s, size_t n DMALLOC_PARAMS)
{
char *dup;
tor_assert(s);
dup = _tor_malloc((n+1) DMALLOC_FN_ARGS);
/* Performance note: Ordinarily we prefer strlcpy to strncpy. But
* this function gets called a whole lot, and platform strncpy is
* much faster than strlcpy when strlen(s) is much longer than n.
*/
strncpy(dup, s, n);
dup[n]='\0';
return dup;
}
/** Allocate a chunk of <b>len</b> bytes, with the same contents starting at
* <b>mem</b>. */
void *
_tor_memdup(const void *mem, size_t len DMALLOC_PARAMS)
{
char *dup;
tor_assert(mem);
dup = _tor_malloc(len DMALLOC_FN_ARGS);
memcpy(dup, mem, len);
return dup;
}
/** Helper for places that need to take a function pointer to the right
* spelling of "free()". */
void
_tor_free(void *mem)
{
tor_free(mem);
}
#if defined(HAVE_MALLOC_GOOD_SIZE) && !defined(HAVE_MALLOC_GOOD_SIZE_PROTOTYPE)
/* Some version of Mac OSX have malloc_good_size in their libc, but not
* actually defined in malloc/malloc.h. We detect this and work around it by
* prototyping.
*/
extern size_t malloc_good_size(size_t size);
#endif
/** Allocate and return a chunk of memory of size at least *<b>size</p>, using
* the same resources we would use to malloc *<b>sizep</b>. Set *<b>sizep</b>
* to the number of usable bytes in the chunk of memory. */
void *
_tor_malloc_roundup(size_t *sizep DMALLOC_PARAMS)
{
#ifdef HAVE_MALLOC_GOOD_SIZE
*sizep = malloc_good_size(*sizep);
return _tor_malloc(*sizep DMALLOC_FN_ARGS);
#elif defined(HAVE_MALLOC_USABLE_SIZE) && !defined(USE_DMALLOC)
void *result = _tor_malloc(*sizep DMALLOC_FN_ARGS);
*sizep = malloc_usable_size(result);
return result;
#else
return _tor_malloc(*sizep DMALLOC_FN_ARGS);
#endif
}
/** Call the platform malloc info function, and dump the results to the log at
* level <b>severity</b>. If no such function exists, do nothing. */
void
tor_log_mallinfo(int severity)
{
#ifdef HAVE_MALLINFO
struct mallinfo mi;
memset(&mi, 0, sizeof(mi));
mi = mallinfo();
log(severity, LD_MM,
"mallinfo() said: arena=%d, ordblks=%d, smblks=%d, hblks=%d, "
"hblkhd=%d, usmblks=%d, fsmblks=%d, uordblks=%d, fordblks=%d, "
"keepcost=%d",
mi.arena, mi.ordblks, mi.smblks, mi.hblks,
mi.hblkhd, mi.usmblks, mi.fsmblks, mi.uordblks, mi.fordblks,
mi.keepcost);
#else
(void)severity;
#endif
#ifdef USE_DMALLOC
dmalloc_log_changed(0, /* Since the program started. */
1, /* Log info about non-freed pointers. */
0, /* Do not log info about freed pointers. */
0 /* Do not log individual pointers. */
);
#endif
}
/* =====
* Math
* ===== */
/** Returns floor(log2(u64)). If u64 is 0, (incorrectly) returns 0. */
int
tor_log2(uint64_t u64)
{
int r = 0;
if (u64 >= (U64_LITERAL(1)<<32)) {
u64 >>= 32;
r = 32;
}
if (u64 >= (U64_LITERAL(1)<<16)) {
u64 >>= 16;
r += 16;
}
if (u64 >= (U64_LITERAL(1)<<8)) {
u64 >>= 8;
r += 8;
}
if (u64 >= (U64_LITERAL(1)<<4)) {
u64 >>= 4;
r += 4;
}
if (u64 >= (U64_LITERAL(1)<<2)) {
u64 >>= 2;
r += 2;
}
if (u64 >= (U64_LITERAL(1)<<1)) {
u64 >>= 1;
r += 1;
}
return r;
}
/** Return the power of 2 closest to <b>u64</b>. */
uint64_t
round_to_power_of_2(uint64_t u64)
{
int lg2 = tor_log2(u64);
uint64_t low = U64_LITERAL(1) << lg2, high = U64_LITERAL(1) << (lg2+1);
if (high - u64 < u64 - low)
return high;
else
return low;
}
/* =====
* String manipulation
* ===== */
/** Remove from the string <b>s</b> every character which appears in
* <b>strip</b>. */
void
tor_strstrip(char *s, const char *strip)
{
char *read = s;
while (*read) {
if (strchr(strip, *read)) {
++read;
} else {
*s++ = *read++;
}
}
*s = '\0';
}
/** Return a pointer to a NUL-terminated hexadecimal string encoding
* the first <b>fromlen</b> bytes of <b>from</b>. (fromlen must be \<= 32.) The
* result does not need to be deallocated, but repeated calls to
* hex_str will trash old results.
*/
const char *
hex_str(const char *from, size_t fromlen)
{
static char buf[65];
if (fromlen>(sizeof(buf)-1)/2)
fromlen = (sizeof(buf)-1)/2;
base16_encode(buf,sizeof(buf),from,fromlen);
return buf;
}
/** Convert all alphabetic characters in the nul-terminated string <b>s</b> to
* lowercase. */
void
tor_strlower(char *s)
{
while (*s) {
*s = TOR_TOLOWER(*s);
++s;
}
}
/** Convert all alphabetic characters in the nul-terminated string <b>s</b> to
* lowercase. */
void
tor_strupper(char *s)
{
while (*s) {
*s = TOR_TOUPPER(*s);
++s;
}
}
/** Return 1 if every character in <b>s</b> is printable, else return 0.
*/
int
tor_strisprint(const char *s)
{
while (*s) {
if (!TOR_ISPRINT(*s))
return 0;
s++;
}
return 1;
}
/** Return 1 if no character in <b>s</b> is uppercase, else return 0.
*/
int
tor_strisnonupper(const char *s)
{
while (*s) {
if (TOR_ISUPPER(*s))
return 0;
s++;
}
return 1;
}
/** Compares the first strlen(s2) characters of s1 with s2. Returns as for
* strcmp.
*/
int
strcmpstart(const char *s1, const char *s2)
{
size_t n = strlen(s2);
return strncmp(s1, s2, n);
}
/** Compare the s1_len-byte string <b>s1</b> with <b>s2</b>,
* without depending on a terminating nul in s1. Sorting order is first by
* length, then lexically; return values are as for strcmp.
*/
int
strcmp_len(const char *s1, const char *s2, size_t s1_len)
{
size_t s2_len = strlen(s2);
if (s1_len < s2_len)
return -1;
if (s1_len > s2_len)
return 1;
return memcmp(s1, s2, s2_len);
}
/** Compares the first strlen(s2) characters of s1 with s2. Returns as for
* strcasecmp.
*/
int
strcasecmpstart(const char *s1, const char *s2)
{
size_t n = strlen(s2);
return strncasecmp(s1, s2, n);
}
/** Compares the last strlen(s2) characters of s1 with s2. Returns as for
* strcmp.
*/
int
strcmpend(const char *s1, const char *s2)
{
size_t n1 = strlen(s1), n2 = strlen(s2);
if (n2>n1)
return strcmp(s1,s2);
else
return strncmp(s1+(n1-n2), s2, n2);
}
/** Compares the last strlen(s2) characters of s1 with s2. Returns as for
* strcasecmp.
*/
int
strcasecmpend(const char *s1, const char *s2)
{
size_t n1 = strlen(s1), n2 = strlen(s2);
if (n2>n1) /* then they can't be the same; figure out which is bigger */
return strcasecmp(s1,s2);
else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -