/* * Copyright (c) 2015-2017, Ieshen Zheng * Copyright (c) 2020, Nick * Copyright (c) 2020-2021, Bjorn Svensson * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Redis nor the names of its contributors may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #ifndef _WIN32 #include #include #include #include #endif #ifdef HI_HAVE_BACKTRACE #include #endif #include "hiutil.h" #include "win32.h" #ifndef _WIN32 int hi_set_blocking(int sd) { int flags; flags = fcntl(sd, F_GETFL, 0); if (flags < 0) { return flags; } return fcntl(sd, F_SETFL, flags & ~O_NONBLOCK); } int hi_set_nonblocking(int sd) { int flags; flags = fcntl(sd, F_GETFL, 0); if (flags < 0) { return flags; } return fcntl(sd, F_SETFL, flags | O_NONBLOCK); } int hi_set_reuseaddr(int sd) { int reuse; socklen_t len; reuse = 1; len = sizeof(reuse); return setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &reuse, len); } /* * Disable Nagle algorithm on TCP socket. * * This option helps to minimize transmit latency by disabling coalescing * of data to fill up a TCP segment inside the kernel. Sockets with this * option must use readv() or writev() to do data transfer in bulk and * hence avoid the overhead of small packets. */ int hi_set_tcpnodelay(int sd) { int nodelay; socklen_t len; nodelay = 1; len = sizeof(nodelay); return setsockopt(sd, IPPROTO_TCP, TCP_NODELAY, &nodelay, len); } int hi_set_linger(int sd, int timeout) { struct linger linger; socklen_t len; linger.l_onoff = 1; linger.l_linger = timeout; len = sizeof(linger); return setsockopt(sd, SOL_SOCKET, SO_LINGER, &linger, len); } int hi_set_sndbuf(int sd, int size) { socklen_t len; len = sizeof(size); return setsockopt(sd, SOL_SOCKET, SO_SNDBUF, &size, len); } int hi_set_rcvbuf(int sd, int size) { socklen_t len; len = sizeof(size); return setsockopt(sd, SOL_SOCKET, SO_RCVBUF, &size, len); } int hi_get_soerror(int sd) { int status, err; socklen_t len; err = 0; len = sizeof(err); status = getsockopt(sd, SOL_SOCKET, SO_ERROR, &err, &len); if (status == 0) { errno = err; } return status; } int hi_get_sndbuf(int sd) { int status, size; socklen_t len; size = 0; len = sizeof(size); status = getsockopt(sd, SOL_SOCKET, SO_SNDBUF, &size, &len); if (status < 0) { return status; } return size; } int hi_get_rcvbuf(int sd) { int status, size; socklen_t len; size = 0; len = sizeof(size); status = getsockopt(sd, SOL_SOCKET, SO_RCVBUF, &size, &len); if (status < 0) { return status; } return size; } #endif int _hi_atoi(uint8_t *line, size_t n) { int value; if (n == 0) { return -1; } for (value = 0; n--; line++) { if (*line < '0' || *line > '9') { return -1; } value = value * 10 + (*line - '0'); } if (value < 0) { return -1; } return value; } void _hi_itoa(uint8_t *s, int num) { uint8_t c; uint8_t sign = 0; if (s == NULL) { return; } uint32_t len, i; len = 0; if (num < 0) { sign = 1; num = abs(num); } else if (num == 0) { s[len++] = '0'; return; } while (num % 10 || num / 10) { c = num % 10 + '0'; num = num / 10; s[len + 1] = s[len]; s[len] = c; len++; } if (sign == 1) { s[len++] = '-'; } s[len] = '\0'; for (i = 0; i < len / 2; i++) { c = s[i]; s[i] = s[len - i - 1]; s[len - i - 1] = c; } } int hi_valid_port(int n) { if (n < 1 || n > UINT16_MAX) { return 0; } return 1; } int _uint_len(uint32_t num) { int n = 0; if (num == 0) { return 1; } while (num != 0) { n++; num /= 10; } return n; } void hi_stacktrace(int skip_count) { #ifdef HI_HAVE_BACKTRACE void *stack[64]; char **symbols; int size, i, j; size = backtrace(stack, 64); symbols = backtrace_symbols(stack, size); if (symbols == NULL) { return; } skip_count++; /* skip the current frame also */ for (i = skip_count, j = 0; i < size; i++, j++) { printf("[%d] %s\n", j, symbols[i]); } hi_free(symbols); #else (void)skip_count; #endif } void hi_stacktrace_fd(int fd) { #ifdef HI_HAVE_BACKTRACE void *stack[64]; int size; size = backtrace(stack, 64); backtrace_symbols_fd(stack, size, fd); #else (void)fd; #endif } void hi_assert(const char *cond, const char *file, int line, int panic) { printf("File: %s Line: %d: %s\n", file, line, cond); if (panic) { hi_stacktrace(1); abort(); } abort(); } #ifndef _WIN32 /* * Send n bytes on a blocking descriptor */ ssize_t _hi_sendn(int sd, const void *vptr, size_t n) { size_t nleft; ssize_t nsend; const char *ptr; ptr = vptr; nleft = n; while (nleft > 0) { nsend = send(sd, ptr, nleft, 0); if (nsend < 0) { if (errno == EINTR) { continue; } return nsend; } if (nsend == 0) { return -1; } nleft -= (size_t)nsend; ptr += nsend; } return (ssize_t)n; } /* * Recv n bytes from a blocking descriptor */ ssize_t _hi_recvn(int sd, void *vptr, size_t n) { size_t nleft; ssize_t nrecv; char *ptr; ptr = vptr; nleft = n; while (nleft > 0) { nrecv = recv(sd, ptr, nleft, 0); if (nrecv < 0) { if (errno == EINTR) { continue; } return nrecv; } if (nrecv == 0) { break; } nleft -= (size_t)nrecv; ptr += nrecv; } return (ssize_t)(n - nleft); } #endif /* * Return the current time in microseconds since Epoch */ int64_t hi_usec_now(void) { int64_t usec; #ifdef _WIN32 LARGE_INTEGER counter, frequency; if (!QueryPerformanceCounter(&counter) || !QueryPerformanceFrequency(&frequency)) { return -1; } usec = counter.QuadPart * 1000000 / frequency.QuadPart; #else struct timeval now; int status; status = gettimeofday(&now, NULL); if (status < 0) { return -1; } usec = (int64_t)now.tv_sec * 1000000LL + (int64_t)now.tv_usec; #endif return usec; } /* * Return the current time in milliseconds since Epoch */ int64_t hi_msec_now(void) { return hi_usec_now() / 1000LL; }