100e305d2STamas Berghammer //===-- PlatformAndroidRemoteGDBServer.cpp ----------------------*- C++ -*-===//
200e305d2STamas Berghammer //
300e305d2STamas Berghammer //                     The LLVM Compiler Infrastructure
400e305d2STamas Berghammer //
500e305d2STamas Berghammer // This file is distributed under the University of Illinois Open Source
600e305d2STamas Berghammer // License. See LICENSE.TXT for details.
700e305d2STamas Berghammer //
800e305d2STamas Berghammer //===----------------------------------------------------------------------===//
900e305d2STamas Berghammer 
1000e305d2STamas Berghammer // Other libraries and framework includes
1100e305d2STamas Berghammer #include "lldb/Core/Error.h"
1205a55de3SOleksiy Vyalov #include "lldb/Core/Log.h"
13*e7eabbb5SOleksiy Vyalov #include "lldb/Host/Socket.h"
1400e305d2STamas Berghammer 
1500e305d2STamas Berghammer // Project includes
1605a55de3SOleksiy Vyalov #include "AdbClient.h"
1700e305d2STamas Berghammer #include "PlatformAndroidRemoteGDBServer.h"
1800e305d2STamas Berghammer #include "Utility/UriParser.h"
1900e305d2STamas Berghammer 
2054971856SOleksiy Vyalov #include <sstream>
2154971856SOleksiy Vyalov 
2200e305d2STamas Berghammer using namespace lldb;
2300e305d2STamas Berghammer using namespace lldb_private;
24db264a6dSTamas Berghammer using namespace platform_android;
2500e305d2STamas Berghammer 
2600e305d2STamas Berghammer static const lldb::pid_t g_remote_platform_pid = 0; // Alias for the process id of lldb-platform
2700e305d2STamas Berghammer 
2800e305d2STamas Berghammer static Error
29*e7eabbb5SOleksiy Vyalov ForwardPortWithAdb (const uint16_t local_port, const uint16_t remote_port, std::string& device_id)
3000e305d2STamas Berghammer {
31db264a6dSTamas Berghammer     Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM));
3200e305d2STamas Berghammer 
3305a55de3SOleksiy Vyalov     AdbClient adb;
343ea689b3SChaoren Lin     auto error = AdbClient::CreateByDeviceID(device_id, adb);
3500e305d2STamas Berghammer     if (error.Fail ())
3600e305d2STamas Berghammer         return error;
3700e305d2STamas Berghammer 
38f9da9483SOleksiy Vyalov     device_id = adb.GetDeviceID();
3905a55de3SOleksiy Vyalov     if (log)
40f9da9483SOleksiy Vyalov         log->Printf("Connected to Android device \"%s\"", device_id.c_str ());
4105a55de3SOleksiy Vyalov 
42*e7eabbb5SOleksiy Vyalov     return adb.SetPortForwarding(local_port, remote_port);
4300e305d2STamas Berghammer }
4400e305d2STamas Berghammer 
4500e305d2STamas Berghammer static Error
46*e7eabbb5SOleksiy Vyalov DeleteForwardPortWithAdb (uint16_t local_port, const std::string& device_id)
4700e305d2STamas Berghammer {
4805a55de3SOleksiy Vyalov     AdbClient adb (device_id);
49*e7eabbb5SOleksiy Vyalov     return adb.DeletePortForwarding (local_port);
50*e7eabbb5SOleksiy Vyalov }
51*e7eabbb5SOleksiy Vyalov 
52*e7eabbb5SOleksiy Vyalov static Error
53*e7eabbb5SOleksiy Vyalov FindUnusedPort (uint16_t& port)
54*e7eabbb5SOleksiy Vyalov {
55*e7eabbb5SOleksiy Vyalov     Socket* socket = nullptr;
56*e7eabbb5SOleksiy Vyalov     auto error = Socket::TcpListen ("localhost:0", false, socket, nullptr);
57*e7eabbb5SOleksiy Vyalov     if (error.Success ())
58*e7eabbb5SOleksiy Vyalov     {
59*e7eabbb5SOleksiy Vyalov         port = socket->GetLocalPortNumber ();
60*e7eabbb5SOleksiy Vyalov         delete socket;
61*e7eabbb5SOleksiy Vyalov     }
62*e7eabbb5SOleksiy Vyalov     return error;
6300e305d2STamas Berghammer }
6400e305d2STamas Berghammer 
6500e305d2STamas Berghammer PlatformAndroidRemoteGDBServer::PlatformAndroidRemoteGDBServer ()
6600e305d2STamas Berghammer {
6700e305d2STamas Berghammer }
6800e305d2STamas Berghammer 
6900e305d2STamas Berghammer PlatformAndroidRemoteGDBServer::~PlatformAndroidRemoteGDBServer ()
7000e305d2STamas Berghammer {
7100e305d2STamas Berghammer     for (const auto& it : m_port_forwards)
723ea689b3SChaoren Lin         DeleteForwardPortWithAdb(it.second, m_device_id);
7300e305d2STamas Berghammer }
7400e305d2STamas Berghammer 
7500e305d2STamas Berghammer uint16_t
7600e305d2STamas Berghammer PlatformAndroidRemoteGDBServer::LaunchGDBserverAndGetPort (lldb::pid_t &pid)
7700e305d2STamas Berghammer {
78*e7eabbb5SOleksiy Vyalov     uint16_t remote_port = m_gdb_client.LaunchGDBserverAndGetPort (pid, "127.0.0.1");
79*e7eabbb5SOleksiy Vyalov     if (remote_port == 0)
80*e7eabbb5SOleksiy Vyalov         return remote_port;
8100e305d2STamas Berghammer 
82*e7eabbb5SOleksiy Vyalov     uint16_t local_port = 0;
83*e7eabbb5SOleksiy Vyalov     auto error = SetPortForwarding (pid, remote_port, local_port);
84*e7eabbb5SOleksiy Vyalov     return error.Success() ? local_port : 0;
8500e305d2STamas Berghammer }
8600e305d2STamas Berghammer 
8700e305d2STamas Berghammer bool
8800e305d2STamas Berghammer PlatformAndroidRemoteGDBServer::KillSpawnedProcess (lldb::pid_t pid)
8900e305d2STamas Berghammer {
901c1d76b3SOleksiy Vyalov     DeleteForwardPort (pid);
9100e305d2STamas Berghammer     return m_gdb_client.KillSpawnedProcess (pid);
9200e305d2STamas Berghammer }
9300e305d2STamas Berghammer 
9400e305d2STamas Berghammer Error
9500e305d2STamas Berghammer PlatformAndroidRemoteGDBServer::ConnectRemote (Args& args)
9600e305d2STamas Berghammer {
973ea689b3SChaoren Lin     m_device_id.clear();
983ea689b3SChaoren Lin 
9900e305d2STamas Berghammer     if (args.GetArgumentCount() != 1)
10000e305d2STamas Berghammer         return Error("\"platform connect\" takes a single argument: <connect-url>");
10100e305d2STamas Berghammer 
102*e7eabbb5SOleksiy Vyalov     int remote_port;
10300e305d2STamas Berghammer     std::string scheme, host, path;
10400e305d2STamas Berghammer     const char *url = args.GetArgumentAtIndex (0);
1053ea689b3SChaoren Lin     if (!url)
1063ea689b3SChaoren Lin         return Error("URL is null.");
107*e7eabbb5SOleksiy Vyalov     if (!UriParser::Parse (url, scheme, host, remote_port, path))
1083ea689b3SChaoren Lin         return Error("Invalid URL: %s", url);
1093ea689b3SChaoren Lin     if (scheme == "adb")
1103ea689b3SChaoren Lin         m_device_id = host;
11100e305d2STamas Berghammer 
112*e7eabbb5SOleksiy Vyalov     uint16_t local_port = 0;
113*e7eabbb5SOleksiy Vyalov     auto error = SetPortForwarding (g_remote_platform_pid, remote_port, local_port);
11400e305d2STamas Berghammer     if (error.Fail ())
11500e305d2STamas Berghammer         return error;
11600e305d2STamas Berghammer 
117*e7eabbb5SOleksiy Vyalov     const std::string new_url = MakeUrl(
118*e7eabbb5SOleksiy Vyalov         scheme.c_str(), host.c_str(), local_port, path.c_str());
119*e7eabbb5SOleksiy Vyalov     args.ReplaceArgumentAtIndex (0, new_url.c_str ());
120*e7eabbb5SOleksiy Vyalov 
121*e7eabbb5SOleksiy Vyalov     Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM));
122*e7eabbb5SOleksiy Vyalov     if (log)
123*e7eabbb5SOleksiy Vyalov         log->Printf("Rewritten URL: %s", new_url.c_str());
12400e305d2STamas Berghammer 
1251c1d76b3SOleksiy Vyalov     error = PlatformRemoteGDBServer::ConnectRemote(args);
1261c1d76b3SOleksiy Vyalov     if (error.Fail ())
1271c1d76b3SOleksiy Vyalov         DeleteForwardPort (g_remote_platform_pid);
1281c1d76b3SOleksiy Vyalov 
1291c1d76b3SOleksiy Vyalov     return error;
13000e305d2STamas Berghammer }
13100e305d2STamas Berghammer 
13200e305d2STamas Berghammer Error
13300e305d2STamas Berghammer PlatformAndroidRemoteGDBServer::DisconnectRemote ()
13400e305d2STamas Berghammer {
1351c1d76b3SOleksiy Vyalov     DeleteForwardPort (g_remote_platform_pid);
1361c1d76b3SOleksiy Vyalov     return PlatformRemoteGDBServer::DisconnectRemote ();
13700e305d2STamas Berghammer }
13800e305d2STamas Berghammer 
1391c1d76b3SOleksiy Vyalov void
1401c1d76b3SOleksiy Vyalov PlatformAndroidRemoteGDBServer::DeleteForwardPort (lldb::pid_t pid)
1411c1d76b3SOleksiy Vyalov {
1421c1d76b3SOleksiy Vyalov     Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM));
1431c1d76b3SOleksiy Vyalov 
1441c1d76b3SOleksiy Vyalov     auto it = m_port_forwards.find(pid);
1451c1d76b3SOleksiy Vyalov     if (it == m_port_forwards.end())
1461c1d76b3SOleksiy Vyalov         return;
1471c1d76b3SOleksiy Vyalov 
1483ea689b3SChaoren Lin     const auto port = it->second;
1493ea689b3SChaoren Lin     const auto error = DeleteForwardPortWithAdb(port, m_device_id);
1501c1d76b3SOleksiy Vyalov     if (error.Fail()) {
1511c1d76b3SOleksiy Vyalov         if (log)
1521c1d76b3SOleksiy Vyalov             log->Printf("Failed to delete port forwarding (pid=%" PRIu64 ", port=%d, device=%s): %s",
1533ea689b3SChaoren Lin                          pid, port, m_device_id.c_str(), error.AsCString());
1541c1d76b3SOleksiy Vyalov     }
1551c1d76b3SOleksiy Vyalov     m_port_forwards.erase(it);
15600e305d2STamas Berghammer }
15754971856SOleksiy Vyalov 
158*e7eabbb5SOleksiy Vyalov Error
159*e7eabbb5SOleksiy Vyalov PlatformAndroidRemoteGDBServer::SetPortForwarding(const lldb::pid_t pid,
160*e7eabbb5SOleksiy Vyalov                                                   const uint16_t remote_port,
161*e7eabbb5SOleksiy Vyalov                                                   uint16_t &local_port)
162*e7eabbb5SOleksiy Vyalov {
163*e7eabbb5SOleksiy Vyalov     static const int kAttempsNum = 5;
164*e7eabbb5SOleksiy Vyalov 
165*e7eabbb5SOleksiy Vyalov     Error error;
166*e7eabbb5SOleksiy Vyalov     // There is a race possibility that somebody will occupy
167*e7eabbb5SOleksiy Vyalov     // a port while we're in between FindUnusedPort and ForwardPortWithAdb -
168*e7eabbb5SOleksiy Vyalov     // adding the loop to mitigate such problem.
169*e7eabbb5SOleksiy Vyalov     for (auto i = 0; i < kAttempsNum; ++i)
170*e7eabbb5SOleksiy Vyalov     {
171*e7eabbb5SOleksiy Vyalov         error = FindUnusedPort(local_port);
172*e7eabbb5SOleksiy Vyalov         if (error.Fail())
173*e7eabbb5SOleksiy Vyalov             return error;
174*e7eabbb5SOleksiy Vyalov 
175*e7eabbb5SOleksiy Vyalov         error = ForwardPortWithAdb(local_port, remote_port, m_device_id);
176*e7eabbb5SOleksiy Vyalov         if (error.Success())
177*e7eabbb5SOleksiy Vyalov         {
178*e7eabbb5SOleksiy Vyalov             m_port_forwards[pid] = local_port;
179*e7eabbb5SOleksiy Vyalov             break;
180*e7eabbb5SOleksiy Vyalov         }
181*e7eabbb5SOleksiy Vyalov     }
182*e7eabbb5SOleksiy Vyalov 
183*e7eabbb5SOleksiy Vyalov     return error;
184*e7eabbb5SOleksiy Vyalov }
185*e7eabbb5SOleksiy Vyalov 
18654971856SOleksiy Vyalov std::string
187*e7eabbb5SOleksiy Vyalov PlatformAndroidRemoteGDBServer::MakeUrl(const char* scheme,
18854971856SOleksiy Vyalov                                         const char* hostname,
189*e7eabbb5SOleksiy Vyalov                                         uint16_t port,
190*e7eabbb5SOleksiy Vyalov                                         const char* path)
19154971856SOleksiy Vyalov {
19254971856SOleksiy Vyalov     std::ostringstream hostname_str;
19354971856SOleksiy Vyalov     if (!strcmp(scheme, "adb"))
19454971856SOleksiy Vyalov         hostname_str << "[" << hostname << "]";
19554971856SOleksiy Vyalov     else
19654971856SOleksiy Vyalov         hostname_str << hostname;
19754971856SOleksiy Vyalov 
198*e7eabbb5SOleksiy Vyalov     return PlatformRemoteGDBServer::MakeUrl(scheme,
19954971856SOleksiy Vyalov                                             hostname_str.str().c_str(),
200*e7eabbb5SOleksiy Vyalov                                             port,
201*e7eabbb5SOleksiy Vyalov                                             path);
20254971856SOleksiy Vyalov }
203