Skip to content
This repository has been archived by the owner on Jan 1, 2024. It is now read-only.

Commit

Permalink
app messaging tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrew Strelsky committed Sep 10, 2023
1 parent 1d29f51 commit e7dddd0
Show file tree
Hide file tree
Showing 9 changed files with 615 additions and 61 deletions.
20 changes: 19 additions & 1 deletion daemon/source/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "elf/elf.hpp"
#include "fd.hpp"
#include "hijacker/hijacker.hpp"
#include "msg.hpp"
#include "servers.hpp"
#include "util.hpp"

Expand Down Expand Up @@ -188,13 +189,15 @@ static bool handleIpc(const int syscore, const int fd) noexcept {
static constexpr int PING = 0;
static constexpr int PONG = 1;
static constexpr int PROCESS_LAUNCHED = 1;
static constexpr uint32_t BREW_PREFIX = 0x57455242;

bool result = true;

struct result {
int cmd;
int pid;
uintptr_t func;
unsigned int prefix;
} res{};

if (recv(fd, &res, sizeof(res), MSG_NOSIGNAL) == -1) {
Expand All @@ -221,8 +224,20 @@ static bool handleIpc(const int syscore, const int fd) noexcept {

result = false;

LoopBuilder loop = SLEEP_LOOP;
const int pid = res.pid;
const auto prefix = res.prefix;
const bool isHomebrew = res.func != 0;
if (notifyHandlers(prefix, pid, isHomebrew)) {
// elf loading has been handled by another loader
return result;
}

if (!isHomebrew && prefix != BREW_PREFIX) {
// handlers notified, not homebrew, nothing else to do
return result;
}

LoopBuilder loop = SLEEP_LOOP;

UniquePtr<Hijacker> spawned = nullptr;
{
Expand Down Expand Up @@ -331,6 +346,8 @@ static void *hookThread(void *args) noexcept {
return 0;
}

// TODO: maybe use sceLncUtilDeclareReadyForSuspend to handle rest mode

int main() {
puts("daemon entered");
AbortServer abortServer{};
Expand All @@ -339,6 +356,7 @@ int main() {
pthread_t elfHandler = nullptr;
UniquePtr<UnixSocket> serverSock{new UnixSocket{"/system_tmp/IPC"}};
pthread_create(&elfHandler, nullptr, hookThread, serverSock.get());
auto msgThread = startMessageReceiver();

abortServer.TcpServer::run();
klogServer.TcpServer::run();
Expand Down
160 changes: 160 additions & 0 deletions daemon/source/msg.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
#include <stdio.h>
#include <stdint.h>
#include <pthread.h>
#include <sys/_stdint.h>
#include <sys/types.h>
#include "msg.hpp"
#include "thread.hpp"
#include "util.hpp"

extern "C" void sceLncUtilGetAppTitleId(uint32_t appId, char *titleId);

class LaunchListeners {

// I should have made this a set
// realistically these will be small though
Vector<uint32_t> appIds{};
mutable Mutex mtx{};

public:
void append(const uint32_t appId) noexcept {
auto lock = mtx.lock();
for (const auto id :appIds) {
if (id == appId) {
return;
}
}
appIds.push_back(appId);
}

void remove(const uint32_t appId) noexcept {
auto lock = mtx.lock();
for (const auto &id :appIds) {
if (id == appId) {
appIds.erase(&id);
return;
}
}
}

void handle(const pid_t pid) noexcept {
auto lock = mtx.lock();
size_t length = appIds.size();
for (int i = 0; i < length; i++) {
const auto &id = appIds[i];
if (sceAppMessagingSendMsg(id, BREW_MSG_TYPE_APP_LAUNCHED, &pid, sizeof(pid), 0) != 0) {
i--;
length--;
appIds.erase(&id);
}
}
}
};

struct RegisteredPrefix {
uint32_t appId;
uint32_t prefix;
};

class PrefixHandlers {

Vector<RegisteredPrefix> ids{};
mutable Mutex mtx{};

public:
void append(uint32_t appId, uint32_t prefix) noexcept {
auto lock = mtx.lock();
for (const auto &id : ids) {
constexpr auto TITLEID_SIZE = 9;
char titleId[TITLEID_SIZE + 1]{};
if (id.prefix == prefix) {
sceLncUtilGetAppTitleId(appId, titleId);
char sPrefix[sizeof(prefix) + 1];
*reinterpret_cast<uint32_t *>(sPrefix) = prefix;
sPrefix[sizeof(sPrefix) - 1] = '\0';
printf("%s already registered to handle prefix %s\n", titleId, sPrefix);
return;
}
}
ids.emplace_back(appId, prefix);
}

bool handle(const uint32_t prefix, const pid_t pid) noexcept {
auto lock = mtx.lock();
size_t length = ids.size();
for (int i = 0; i < length; i++) {
const auto &id = ids[i];
if (id.prefix == prefix) {
if (sceAppMessagingSendMsg(id.appId, BREW_MSG_TYPE_APP_LAUNCHED, &pid, sizeof(pid), 0) != 0) {
i--;
length--;
ids.erase(&id);
}
return true;
}
}
return false;
}

bool canHandle(const uint32_t prefix) const noexcept {
auto lock = mtx.lock();
for (const auto &id : ids) {
if (id.prefix == prefix) {
return true;
}
}
return false;
}
};

static PrefixHandlers prefixHandlers{}; // NOLINT
static LaunchListeners launchListeners{}; // NOLINT

static int messageThread(void *unused) noexcept {
(void)unused;
static AppMessage msg{};

while (true) {
if (sceAppMessagingReceiveMsg(&msg) < 0) {
puts("sceAppMessagingReceiveMsg failed");
}
printf("received msg from 0x%04x\n", msg.sender);
printf("msgType: 0x%x\n", msg.msgType);
printf("payloadSize: 0x%x\n", msg.payloadSize);
switch (msg.msgType) {
case BREW_MSG_TYPE_REGISTER_PREFIX_HANDLER: {
prefixHandlers.append(msg.sender, *reinterpret_cast<uint32_t *>(msg.payload));
break;
}
case BREW_MSG_TYPE_REGISTER_LAUNCH_LISTENER:
if (*msg.payload) {
launchListeners.append(msg.sender);
} else {
launchListeners.remove(msg.sender);
}
break;
default:
puts("unexpected msgType");
break;
}
}
return 0;
}

JThread startMessageReceiver() noexcept {
return JThread{messageThread};
}

bool notifyHandlers(const uint32_t prefix, const pid_t pid, const bool isHomebrew) noexcept {
if (isHomebrew) {
// prefix handlers are notified first since they are responsible for loading the elf if applicable
// listeners need not be notified
return prefixHandlers.handle(prefix, pid);
}
launchListeners.handle(pid);
return false;
}

bool hasPrefixHandler(const uint32_t prefix) noexcept {
return prefixHandlers.canHandle(prefix);
}
30 changes: 30 additions & 0 deletions daemon/source/msg.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#pragma once

#include <stdint.h>
#include <stdlib.h>
#include "thread.hpp"

struct AppMessage;

extern "C" uint32_t sceAppMessagingSendMsg(uint32_t appId, uint32_t msgType, const void *msg, size_t msgLength, uint32_t flags);

extern "C" int sceAppMessagingReceiveMsg(const AppMessage *msg);

struct AppMessage {
static constexpr size_t PAYLOAD_SIZE = 8192;
uint32_t sender;
uint32_t msgType;
uint8_t payload[PAYLOAD_SIZE];
uint32_t payloadSize;
uint64_t timestamp;
};

enum HomebrewDaemonMessageType : uint32_t {
BREW_MSG_TYPE_REGISTER_PREFIX_HANDLER = 0x1000000,
BREW_MSG_TYPE_REGISTER_LAUNCH_LISTENER,
BREW_MSG_TYPE_APP_LAUNCHED
};

JThread startMessageReceiver() noexcept;
bool notifyHandlers(const uint32_t prefix, const pid_t pid, const bool isHomebrew) noexcept;
bool hasPrefixHandler(const uint32_t prefix) noexcept;
50 changes: 50 additions & 0 deletions daemon/source/thread.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,53 @@ class JThread : public Thread {
join();
}
};

class ScopedLock {
friend class Mutex;

pthread_mutex_t *mtx;

ScopedLock() = delete;
ScopedLock(pthread_mutex_t *mtx) noexcept : mtx(mtx) {
pthread_mutex_lock(mtx);
}

public:
ScopedLock(const ScopedLock&) = delete;
ScopedLock &operator=(const ScopedLock&) = delete;
ScopedLock(ScopedLock &&rhs) noexcept : mtx(rhs.mtx) {
rhs.mtx = nullptr;
}
ScopedLock &operator=(ScopedLock &&rhs) noexcept {
if (mtx != nullptr) {
std::terminate();
}
mtx = rhs.mtx;
rhs.mtx = nullptr;
return *this;
}
~ScopedLock() noexcept {
if (mtx != nullptr) {
pthread_mutex_unlock(mtx);
}
}
};

class Mutex {
pthread_mutex_t mtx;

public:
Mutex() noexcept : mtx{} {
pthread_mutex_init(&mtx, nullptr);
}
Mutex(const Mutex&) = delete;
Mutex &operator=(const Mutex&) = delete;
Mutex(Mutex &&rhs)= delete;
Mutex &operator=(Mutex &&rhs) = delete;
~Mutex() noexcept {
pthread_mutex_destroy(&mtx);
}
ScopedLock lock() noexcept {
return &mtx;
}
};
6 changes: 6 additions & 0 deletions include/kernel/proc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ class KProc : public KernelObject<KProc, PROC_SIZE> {
static constexpr size_t PID_OFFSET = 0xbc;
static constexpr size_t THREADS_OFFSET = 0x10;
static constexpr size_t FD_OFFSET = 0x48;
static constexpr size_t TITLEID_OFFSET = 0x470;
static constexpr size_t SELFINFO_OFFSET = 0x588;
static constexpr size_t SELFINFO_NAME_OFFSET = 0x59C;

Expand Down Expand Up @@ -176,6 +177,11 @@ class KProc : public KernelObject<KProc, PROC_SIZE> {
this->reload();
}
}

String getTitleId() const noexcept {
constexpr auto TITLE_ID_SIZE = 9;
return StringView{reinterpret_cast<const char *>(buf) + TITLEID_OFFSET, TITLE_ID_SIZE};
}
};

inline KIterator<KProc> getAllProcs() {
Expand Down
Loading

0 comments on commit e7dddd0

Please sign in to comment.