chromium/chromecast/media/audio/net/audio_socket_service.h

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

#ifndef CHROMECAST_MEDIA_AUDIO_NET_AUDIO_SOCKET_SERVICE_H_
#define CHROMECAST_MEDIA_AUDIO_NET_AUDIO_SOCKET_SERVICE_H_

#include <memory>
#include <string>

#include "base/containers/flat_map.h"
#include "base/files/file_descriptor_watcher_posix.h"
#include "base/files/scoped_file.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "net/socket/socket_descriptor.h"

namespace base {
class SequencedTaskRunner;
}  // namespace base

namespace net {
class ServerSocket;
class StreamSocket;
}  // namespace net

namespace chromecast {
namespace media {

// Listens to a server socket and passes accepted sockets to a delegate. It
// is used for creating socket connections to pass audio data between processes.
// Must be created and used on an IO thread.
class AudioSocketService {
 public:
  class Delegate {
   public:
    // Handles a newly accepted |socket|.
    virtual void HandleAcceptedSocket(
        std::unique_ptr<net::StreamSocket> socket) = 0;

   protected:
    virtual ~Delegate() = default;
  };

  // When |use_socket_descriptor| is true, AudioSocketService will receive a
  // socket descriptor from the connection created through |listen_socket_|, and
  // then use the received socket descriptor to create the real socket for
  // transferring data. This is useful when the actual client of the service is
  // not able to create a socket themselves but instead needs a brokered socket
  // descriptor (created with socketpair()) to connect.
  AudioSocketService(const std::string& endpoint,
                     int port,
                     int max_accept_loop,
                     Delegate* delegate,
                     bool use_socket_descriptor = false);
  AudioSocketService(const AudioSocketService&) = delete;
  AudioSocketService& operator=(const AudioSocketService&) = delete;
  ~AudioSocketService();

  // Starts accepting incoming connections.
  void Accept();

  // Creates a connection to an AudioSocketService instance. The |endpoint| is
  // used on systems that support Unix domain sockets; otherwise, the |port| is
  // used to make a TCP connection.
  static std::unique_ptr<net::StreamSocket> Connect(const std::string& endpoint,
                                                    int port);

 private:
  void OnAsyncAcceptComplete(int result);
  bool HandleAcceptResult(int result);

  // The following methods are implemented in audio_socket_service_{uds|tcp}.cc.
  int AcceptOne();
  void OnAcceptSuccess();
  void ReceiveFdFromSocket(int socket_fd);

  const int max_accept_loop_;
  const bool use_socket_descriptor_;
  Delegate* const delegate_;  // Not owned.

  scoped_refptr<base::SequencedTaskRunner> task_runner_;

  std::unique_ptr<net::ServerSocket> listen_socket_;
  std::unique_ptr<net::StreamSocket> accepted_socket_;
  net::SocketDescriptor accepted_descriptor_ = net::kInvalidSocket;
  base::flat_map<int /* fd */,
                 std::unique_ptr<base::FileDescriptorWatcher::Controller>>
      fd_watcher_controllers_;
  base::WeakPtrFactory<AudioSocketService> weak_factory_{this};
};

}  // namespace media
}  // namespace chromecast

#endif  // CHROMECAST_MEDIA_AUDIO_NET_AUDIO_SOCKET_SERVICE_H_