GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerCommon::Handle_qSpeedTest(
    StringExtractorGDBRemote &packet) {
  packet.SetFilePos(::strlen("qSpeedTest:"));

  llvm::StringRef key;
  llvm::StringRef value;
  bool success = packet.GetNameColonValue(key, value);
  if (success && key.equals("response_size")) {
    uint32_t response_size = 0;
    if (!value.getAsInteger(0, response_size)) {
      if (response_size == 0)
        return SendOKResponse();
      StreamString response;
      uint32_t bytes_left = response_size;
      response.PutCString("data:");
      while (bytes_left > 0) {
        if (bytes_left >= 26) {
          response.PutCString("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
          bytes_left -= 26;
        } else {
          response.Printf("%*.*s;", bytes_left, bytes_left,
                          "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
          bytes_left = 0;
        }
      }
      return SendPacketNoLock(response.GetString());
    }
  }
  return SendErrorResponse(7);
}
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet)
{
#ifdef _WIN32
    return SendErrorResponse(9);
#else
    // Spawn a local debugserver as a platform so we can then attach or launch
    // a process...

    Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
    if (log)
        log->Printf ("GDBRemoteCommunicationServerPlatform::%s() called", __FUNCTION__);

    ConnectionFileDescriptor file_conn;
    std::string hostname;
    packet.SetFilePos(::strlen ("qLaunchGDBServer;"));
    std::string name;
    std::string value;
    uint16_t port = UINT16_MAX;
    while (packet.GetNameColonValue(name, value))
    {
        if (name.compare ("host") == 0)
            hostname.swap(value);
        else if (name.compare ("port") == 0)
            port = StringConvert::ToUInt32(value.c_str(), 0, 0);
    }

    lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID;
    std::string socket_name;
    Error error = LaunchGDBServer(Args(), hostname, debugserver_pid, port, socket_name);
    if (error.Fail())
    {
        if (log)
            log->Printf("GDBRemoteCommunicationServerPlatform::%s() debugserver launch failed: %s", __FUNCTION__, error.AsCString ());
        return SendErrorResponse(9);
    }

    if (log)
        log->Printf ("GDBRemoteCommunicationServerPlatform::%s() debugserver launched successfully as pid %" PRIu64, __FUNCTION__, debugserver_pid);

    StreamGDBRemote response;
    response.Printf("pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset);
    if (!socket_name.empty())
    {
        response.PutCString("socket_name:");
        response.PutCStringAsRawHex8(socket_name.c_str());
        response.PutChar(';');
    }

    PacketResult packet_result = SendPacketNoLock(response.GetData(), response.GetSize());
    if (packet_result != PacketResult::Success)
    {
        if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
            ::kill (debugserver_pid, SIGINT);
    }
    return packet_result;
#endif
}
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServer::Handle_qSpeedTest (StringExtractorGDBRemote &packet)
{
    packet.SetFilePos(::strlen ("qSpeedTest:"));

    std::string key;
    std::string value;
    bool success = packet.GetNameColonValue(key, value);
    if (success && key.compare("response_size") == 0)
    {
        uint32_t response_size = Args::StringToUInt32(value.c_str(), 0, 0, &success);
        if (success)
        {
            if (response_size == 0)
                return SendOKResponse();
            StreamString response;
            uint32_t bytes_left = response_size;
            response.PutCString("data:");
            while (bytes_left > 0)
            {
                if (bytes_left >= 26)
                {
                    response.PutCString("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
                    bytes_left -= 26;
                }
                else
                {
                    response.Printf ("%*.*s;", bytes_left, bytes_left, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
                    bytes_left = 0;
                }
            }
            return SendPacketNoLock (response.GetData(), response.GetSize());
        }
    }
    return SendErrorResponse (7);
}
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet)
{
#ifdef _WIN32
    // No unix sockets on windows
    return false;
#else
    // Spawn a local debugserver as a platform so we can then attach or launch
    // a process...

    if (m_is_platform)
    {
        // Sleep and wait a bit for debugserver to start to listen...
        ConnectionFileDescriptor file_conn;
        Error error;
        std::string hostname;
        // TODO: /tmp/ should not be hardcoded. User might want to override /tmp
        // with the TMPDIR environnement variable
        packet.SetFilePos(::strlen ("qLaunchGDBServer;"));
        std::string name;
        std::string value;
        uint16_t port = UINT16_MAX;
        while (packet.GetNameColonValue(name, value))
        {
            if (name.compare ("host") == 0)
                hostname.swap(value);
            else if (name.compare ("port") == 0)
                port = Args::StringToUInt32(value.c_str(), 0, 0);
        }
        if (port == UINT16_MAX)
            port = GetNextAvailablePort();

        // Spawn a new thread to accept the port that gets bound after
        // binding to port 0 (zero).

        if (error.Success())
        {
            // Spawn a debugserver and try to get the port it listens to.
            ProcessLaunchInfo debugserver_launch_info;
            StreamString host_and_port;
            if (hostname.empty())
                hostname = "localhost";
            host_and_port.Printf("%s:%u", hostname.c_str(), port);
            const char *host_and_port_cstr = host_and_port.GetString().c_str();
            Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
            if (log)
                log->Printf("Launching debugserver with: %s...\n", host_and_port_cstr);

            debugserver_launch_info.SetMonitorProcessCallback(ReapDebugserverProcess, this, false);
            
            error = StartDebugserverProcess (host_and_port_cstr,
                                             debugserver_launch_info,
                                             port);

            lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID();


            if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
            {
                Mutex::Locker locker (m_spawned_pids_mutex);
                m_spawned_pids.insert(debugserver_pid);
                if (port > 0)
                    AssociatePortWithProcess(port, debugserver_pid);
            }
            else
            {
                if (port > 0)
                    FreePort (port);
            }

            if (error.Success())
            {
                char response[256];
                const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset);
                assert (response_len < sizeof(response));
                PacketResult packet_result = SendPacketNoLock (response, response_len);

                if (packet_result != PacketResult::Success)
                {
                    if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
                        ::kill (debugserver_pid, SIGINT);
                }
                return packet_result;
            }
        }
    }
    return SendErrorResponse (9);
#endif
}
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServer::Handle_qfProcessInfo (StringExtractorGDBRemote &packet)
{
    m_proc_infos_index = 0;
    m_proc_infos.Clear();

    ProcessInstanceInfoMatch match_info;
    packet.SetFilePos(::strlen ("qfProcessInfo"));
    if (packet.GetChar() == ':')
    {

        std::string key;
        std::string value;
        while (packet.GetNameColonValue(key, value))
        {
            bool success = true;
            if (key.compare("name") == 0)
            {
                StringExtractor extractor;
                extractor.GetStringRef().swap(value);
                extractor.GetHexByteString (value);
                match_info.GetProcessInfo().GetExecutableFile().SetFile(value.c_str(), false);
            }
            else if (key.compare("name_match") == 0)
            {
                if (value.compare("equals") == 0)
                {
                    match_info.SetNameMatchType (eNameMatchEquals);
                }
                else if (value.compare("starts_with") == 0)
                {
                    match_info.SetNameMatchType (eNameMatchStartsWith);
                }
                else if (value.compare("ends_with") == 0)
                {
                    match_info.SetNameMatchType (eNameMatchEndsWith);
                }
                else if (value.compare("contains") == 0)
                {
                    match_info.SetNameMatchType (eNameMatchContains);
                }
                else if (value.compare("regex") == 0)
                {
                    match_info.SetNameMatchType (eNameMatchRegularExpression);
                }
                else
                {
                    success = false;
                }
            }
            else if (key.compare("pid") == 0)
            {
                match_info.GetProcessInfo().SetProcessID (Args::StringToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0, &success));
            }
            else if (key.compare("parent_pid") == 0)
            {
                match_info.GetProcessInfo().SetParentProcessID (Args::StringToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0, &success));
            }
            else if (key.compare("uid") == 0)
            {
                match_info.GetProcessInfo().SetUserID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success));
            }
            else if (key.compare("gid") == 0)
            {
                match_info.GetProcessInfo().SetGroupID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success));
            }
            else if (key.compare("euid") == 0)
            {
                match_info.GetProcessInfo().SetEffectiveUserID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success));
            }
            else if (key.compare("egid") == 0)
            {
                match_info.GetProcessInfo().SetEffectiveGroupID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success));
            }
            else if (key.compare("all_users") == 0)
            {
                match_info.SetMatchAllUsers(Args::StringToBoolean(value.c_str(), false, &success));
            }
            else if (key.compare("triple") == 0)
            {
                match_info.GetProcessInfo().GetArchitecture().SetTriple (value.c_str(), NULL);
            }
            else
            {
                success = false;
            }

            if (!success)
                return SendErrorResponse (2);
        }
    }

    if (Host::FindProcesses (match_info, m_proc_infos))
    {
        // We found something, return the first item by calling the get
        // subsequent process info packet handler...
        return Handle_qsProcessInfo (packet);
    }
    return SendErrorResponse (3);
}
bool
GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet)
{
#ifdef _WIN32
    // No unix sockets on windows
    return false;
#else
    // Spawn a local debugserver as a platform so we can then attach or launch
    // a process...

    if (m_is_platform)
    {
        // Sleep and wait a bit for debugserver to start to listen...
        ConnectionFileDescriptor file_conn;
        char connect_url[PATH_MAX];
        Error error;
        std::string hostname;
        // TODO: /tmp/ should not be hardcoded. User might want to override /tmp
        // with the TMPDIR environnement variable
        packet.SetFilePos(::strlen ("qLaunchGDBServer;"));
        std::string name;
        std::string value;
        uint16_t port = UINT16_MAX;
        while (packet.GetNameColonValue(name, value))
        {
            if (name.compare ("host") == 0)
                hostname.swap(value);
            else if (name.compare ("port") == 0)
                port = Args::StringToUInt32(value.c_str(), 0, 0);
        }
        if (port == UINT16_MAX)
            port = GetNextAvailablePort();

        // Spawn a new thread to accept the port that gets bound after
        // binding to port 0 (zero).
        lldb::thread_t accept_thread = LLDB_INVALID_HOST_THREAD;
        const char *unix_socket_name = NULL;
        char unix_socket_name_buf[PATH_MAX] = "/tmp/XXXXXXXXX";

        if (port == 0)
        {
            if (::mkstemp (unix_socket_name_buf) == 0)
            {
                unix_socket_name = unix_socket_name_buf;
                ::snprintf (connect_url, sizeof(connect_url), "unix-accept://%s", unix_socket_name);
                accept_thread = Host::ThreadCreate (unix_socket_name,
                                                    AcceptPortFromInferior,
                                                    connect_url,
                                                    &error);
            }
            else
            {
                error.SetErrorStringWithFormat("failed to make temporary path for a unix socket: %s", strerror(errno));
            }
        }

        if (error.Success())
        {
            // Spawn a debugserver and try to get the port it listens to.
            ProcessLaunchInfo debugserver_launch_info;
            StreamString host_and_port;
            if (hostname.empty())
                hostname = "localhost";
            host_and_port.Printf("%s:%u", hostname.c_str(), port);
            const char *host_and_port_cstr = host_and_port.GetString().c_str();
            Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
            if (log)
                log->Printf("Launching debugserver with: %s...\n", host_and_port_cstr);

            debugserver_launch_info.SetMonitorProcessCallback(ReapDebugserverProcess, this, false);
            
            error = StartDebugserverProcess (host_and_port_cstr,
                                             unix_socket_name,
                                             debugserver_launch_info);

            lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID();


            if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
            {
                Mutex::Locker locker (m_spawned_pids_mutex);
                m_spawned_pids.insert(debugserver_pid);
                if (port > 0)
                    AssociatePortWithProcess(port, debugserver_pid);
            }
            else
            {
                if (port > 0)
                    FreePort (port);
            }

            if (error.Success())
            {
                bool success = false;

                if (IS_VALID_LLDB_HOST_THREAD(accept_thread))
                {
                    thread_result_t accept_thread_result = NULL;
                    if (Host::ThreadJoin (accept_thread, &accept_thread_result, &error))
                    {
                        if (accept_thread_result)
                        {
                            port = (intptr_t)accept_thread_result;
                            char response[256];
                            const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset);
                            assert (response_len < sizeof(response));
                            //m_port_to_pid_map[port] = debugserver_launch_info.GetProcessID();
                            success = SendPacketNoLock (response, response_len) > 0;
                        }
                    }
                }
                else
                {
                    char response[256];
                    const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset);
                    assert (response_len < sizeof(response));
                    //m_port_to_pid_map[port] = debugserver_launch_info.GetProcessID();
                    success = SendPacketNoLock (response, response_len) > 0;

                }
                Host::Unlink (unix_socket_name);

                if (!success)
                {
                    if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
                        ::kill (debugserver_pid, SIGINT);
                }
                return success;
            }
            else if (accept_thread)
            {
                Host::Unlink (unix_socket_name);
            }
        }
    }
    return SendErrorResponse (9);
