chromium/tools/android/forwarder2/socket.h

// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef TOOLS_ANDROID_FORWARDER2_SOCKET_H_
#define TOOLS_ANDROID_FORWARDER2_SOCKET_H_

#include <fcntl.h>
#include <netinet/in.h>
#include <stddef.h>
#include <sys/socket.h>
#include <sys/un.h>

#include <string>
#include <vector>

namespace forwarder2 {

// Wrapper class around unix socket api.  Can be used to create, bind or
// connect to both Unix domain sockets and TCP sockets.
// TODO(pliard): Split this class into TCPSocket and UnixDomainSocket.
class Socket {
 public:
  Socket();

  Socket(const Socket&) = delete;
  Socket& operator=(const Socket&) = delete;

  ~Socket();

  bool BindUnix(const std::string& path);
  bool BindTcp(const std::string& host, int port);
  bool ConnectUnix(const std::string& path);
  bool ConnectTcp(const std::string& host, int port);

  // Just a wrapper around unix socket shutdown(), see man 2 shutdown.
  void Shutdown();

  // Just a wrapper around unix socket close(), see man 2 close.
  void Close();
  bool IsClosed() const { return socket_ < 0; }

  int fd() const { return socket_; }

  bool Accept(Socket* new_socket);

  // Returns the port allocated to this socket or zero on error.
  int GetPort();

  // Just a wrapper around unix read() function.
  // Reads up to buffer_size, but may read less than buffer_size.
  // Returns the number of bytes read.
  int Read(void* buffer, size_t buffer_size);

  // Same as Read() but with a timeout.
  int ReadWithTimeout(void* buffer, size_t buffer_size, int timeout_secs);

  // Non-blocking version of Read() above. This must be called after a
  // successful call to select(). The socket must also be in non-blocking mode
  // before calling this method.
  int NonBlockingRead(void* buffer, size_t buffer_size);

  // Wrapper around send().
  int Write(const void* buffer, size_t count);

  // Same as NonBlockingRead() but for writing.
  int NonBlockingWrite(const void* buffer, size_t count);

  // Calls Read() multiple times until num_bytes is written to the provided
  // buffer. No bounds checking is performed.
  // Returns number of bytes read, which can be different from num_bytes in case
  // of errror.
  int ReadNumBytes(void* buffer, size_t num_bytes);

  // Same as ReadNumBytes() but with a timeout.
  int ReadNumBytesWithTimeout(void* buffer, size_t num_bytes, int timeout_secs);

  // Calls Write() multiple times until num_bytes is written. No bounds checking
  // is performed. Returns number of bytes written, which can be different from
  // num_bytes in case of errror.
  int WriteNumBytes(const void* buffer, size_t num_bytes);

  // Calls WriteNumBytes for the given std::string. Note that the null
  // terminator is not written to the socket.
  int WriteString(const std::string& buffer);

  bool has_error() const { return socket_error_; }

  // |event_fd| must be a valid pipe file descriptor created from the
  // PipeNotifier and must live (not be closed) at least as long as this socket
  // is alive.
  void AddEventFd(int event_fd);

  // Returns whether Accept() or Connect() was interrupted because the socket
  // received an external event fired through the provided fd.
  bool DidReceiveEventOnFd(int fd) const;

  bool DidReceiveEvent() const;

  static pid_t GetUnixDomainSocketProcessOwner(const std::string& path);

 private:
  enum EventType {
    READ,
    WRITE
  };

  union SockAddr {
    // IPv4 sockaddr
    sockaddr_in addr4;
    // IPv6 sockaddr
    sockaddr_in6 addr6;
    // Unix Domain sockaddr
    sockaddr_un addr_un;
  };

  struct Event {
    int fd;
    bool was_fired;
  };

  bool SetNonBlocking();

  // If |host| is empty, use localhost.
  bool InitTcpSocket(const std::string& host, int port);
  bool InitUnixSocket(const std::string& path);
  bool BindAndListen();
  bool Connect();

  bool Resolve(const std::string& host);
  bool InitSocketInternal();
  void SetSocketError();

  // Waits until a read or write i/o event has happened.
  bool WaitForEvent(EventType type, int timeout_secs);

  int socket_;
  int port_;
  bool socket_error_;

  // Family of the socket (AF_INET, AF_INET6 or PF_UNIX).
  int family_;

  SockAddr addr_;

  // Points to one of the members of the above union depending on the family.
  sockaddr* addr_ptr_;
  // Length of one of the members of the above union depending on the family.
  socklen_t addr_len_;

  // Used to listen for external events (e.g. process received a SIGTERM) while
  // blocking on I/O operations.
  std::vector<Event> events_;
};

}  // namespace forwarder

#endif  // TOOLS_ANDROID_FORWARDER2_SOCKET_H_