summaryrefslogtreecommitdiff
path: root/src/common/compat.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/compat.c')
-rw-r--r--src/common/compat.c216
1 files changed, 127 insertions, 89 deletions
diff --git a/src/common/compat.c b/src/common/compat.c
index 30bde3d1ca..d40e5036ff 100644
--- a/src/common/compat.c
+++ b/src/common/compat.c
@@ -123,16 +123,24 @@
int
tor_open_cloexec(const char *path, int flags, unsigned mode)
{
+ int fd;
#ifdef O_CLOEXEC
- return open(path, flags|O_CLOEXEC, mode);
-#else
- int fd = open(path, flags, mode);
+ fd = open(path, flags|O_CLOEXEC, mode);
+ if (fd >= 0)
+ return fd;
+ /* If we got an error, see if it is EINVAL. EINVAL might indicate that,
+ * even though we were built on a system with O_CLOEXEC support, we
+ * are running on one without. */
+ if (errno != EINVAL)
+ return -1;
+#endif
+
+ fd = open(path, flags, mode);
#ifdef FD_CLOEXEC
if (fd >= 0)
fcntl(fd, F_SETFD, FD_CLOEXEC);
#endif
return fd;
-#endif
}
/** DOCDOC */
@@ -546,25 +554,43 @@ const char TOR_TOLOWER_TABLE[256] = {
240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,
};
+/** Helper for tor_strtok_r_impl: Advances cp past all characters in
+ * <b>sep</b>, and returns its new value. */
+static char *
+strtok_helper(char *cp, const char *sep)
+{
+ if (sep[1]) {
+ while (*cp && strchr(sep, *cp))
+ ++cp;
+ } else {
+ while (*cp && *cp == *sep)
+ ++cp;
+ }
+ return cp;
+}
+
/** Implementation of strtok_r for platforms whose coders haven't figured out
* how to write one. Hey guys! You can use this code here for free! */
char *
tor_strtok_r_impl(char *str, const char *sep, char **lasts)
{
char *cp, *start;
- if (str)
+ tor_assert(*sep);
+ if (str) {
+ str = strtok_helper(str, sep);
+ if (!*str)
+ return NULL;
start = cp = *lasts = str;
- else if (!*lasts)
+ } else if (!*lasts || !**lasts) {
return NULL;
- else
+ } else {
start = cp = *lasts;
+ }
- tor_assert(*sep);
if (sep[1]) {
while (*cp && !strchr(sep, *cp))
++cp;
} else {
- tor_assert(strlen(sep) == 1);
cp = strchr(cp, *sep);
}
@@ -572,7 +598,7 @@ tor_strtok_r_impl(char *str, const char *sep, char **lasts)
*lasts = NULL;
} else {
*cp++ = '\0';
- *lasts = cp;
+ *lasts = strtok_helper(cp, sep);
}
return start;
}
@@ -968,19 +994,31 @@ tor_open_socket(int domain, int type, int protocol)
{
tor_socket_t s;
#ifdef SOCK_CLOEXEC
-#define LINUX_CLOEXEC_OPEN_SOCKET
- type |= SOCK_CLOEXEC;
-#endif
+ s = socket(domain, type|SOCK_CLOEXEC, protocol);
+ if (SOCKET_OK(s))
+ goto socket_ok;
+ /* If we got an error, see if it is EINVAL. EINVAL might indicate that,
+ * even though we were built on a system with SOCK_CLOEXEC support, we
+ * are running on one without. */
+ if (errno != EINVAL)
+ return s;
+#endif /* SOCK_CLOEXEC */
+
s = socket(domain, type, protocol);
- if (SOCKET_OK(s)) {
-#if !defined(LINUX_CLOEXEC_OPEN_SOCKET) && defined(FD_CLOEXEC)
- fcntl(s, F_SETFD, FD_CLOEXEC);
+ if (! SOCKET_OK(s))
+ return s;
+
+#if defined(FD_CLOEXEC)
+ fcntl(s, F_SETFD, FD_CLOEXEC);
#endif
- socket_accounting_lock();
- ++n_sockets_open;
- mark_socket_open(s);
- socket_accounting_unlock();
- }
+
+ goto socket_ok; /* So that socket_ok will not be unused. */
+
+ socket_ok:
+ socket_accounting_lock();
+ ++n_sockets_open;
+ mark_socket_open(s);
+ socket_accounting_unlock();
return s;
}
@@ -990,20 +1028,32 @@ tor_accept_socket(tor_socket_t sockfd, struct sockaddr *addr, socklen_t *len)
{
tor_socket_t s;
#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC)
-#define LINUX_CLOEXEC_ACCEPT
s = accept4(sockfd, addr, len, SOCK_CLOEXEC);
-#else
- s = accept(sockfd, addr, len);
+ if (SOCKET_OK(s))
+ goto socket_ok;
+ /* If we got an error, see if it is ENOSYS. ENOSYS indicates that,
+ * even though we were built on a system with accept4 support, we
+ * are running on one without. Also, check for EINVAL, which indicates that
+ * we are missing SOCK_CLOEXEC support. */
+ if (errno != EINVAL && errno != ENOSYS)
+ return s;
#endif
- if (SOCKET_OK(s)) {
-#if !defined(LINUX_CLOEXEC_ACCEPT) && defined(FD_CLOEXEC)
- fcntl(s, F_SETFD, FD_CLOEXEC);
+
+ s = accept(sockfd, addr, len);
+ if (!SOCKET_OK(s))
+ return s;
+
+#if defined(FD_CLOEXEC)
+ fcntl(s, F_SETFD, FD_CLOEXEC);
#endif
- socket_accounting_lock();
- ++n_sockets_open;
- mark_socket_open(s);
- socket_accounting_unlock();
- }
+
+ goto socket_ok; /* So that socket_ok will not be unused. */
+
+ socket_ok:
+ socket_accounting_lock();
+ ++n_sockets_open;
+ mark_socket_open(s);
+ socket_accounting_unlock();
return s;
}
@@ -1054,29 +1104,43 @@ tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2])
//don't use win32 socketpairs (they are always bad)
#if defined(HAVE_SOCKETPAIR) && !defined(_WIN32)
int r;
+
#ifdef SOCK_CLOEXEC
- type |= SOCK_CLOEXEC;
+ r = socketpair(family, type|SOCK_CLOEXEC, protocol, fd);
+ if (r == 0)
+ goto sockets_ok;
+ /* If we got an error, see if it is EINVAL. EINVAL might indicate that,
+ * even though we were built on a system with SOCK_CLOEXEC support, we
+ * are running on one without. */
+ if (errno != EINVAL)
+ return -errno;
#endif
+
r = socketpair(family, type, protocol, fd);
- if (r == 0) {
-#if !defined(SOCK_CLOEXEC) && defined(FD_CLOEXEC)
- if (SOCKET_OK(fd[0]))
- fcntl(fd[0], F_SETFD, FD_CLOEXEC);
- if (SOCKET_OK(fd[1]))
- fcntl(fd[1], F_SETFD, FD_CLOEXEC);
-#endif
- socket_accounting_lock();
- if (SOCKET_OK(fd[0])) {
- ++n_sockets_open;
- mark_socket_open(fd[0]);
- }
- if (SOCKET_OK(fd[1])) {
- ++n_sockets_open;
- mark_socket_open(fd[1]);
- }
- socket_accounting_unlock();
+ if (r < 0)
+ return -errno;
+
+#if defined(FD_CLOEXEC)
+ if (SOCKET_OK(fd[0]))
+ fcntl(fd[0], F_SETFD, FD_CLOEXEC);
+ if (SOCKET_OK(fd[1]))
+ fcntl(fd[1], F_SETFD, FD_CLOEXEC);
+#endif
+ goto sockets_ok; /* So that sockets_ok will not be unused. */
+
+ sockets_ok:
+ socket_accounting_lock();
+ if (SOCKET_OK(fd[0])) {
+ ++n_sockets_open;
+ mark_socket_open(fd[0]);
+ }
+ if (SOCKET_OK(fd[1])) {
+ ++n_sockets_open;
+ mark_socket_open(fd[1]);
}
- return r < 0 ? -errno : r;
+ socket_accounting_unlock();
+
+ return 0;
#else
/* This socketpair does not work when localhost is down. So
* it's really not the same thing at all. But it's close enough
@@ -1667,7 +1731,7 @@ make_path_absolute(char *fname)
}
#ifndef HAVE__NSGETENVIRON
-#ifndef HAVE_EXTERN_ENVIRON_DECLARED__
+#ifndef HAVE_EXTERN_ENVIRON_DECLARED
/* Some platforms declare environ under some circumstances, others don't. */
extern char **environ;
#endif
@@ -1966,8 +2030,7 @@ get_uname(void)
#ifdef HAVE_UNAME
if (uname(&u) != -1) {
/* (Linux says 0 is success, Solaris says 1 is success) */
- tor_snprintf(uname_result, sizeof(uname_result), "%s %s",
- u.sysname, u.machine);
+ strlcpy(uname_result, u.sysname, sizeof(uname_result));
} else
#endif
{
@@ -1975,8 +2038,6 @@ get_uname(void)
OSVERSIONINFOEX info;
int i;
const char *plat = NULL;
- const char *extra = NULL;
- char acsd[MAX_PATH] = {0};
static struct {
unsigned major; unsigned minor; const char *version;
} win_version_table[] = {
@@ -2001,20 +2062,11 @@ get_uname(void)
uname_result_is_set = 1;
return uname_result;
}
-#ifdef UNICODE
- wcstombs(acsd, info.szCSDVersion, MAX_PATH);
-#else
- strlcpy(acsd, info.szCSDVersion, sizeof(acsd));
-#endif
if (info.dwMajorVersion == 4 && info.dwMinorVersion == 0) {
if (info.dwPlatformId == VER_PLATFORM_WIN32_NT)
plat = "Windows NT 4.0";
else
plat = "Windows 95";
- if (acsd[1] == 'B')
- extra = "OSR2 (B)";
- else if (acsd[1] == 'C')
- extra = "OSR2 (C)";
} else {
for (i=0; win_version_table[i].major>0; ++i) {
if (win_version_table[i].major == info.dwMajorVersion &&
@@ -2024,39 +2076,25 @@ get_uname(void)
}
}
}
- if (plat && !strcmp(plat, "Windows 98")) {
- if (acsd[1] == 'A')
- extra = "SE (A)";
- else if (acsd[1] == 'B')
- extra = "SE (B)";
- }
if (plat) {
- if (!extra)
- extra = acsd;
- tor_snprintf(uname_result, sizeof(uname_result), "%s %s",
- plat, extra);
+ strlcpy(uname_result, plat, sizeof(uname_result));
} else {
if (info.dwMajorVersion > 6 ||
(info.dwMajorVersion==6 && info.dwMinorVersion>2))
tor_snprintf(uname_result, sizeof(uname_result),
- "Very recent version of Windows [major=%d,minor=%d] %s",
- (int)info.dwMajorVersion,(int)info.dwMinorVersion,
- acsd);
+ "Very recent version of Windows [major=%d,minor=%d]",
+ (int)info.dwMajorVersion,(int)info.dwMinorVersion);
else
tor_snprintf(uname_result, sizeof(uname_result),
- "Unrecognized version of Windows [major=%d,minor=%d] %s",
- (int)info.dwMajorVersion,(int)info.dwMinorVersion,
- acsd);
+ "Unrecognized version of Windows [major=%d,minor=%d]",
+ (int)info.dwMajorVersion,(int)info.dwMinorVersion);
}
#if !defined (WINCE)
-#ifdef VER_SUITE_BACKOFFICE
- if (info.wProductType == VER_NT_DOMAIN_CONTROLLER) {
- strlcat(uname_result, " [domain controller]", sizeof(uname_result));
- } else if (info.wProductType == VER_NT_SERVER) {
- strlcat(uname_result, " [server]", sizeof(uname_result));
- } else if (info.wProductType == VER_NT_WORKSTATION) {
- strlcat(uname_result, " [workstation]", sizeof(uname_result));
- }
+#ifdef VER_NT_SERVER
+ if (info.wProductType == VER_NT_SERVER ||
+ info.wProductType == VER_NT_DOMAIN_CONTROLLER) {
+ strlcat(uname_result, " [server]", sizeof(uname_result));
+ }
#endif
#endif
#else