//
// Copyright (C) 2015 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#include "apmanager/hostapd_monitor.h"

#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>

#include <base/bind.h>
#include <base/logging.h>
#include <base/strings/stringprintf.h>
#include <shill/net/io_handler_factory_container.h>
#include <shill/net/sockets.h>

using base::Bind;
using base::Unretained;
using shill::IOHandlerFactoryContainer;
using std::string;

namespace apmanager {

// static.
#if !defined(__ANDROID__)
const char HostapdMonitor::kLocalPathFormat[] =
    "/run/apmanager/hostapd/hostapd_ctrl_%s";
#else
const char HostapdMonitor::kLocalPathFormat[] =
    "/data/misc/apmanager/hostapd/hostapd_ctrl_%s";
#endif  // __ANDROID__

const char HostapdMonitor::kHostapdCmdAttach[] = "ATTACH";
const char HostapdMonitor::kHostapdRespOk[] = "OK\n";
const char HostapdMonitor::kHostapdEventStationConnected[] = "AP-STA-CONNECTED";
const char HostapdMonitor::kHostapdEventStationDisconnected[] =
    "AP-STA-DISCONNECTED";
const int HostapdMonitor::kHostapdCtrlIfaceCheckIntervalMs = 500;
const int HostapdMonitor::kHostapdCtrlIfaceCheckMaxAttempts = 5;
const int HostapdMonitor::kHostapdAttachTimeoutMs = 1000;
const int HostapdMonitor::kInvalidSocket = -1;

HostapdMonitor::HostapdMonitor(const EventCallback& callback,
                               const string& control_interface_path,
                               const string& network_interface_name)
    : sockets_(new shill::Sockets()),
      event_callback_(callback),
      dest_path_(base::StringPrintf("%s/%s",
                                    control_interface_path.c_str(),
                                    network_interface_name.c_str())),
      local_path_(base::StringPrintf(kLocalPathFormat,
                                     network_interface_name.c_str())),
      hostapd_socket_(kInvalidSocket),
      io_handler_factory_(
          IOHandlerFactoryContainer::GetInstance()->GetIOHandlerFactory()),
      event_dispatcher_(EventDispatcher::GetInstance()),
      weak_ptr_factory_(this),
      started_(false) {}

HostapdMonitor::~HostapdMonitor() {
  if (hostapd_socket_ != kInvalidSocket) {
    unlink(local_path_.c_str());
    sockets_->Close(hostapd_socket_);
  }
}

void HostapdMonitor::Start() {
  if (started_) {
    LOG(ERROR) << "HostapdMonitor already started";
    return;
  }

  hostapd_ctrl_iface_check_count_ = 0;
  // Start off by checking the control interface file for the hostapd process.
  event_dispatcher_->PostTask(
      Bind(&HostapdMonitor::HostapdCtrlIfaceCheckTask,
           weak_ptr_factory_.GetWeakPtr()));
  started_ = true;
}

void HostapdMonitor::HostapdCtrlIfaceCheckTask() {
  struct stat buf;
  if (stat(dest_path_.c_str(), &buf) != 0) {
    if (hostapd_ctrl_iface_check_count_ >= kHostapdCtrlIfaceCheckMaxAttempts) {
      // This indicates the hostapd failed to start. Invoke callback indicating
      // hostapd start failed.
      LOG(ERROR) << "Timeout waiting for hostapd control interface";
      event_callback_.Run(kHostapdFailed, "");
    } else {
      hostapd_ctrl_iface_check_count_++;
      event_dispatcher_->PostDelayedTask(
          base::Bind(&HostapdMonitor::HostapdCtrlIfaceCheckTask,
                     weak_ptr_factory_.GetWeakPtr()),
          kHostapdCtrlIfaceCheckIntervalMs);
    }
    return;
  }

  // Control interface is up, meaning hostapd started successfully.
  event_callback_.Run(kHostapdStarted, "");

  // Attach to the control interface to receive unsolicited event notifications.
  AttachToHostapd();
}

void HostapdMonitor::AttachToHostapd() {
  if (hostapd_socket_ != kInvalidSocket) {
    LOG(ERROR) << "Socket already initialized";
    return;
  }

  // Setup socket address for local file and remote file.
  struct sockaddr_un local;
  local.sun_family = AF_UNIX;
  snprintf(local.sun_path, sizeof(local.sun_path), "%s", local_path_.c_str());
  struct sockaddr_un dest;
  dest.sun_family = AF_UNIX;
  snprintf(dest.sun_path, sizeof(dest.sun_path), "%s", dest_path_.c_str());

  // Setup socket for interprocess communication.
  hostapd_socket_ = sockets_->Socket(PF_UNIX, SOCK_DGRAM, 0);
  if (hostapd_socket_ < 0) {
    LOG(ERROR) << "Failed to open hostapd socket";
    return;
  }
  if (sockets_->Bind(hostapd_socket_,
                     reinterpret_cast<struct sockaddr*>(&local),
                     sizeof(local)) < 0) {
    PLOG(ERROR) << "Failed to bind to local socket";
    return;
  }
  if (sockets_->Connect(hostapd_socket_,
                        reinterpret_cast<struct sockaddr*>(&dest),
                        sizeof(dest)) < 0) {
    PLOG(ERROR) << "Failed to connect";
    return;
  }

  // Setup IO Input handler.
  hostapd_input_handler_.reset(io_handler_factory_->CreateIOInputHandler(
      hostapd_socket_,
      Bind(&HostapdMonitor::ParseMessage, Unretained(this)),
      Bind(&HostapdMonitor::OnReadError, Unretained(this))));

  if (!SendMessage(kHostapdCmdAttach, strlen(kHostapdCmdAttach))) {
    LOG(ERROR) << "Failed to attach to hostapd";
    return;
  }

  // Start a timer for ATTACH response.
  attach_timeout_callback_.Reset(
      Bind(&HostapdMonitor::AttachTimeoutHandler,
           weak_ptr_factory_.GetWeakPtr()));
  event_dispatcher_->PostDelayedTask(attach_timeout_callback_.callback(),
                                     kHostapdAttachTimeoutMs);
  return;
}

void HostapdMonitor::AttachTimeoutHandler() {
  LOG(ERROR) << "Timeout waiting for attach response";
}

// Method for sending message to hostapd control interface.
bool HostapdMonitor::SendMessage(const char* message, size_t length) {
  if (sockets_->Send(hostapd_socket_, message, length, 0) < 0) {
    PLOG(ERROR) << "Send to hostapd failed";
    return false;
  }

  return true;
}

void HostapdMonitor::ParseMessage(shill::InputData* data) {
  string str(reinterpret_cast<const char*>(data->buf), data->len);
  // "OK" response for the "ATTACH" command.
  if (str == kHostapdRespOk) {
    attach_timeout_callback_.Cancel();
    return;
  }

  // Event messages are in format of <[Level]>[Event] [Detail message].
  // For example: <2>AP-STA-CONNECTED 00:11:22:33:44:55
  // Refer to wpa_ctrl.h for complete list of possible events.
  if (str.find_first_of('<', 0) == 0 && str.find_first_of('>', 0) == 2) {
    // Remove the log level.
    string msg = str.substr(3);
    string event;
    string data;
    size_t pos = msg.find_first_of(' ', 0);
    if (pos == string::npos) {
      event = msg;
    } else {
      event = msg.substr(0, pos);
      data = msg.substr(pos + 1);
    }

    Event event_code;
    if (event == kHostapdEventStationConnected) {
      event_code = kStationConnected;
    } else if (event == kHostapdEventStationDisconnected) {
      event_code = kStationDisconnected;
    } else {
      LOG(INFO) << "Received unknown event: " << event;
      return;
    }
    event_callback_.Run(event_code, data);
    return;
  }

  LOG(INFO) << "Received unknown message: " << str;
}

void HostapdMonitor::OnReadError(const string& error_msg) {
  LOG(FATAL) << "Hostapd Socket read returns error: "
             << error_msg;
}

}  // namespace apmanager
