/*
 *  Copyright 2012 The WebRTC Project Authors. All rights reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include <fstream>
#include <iostream>
#include <map>
#include <string>
#include <utility>

#include "absl/strings/string_view.h"
#include "examples/turnserver/read_auth_file.h"
#include "p2p/base/basic_packet_socket_factory.h"
#include "p2p/base/port_interface.h"
#include "p2p/test/turn_server.h"
#include "rtc_base/async_udp_socket.h"
#include "rtc_base/ip_address.h"
#include "rtc_base/physical_socket_server.h"
#include "rtc_base/socket_address.h"
#include "rtc_base/thread.h"

namespace {
const char kSoftware[] = "libjingle TurnServer";

class TurnFileAuth : public webrtc::TurnAuthInterface {
 public:
  explicit TurnFileAuth(std::map<std::string, std::string> name_to_key)
      : name_to_key_(std::move(name_to_key)) {}

  virtual bool GetKey(absl::string_view username,
                      absl::string_view realm,
                      std::string* key) {
    // File is stored as lines of <username>=<HA1>.
    // Generate HA1 via "echo -n "<username>:<realm>:<password>" | md5sum"
    auto it = name_to_key_.find(std::string(username));
    if (it == name_to_key_.end())
      return false;
    *key = it->second;
    return true;
  }

 private:
  const std::map<std::string, std::string> name_to_key_;
};

}  // namespace

int main(int argc, char* argv[]) {
  if (argc != 5) {
    std::cerr << "usage: turnserver int-addr ext-ip realm auth-file"
              << std::endl;
    return 1;
  }

  webrtc::SocketAddress int_addr;
  if (!int_addr.FromString(argv[1])) {
    std::cerr << "Unable to parse IP address: " << argv[1] << std::endl;
    return 1;
  }

  webrtc::IPAddress ext_addr;
  if (!webrtc::IPFromString(argv[2], &ext_addr)) {
    std::cerr << "Unable to parse IP address: " << argv[2] << std::endl;
    return 1;
  }

  webrtc::PhysicalSocketServer socket_server;
  webrtc::AutoSocketServerThread main(&socket_server);
  webrtc::AsyncUDPSocket* int_socket =
      webrtc::AsyncUDPSocket::Create(&socket_server, int_addr);
  if (!int_socket) {
    std::cerr << "Failed to create a UDP socket bound at" << int_addr.ToString()
              << std::endl;
    return 1;
  }

  webrtc::TurnServer server(&main);
  std::fstream auth_file(argv[4], std::fstream::in);

  TurnFileAuth auth(auth_file.is_open()
                        ? webrtc_examples::ReadAuthFile(&auth_file)
                        : std::map<std::string, std::string>());
  server.set_realm(argv[3]);
  server.set_software(kSoftware);
  server.set_auth_hook(&auth);
  server.AddInternalSocket(int_socket, webrtc::PROTO_UDP);
  server.SetExternalSocketFactory(
      new webrtc::BasicPacketSocketFactory(&socket_server),
      webrtc::SocketAddress(ext_addr, 0));

  std::cout << "Listening internally at " << int_addr.ToString() << std::endl;

  main.Run();
  return 0;
}
