+#include <cstdlib>
+#include <cstring>
+#include <vector>
+#include <string>
+#include <set>
+#include <sstream>
+
+#include <dirent.h>
+#include <sys/stat.h>
+
+#include "environment.h"
+#include "waiter.h"
+#include "log.h"
+
+#include "tini.hpp"
+
+#ifndef LAUNCHER_CONFIG
+#define LAUNCHER_CONFIG "/usr/share/dotnet/dotnet-launcher.ini"
+#endif
+
+static std::string AbsolutePath(const std::string& path)
+{
+ std::string absPath;
+
+ char realPath[PATH_MAX];
+ if (realpath(path, realPath) != nullptr && realPath[0] != '\0')
+ {
+ absPath.assign(realPath);
+ }
+
+ return absPath;
+}
+
+static std::string Basename(const std::string& path)
+{
+ auto pos = path.find_last_of('/');
+ if (pos != std::string::npos)
+ {
+ return path.substr(0, pos);
+ }
+ return path;
+}
+
+static std::string AssembliesInDirectory(const char *directory)
+{
+ const char * const nativeImageExtension = ".ni";
+ const char * const tpaExtensions[] = {".dll", ".exe"};
+ int niExtensionSize = strlen(nativeImageExtension);
+ int directoryPathSize = strlen(directory);
+
+ std::string tpaList;
+
+ DIR* dir = opendir(directory);
+
+ if (dir == nullptr) return std::string();
+
+ std::map<std::pair<std::string, std::string>, bool> addedAssemblies;
+
+ struct dirent *entry;
+ while ((entry = readdir(dir)) != nullptr)
+ {
+ switch (entry->d_type)
+ {
+ case DT_REG: break;
+ case DT_LNK:
+ case DT_UNKNOWN:
+ {
+ std::string fullname;
+ fullname.append(directory);
+ fullname.append("/");
+ fullname.append(entry->d_name);
+
+ struct stat sb;
+ if (stat(fullname.c_str(), &sb) == -1)
+ continue;
+
+ if (!S_ISREG(sb.st_mode))
+ continue;
+ }
+ break;
+ default:
+ continue;
+ }
+
+ // Check the extension.
+ std::string filename(entry->d_name);
+ int extPos = filename.find_last_of('.');
+ if (extPos <= 0) continue;
+ for (auto ext : tpaExtensions)
+ {
+ int extLength = strlen(ext);
+ if (filename.compare(extPos-1, extLength, ext) != 0)
+ continue;
+ }
+
+
+ std::string filenameWithoutExt;
+ bool isNativeImage = extPos > niExtensionSize ?
+ filename.compare(extPos-niExtensionSize, niExtensionSize, nativeImageExtension) == 0 : false;
+ if (isNativeImage)
+ {
+ filenameWithoutExt = filename.substr(0, extPos-niExtensionSize);
+ }
+ else
+ {
+ filenameWithoutExt = filename.substr(0, extPos);
+ }
+ std::string ext = filename.substr(extPos);
+
+ std::pair<std::string, std::string> key(filenameWithoutExt, ext);
+ std::cout << " " << filenameWithoutExt << ext << " " << isNativeImage << std::endl;
+ if (addedAssemblies.count(key))
+ {
+ isNativeImage = isNativeImage || addedAssemblies[key];
+ }
+ addedAssemblies[key] = isNativeImage;
+ }
+
+ for (auto pair : addedAssemblies)
+ {
+ tpaList.append(directory);
+ if (directory[directoryPathSize-1] != '/')
+ tpaList.append("/");
+ tpaList.append(pair.first.first);
+ if (pair.second)
+ {
+ tpaList.append(nativeImageExtension);
+ }
+ tpaList.append(pair.first.second);
+ tpaList.append(":");
+ }
+
+ closedir(dir);
+ return tpaList;
+}
+
+Launcher::Launcher()
+{
+}
+
+Launcher::~Launcher()
+{
+}
+
+void Launcher::Initialize()
+{
+ std::ifstream iniStream(LAUNCHER_CONFIG);
+ std::stringstream iniString;
+ iniString << iniStream.rdbuf();
+ tini::ini launcherIni(iniString);
+
+ auto &dotnet = ini["dotnet"];
+ if (dotnet.find("libcoreclr") == dotnet.end())
+ dotnet["libcoreclr"] = "libcoreclr.so";
+ if (dotnet.find("coreclr_dir") == dotnet.end())
+ dotnet["coreclr_dir"] = "/usr/share/dotnet";
+ if (dotnet.find("tpa_dir") == dotnet.end())
+ dotnet["tpa_dir"] = dotnet["coreclr_dir"] + ":" + "/usr/share/assemblies";
+ if (dontet.find("native_so_search_dirs") == dotnet.end())
+ dotnet["native_so_search_dirs"] = dotnet["tpa_dir"];
+
+ std::string libcoreclr = dotnet["coreclr_dir"] + "/" + dotnet["libcoreclr"];
+ std::string tpaDirs = dotnet["tpa_dirs"];
+ std::string nativeSoSearchDirs = dotnet["native_so_search_dirs"];
+
+ void* coreclrLib = dlopen(libcoreclr, RTLD_NOW | RTLD_LOCAL);
+ if (coreclrLib == nullptr)
+ {
+ char *err = dlerror();
+ _ERR("dlopen failed to open libcoreclr.so with error %s", err);
+ goto CoreClrLibClose;
+ }
+
+ initializeCoreCLR = (coreclr_initialize_ptr)dlsym(coreclrLib, "coreclr_initialize");
+ executeAssembly = (coreclr_execute_assembly_ptr)dlsym(coreclrLib, "coreclr_execute_assembly");
+ shutdownCoreCLR = (coreclr_shutdown_ptr)dlsym(coreclrLib, "coreclr_shutdown");
+
+ if (coreclr_initialize_ptr == nullptr)
+ {
+ _ERR("coreclr_initialize_ptr not found in the libcoreclr.so");
+ }
+ else if (coreclr_execute_assembly_ptr == nullptr)
+ {
+ _ERR("coreclr_execute_assembly_ptr not found in the libcoreclr.so");
+ }
+ else if (coreclr_shutdown_ptr == nullptr)
+ {
+ _ERR("coreclr_shutdown_ptr not found in the libcoreclr.so");
+ }
+ else
+ {
+ std::istringstream f(tpaDirs);
+ std::string s;
+ while (std::getline(f, s, ':'))
+ {
+ TrustedPlatformAssemblies += AssembliesInDirectory(s);
+ }
+ NativeDllSearchDirectories = nativeSoSearchDirs;
+ AppDomainCompatSwitch = "UseLatestBehaviorWhenTFMNotSpecified";
+ }
+
+CoreClrLibClose:
+ if (dlclose(coreclrLib) != 0)
+ {
+ _ERR("libcoreclr.so close failed");
+ }
+}
+
+void Launcher::Dispose()
+{
+}
+
+void Launcher::Launch(const string& exe_path, int argc, char *argv[])
+{
+ std::string bin_path = Basename(exe_path);
+ std::string app_home = Basename(app_path);
+ std::string lib_path = app_home + "/lib";
+ std::string app_path = bin_path + ":" + lib_path
+ std::string app_ni_path = app_path;
+ std::string nativeDllSearchDirectories = NativeDllSearchDirectories + app_path;
+
+ const char *propertyKeys[] =
+ {
+ "TRUSTED_PLATFORM_ASSEMBLIES",
+ "APP_PATHS",
+ "APP_NI_PATHS",
+ "NATIVE_DLL_SEARCH_DIRECTORIES",
+ "AppDomainCompatSwitch"
+ };
+
+ const char *propertyValues[] =
+ {
+ TrustedPlatformAssemblies.c_str(),
+ app_path.c_str(),
+ app_ni_path.c_str(),
+ nativeDllSearchDirectories.c_str(),
+ AppDomainCompatSwitch.c_str()
+ };
+
+ void* hostHandle;
+ unsigned int domainId;
+
+ int st = initializeCoreCLR(exe_path,
+ "tizen_dotnet_launcher",
+ sizeof(propertyKeys) / sizeof(propertyKeys[0]),
+ propertyKeys,
+ propertyValues,
+ &hostHandle,
+ &domainId);
+ if (st < 0)
+ {
+ // initialize coreclr fail
+ exit(-1);
+ }
+
+ unsigned int exitCode;
+ st = executeAssembly(hostHandle, domainId, argc, argv, exe_path, &exitCode);
+ if (st < 0)
+ {
+ // execute coreclr fail
+ exit(-1);
+ }
+
+ st = shutdownCoreCLR(hostHandle, domainId);
+ if (st < 0)
+ {
+ // shutdown fail
+ exit(-1);
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ std::unique_ptr<Launcher> launcher(new Launcher());
+ auto on_prepare = [&launcher]()
+ {
+ launcher.Initialize();
+ };
+ auto on_requested = [&launcher]()
+ {
+ };
+ auto on_executed = [&launcher](const std::string& path, int argc, char *argv[])
+ {
+ launcher.launch(path, argc, argv);
+ }
+ std::unique_ptr<Waiter> waiter(new Waiter(on_prepare, on_requested, on_executed));
+}