diff options
Diffstat (limited to 'src/common/compat.c')
-rw-r--r-- | src/common/compat.c | 216 |
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 |