text: // Copyright 2009 the V8 project authors. 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 Google Inc. 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.
  
  // Platform specific code for POSIX goes here. This is not a platform on its
  // own but contains the parts which are the same across POSIX platforms Linux,
  // Mac OS, FreeBSD and OpenBSD.
  
  #include <unistd.h>
  #include <errno.h>
  #include <time.h>
  
  #include <sys/socket.h>
  #include <sys/resource.h>
  #include <sys/time.h>
  #include <sys/types.h>
  
  #include <arpa/inet.h>
  #include <netinet/in.h>
  #include <netdb.h>
  
  #if defined(ANDROID)
  #define LOG_TAG "v8"
  #include <utils/Log.h>  // LOG_PRI_VA
  #endif
  
  #include "v8.h"
  
  #include "platform.h"
  
  namespace v8 {
  namespace internal {
  
  // ----------------------------------------------------------------------------
  // Math functions
  
  double modulo(double x, double y) {
    return fmod(x, y);
  }
  
  // ----------------------------------------------------------------------------
  // POSIX date/time support.
  //
  
  int OS::GetUserTime(uint32_t* secs,  uint32_t* usecs) {
    struct rusage usage;
  
    if (getrusage(RUSAGE_SELF, &usage) < 0) return -1;
    *secs = usage.ru_utime.tv_sec;
    *usecs = usage.ru_utime.tv_usec;
    return 0;
  }
  
  
  double OS::TimeCurrentMillis() {
    struct timeval tv;
    if (gettimeofday(&tv, NULL) < 0) return 0.0;
    return (static_cast<double>(tv.tv_sec) * 1000) +
           (static_cast<double>(tv.tv_usec) / 1000);
  }
  
  
  int64_t OS::Ticks() {
    // gettimeofday has microsecond resolution.
    struct timeval tv;
    if (gettimeofday(&tv, NULL) < 0)
      return 0;
    return (static_cast<int64_t>(tv.tv_sec) * 1000000) + tv.tv_usec;
  }
  
  
  double OS::DaylightSavingsOffset(double time) {
    if (isnan(time)) return nan_value();
    time_t tv = static_cast<time_t>(floor(time/msPerSecond));
    struct tm* t = localtime(&tv);
    if (NULL == t) return nan_value();
    return t->tm_isdst > 0 ? 3600 * msPerSecond : 0;
  }
  
  
  // ----------------------------------------------------------------------------
  // POSIX stdio support.
  //
  
  FILE* OS::FOpen(const char* path, const char* mode) {
    return fopen(path, mode);
  }
  
  
  const char* OS::LogFileOpenMode = "w";
  
  
  void OS::Print(const char* format, ...) {
    va_list args;
    va_start(args, format);
    VPrint(format, args);
    va_end(args);
  }
  
  
  void OS::VPrint(const char* format, va_list args) {
  #if defined(ANDROID)
    LOG_PRI_VA(ANDROID_LOG_INFO, LOG_TAG, format, args);
  #else
    vprintf(format, args);
  #endif
  }
  
  
  void OS::PrintError(const char* format, ...) {
    va_list args;
    va_start(args, format);
    VPrintError(format, args);
    va_end(args);
  }
  
  
  void OS::VPrintError(const char* format, va_list args) {
  #if defined(ANDROID)
    LOG_PRI_VA(ANDROID_LOG_ERROR, LOG_TAG, format, args);
  #else
    vfprintf(stderr, format, args);
  #endif
  }
  
  
  int OS::SNPrintF(Vector<char> str, const char* format, ...) {
    va_list args;
    va_start(args, format);
    int result = VSNPrintF(str, format, args);
    va_end(args);
    return result;
  }
  
  
  int OS::VSNPrintF(Vector<char> str,
                    const char* format,
                    va_list args) {
    int n = vsnprintf(str.start(), str.length(), format, args);
    if (n < 0 || n >= str.length()) {
      str[str.length() - 1] = '\0';
      return -1;
    } else {
      return n;
    }
  }
  
  
  // ----------------------------------------------------------------------------
  // POSIX string support.
  //
  
  char* OS::StrChr(char* str, int c) {
    return strchr(str, c);
  }
  
  
  void OS::StrNCpy(Vector<char> dest, const char* src, size_t n) {
    strncpy(dest.start(), src, n);
  }
  
  
  // ----------------------------------------------------------------------------
  // POSIX socket support.
  //
  
  class POSIXSocket : public Socket {
   public:
    explicit POSIXSocket() {
      // Create the socket.
      socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    }
    explicit POSIXSocket(int socket): socket_(socket) { }
    virtual ~POSIXSocket() { Shutdown(); }
  
    // Server initialization.
    bool Bind(const int port);
    bool Listen(int backlog) const;
    Socket* Accept() const;
  
    // Client initialization.
    bool Connect(const char* host, const char* port);
  
    // Shutdown socket for both read and write.
    bool Shutdown();
  
    // Data Transimission
    int Send(const char* data, int len) const;
    int Receive(char* data, int len) const;
  
    bool SetReuseAddress(bool reuse_address);
  
    bool IsValid() const { return socket_ != -1; }
  
   private:
    int socket_;
  };
  
  
  bool POSIXSocket::Bind(const int port) {
    if (!IsValid())  {
      return false;
    }
  
    sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
    addr.sin_port = htons(port);
    int status = bind(socket_,
                      reinterpret_cast<struct sockaddr *>(&addr),
                      sizeof(addr));
    return status == 0;
  }
  
  
  bool POSIXSocket::Listen(int backlog) const {
    if (!IsValid()) {
      return false;
    }
  
    int status = listen(socket_, backlog);
    return status == 0;
  }
  
  
  Socket* POSIXSocket::Accept() const {
    if (!IsValid()) {
      return NULL;
    }
  
    int socket = accept(socket_, NULL, NULL);
    if (socket == -1) {
      return NULL;
    } else {
      return new POSIXSocket(socket);
    }
  }
  
  
  bool POSIXSocket::Connect(const char* host, const char* port) {
    if (!IsValid()) {
      return false;
    }
  
    // Lookup host and port.
    struct addrinfo *result = NULL;
    struct addrinfo hints;
    memset(&hints, 0, sizeof(addrinfo));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    int status = getaddrinfo(host, port, &hints, &result);
    if (status != 0) {
      return false;
    }
  
    // Connect.
    status = connect(socket_, result->ai_addr, result->ai_addrlen);
    freeaddrinfo(result);
    return status == 0;
  }
  
  
  bool POSIXSocket::Shutdown() {
    if (IsValid()) {
      // Shutdown socket for both read and write.
      int status = shutdown(socket_, SHUT_RDWR);
      close(socket_);
      socket_ = -1;
      return status == 0;
    }
    return true;
  }
  
  
  int POSIXSocket::Send(const char* data, int len) const {
    int status = send(socket_, data, len, 0);
    return status;
  }
  
  
  int POSIXSocket::Receive(char* data, int len) const {
    int status = recv(socket_, data, len, 0);
    return status;
  }
  
  
  bool POSIXSocket::SetReuseAddress(bool reuse_address) {
    int on = reuse_address ? 1 : 0;
    int status = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
    return status == 0;
  }
  
  
  bool Socket::Setup() {
    // Nothing to do on POSIX.
    return true;
  }
  
  
  int Socket::LastError() {
    return errno;
  }
  
  
  uint16_t Socket::HToN(uint16_t value) {
    return htons(value);
  }
  
  
  uint16_t Socket::NToH(uint16_t value) {
    return ntohs(value);
  }
  
  
  uint32_t Socket::HToN(uint32_t value) {
    return htonl(value);
  }
  
  
  uint32_t Socket::NToH(uint32_t value) {
    return ntohl(value);
  }
  
  
  Socket* OS::CreateSocket() {
    return new POSIXSocket();
  }
  
  
  } }  // namespace v8::internal
  