#endif
}
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerCommon::Handle_qfProcessInfo(
    StringExtractorGDBRemote &packet) {
  m_proc_infos_index = 0;
  m_proc_infos.Clear();

  ProcessInstanceInfoMatch match_info;
  packet.SetFilePos(::strlen("qfProcessInfo"));
  if (packet.GetChar() == ':') {
    llvm::StringRef key;
    llvm::StringRef value;
    while (packet.GetNameColonValue(key, value)) {
      bool success = true;
      if (key.equals("name")) {
        StringExtractor extractor(value);
        std::string file;
        extractor.GetHexByteString(file);
        match_info.GetProcessInfo().GetExecutableFile().SetFile(file.c_str(),
                                                                false);
      } else if (key.equals("name_match")) {
        NameMatchType name_match =
            llvm::StringSwitch<NameMatchType>(value)
                .Case("equals", eNameMatchEquals)
                .Case("starts_with", eNameMatchStartsWith)
                .Case("ends_with", eNameMatchEndsWith)
                .Case("contains", eNameMatchContains)
                .Case("regex", eNameMatchRegularExpression)
                .Default(eNameMatchIgnore);
        match_info.SetNameMatchType(name_match);
        if (name_match == eNameMatchIgnore)
          return SendErrorResponse(2);
      } else if (key.equals("pid")) {
        lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
        if (value.getAsInteger(0, pid))
          return SendErrorResponse(2);
        match_info.GetProcessInfo().SetProcessID(pid);
      } else if (key.equals("parent_pid")) {
        lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
        if (value.getAsInteger(0, pid))
          return SendErrorResponse(2);
        match_info.GetProcessInfo().SetParentProcessID(pid);
      } else if (key.equals("uid")) {
        uint32_t uid = UINT32_MAX;
        if (value.getAsInteger(0, uid))
          return SendErrorResponse(2);
        match_info.GetProcessInfo().SetUserID(uid);
      } else if (key.equals("gid")) {
        uint32_t gid = UINT32_MAX;
        if (value.getAsInteger(0, gid))
          return SendErrorResponse(2);
        match_info.GetProcessInfo().SetGroupID(gid);
      } else if (key.equals("euid")) {
        uint32_t uid = UINT32_MAX;
        if (value.getAsInteger(0, uid))
          return SendErrorResponse(2);
        match_info.GetProcessInfo().SetEffectiveUserID(uid);
      } else if (key.equals("egid")) {
        uint32_t gid = UINT32_MAX;
        if (value.getAsInteger(0, gid))
          return SendErrorResponse(2);
        match_info.GetProcessInfo().SetEffectiveGroupID(gid);
      } else if (key.equals("all_users")) {
        match_info.SetMatchAllUsers(
            Args::StringToBoolean(value, false, &success));
      } else if (key.equals("triple")) {
        match_info.GetProcessInfo().GetArchitecture().SetTriple(
            value.str().c_str(), NULL);
      } else {
        success = false;
      }

      if (!success)
        return SendErrorResponse(2);
    }
  }

  if (Host::FindProcesses(match_info, m_proc_infos)) {
    // We found something, return the first item by calling the get
    // subsequent process info packet handler...
    return Handle_qsProcessInfo(packet);
  }
  return SendErrorResponse(3);
}
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet)
{
#ifdef _WIN32
    return SendErrorResponse(9);
#else
    // Spawn a local debugserver as a platform so we can then attach or launch
    // a process...

    Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
    if (log)
        log->Printf ("GDBRemoteCommunicationServerPlatform::%s() called", __FUNCTION__);

    // Sleep and wait a bit for debugserver to start to listen...
    ConnectionFileDescriptor file_conn;
    std::string hostname;
    // TODO: /tmp/ should not be hardcoded. User might want to override /tmp
    // with the TMPDIR environment variable
    packet.SetFilePos(::strlen ("qLaunchGDBServer;"));
    std::string name;
    std::string value;
    uint16_t port = UINT16_MAX;
    while (packet.GetNameColonValue(name, value))
    {
        if (name.compare ("host") == 0)
            hostname.swap(value);
        else if (name.compare ("port") == 0)
            port = StringConvert::ToUInt32(value.c_str(), 0, 0);
    }
    if (port == UINT16_MAX)
        port = GetNextAvailablePort();

    // Spawn a new thread to accept the port that gets bound after
    // binding to port 0 (zero).

    // ignore the hostname send from the remote end, just use the ip address
    // that we're currently communicating with as the hostname

    // Spawn a debugserver and try to get the port it listens to.
    ProcessLaunchInfo debugserver_launch_info;
    if (hostname.empty())
        hostname = "127.0.0.1";
    if (log)
        log->Printf("Launching debugserver with: %s:%u...\n", hostname.c_str(), port);

    // Do not run in a new session so that it can not linger after the
    // platform closes.
    debugserver_launch_info.SetLaunchInSeparateProcessGroup(false);
    debugserver_launch_info.SetMonitorProcessCallback(ReapDebugserverProcess, this, false);

    std::string platform_scheme;
    std::string platform_ip;
    int platform_port;
    std::string platform_path;
    bool ok = UriParser::Parse(GetConnection()->GetURI().c_str(), platform_scheme, platform_ip, platform_port, platform_path);
    assert(ok);
    Error error = StartDebugserverProcess (
                                     platform_ip.c_str(),
                                     port,
                                     debugserver_launch_info,
                                     port);

    lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID();


    if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
    {
        Mutex::Locker locker (m_spawned_pids_mutex);
        m_spawned_pids.insert(debugserver_pid);
        if (port > 0)
            AssociatePortWithProcess(port, debugserver_pid);
    }
    else
    {
        if (port > 0)
            FreePort (port);
    }

    if (error.Success())
    {
        if (log)
            log->Printf ("GDBRemoteCommunicationServerPlatform::%s() debugserver launched successfully as pid %" PRIu64, __FUNCTION__, debugserver_pid);

        char response[256];
        const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset);
        assert (response_len < (int)sizeof(response));
        PacketResult packet_result = SendPacketNoLock (response, response_len);

        if (packet_result != PacketResult::Success)
        {
            if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
                ::kill (debugserver_pid, SIGINT);
        }
        return packet_result;
    }
    else
    {
        if (log)
            log->Printf ("GDBRemoteCommunicationServerPlatform::%s() debugserver launch failed: %s", __FUNCTION__, error.AsCString ());
    }
    return SendErrorResponse (9);
#endif
}