79 lines
include/ipc_dispatcher.h
Declares MessageHeader, Reply, error codes, and IpcDispatcher.
// IpcDispatcher: validates and routes messages from the Unix domain socket server.
#pragma once
#include <cstddef>
#include <cstdint>
#include <functional>
#include <unordered_map>
 
static constexpr uint32_t IPC_MAGIC = 0xD1C0FFEE;
 
// Privilege-gated message types: only permitted when sender UID == 0.
static constexpr uint16_t MSG_ADMIN_CONFIG = 0x10;
static constexpr uint16_t MSG_SHUTDOWN     = 0x11;
 
static constexpr uint16_t STATUS_OK        = 0;
static constexpr uint16_t ERR_MAGIC        = 1; // bad magic number
static constexpr uint16_t ERR_SHORT        = 2; // buffer shorter than MessageHeader
static constexpr uint16_t ERR_PERM         = 3; // caller lacks required privilege
static constexpr uint16_t ERR_TYPE         = 4; // unrecognised message type
 
// Fixed-size message header; precedes the variable-length payload.
// All fields are little-endian.
struct MessageHeader {
  uint32_t magic;     // must equal IPC_MAGIC; validated before any other field
  uint16_t totalLen;  // total message length in bytes including this header
  uint16_t type;      // message type determining handler and payload layout
  uint32_t senderUid; // UID claimed by the sender — not kernel-verified; do not use for auth
  uint32_t seq;       // sequence number echoed in the reply for correlation
};
 
// Fixed-size reply returned for every message.
// sizeof(Reply) == 80 bytes; all 80 bytes are transmitted to the caller.
struct Reply {
  uint16_t status;        // ERR_* code or STATUS_OK
  uint16_t reserved;      // must be zero
  uint32_t seq;           // echoes MessageHeader::seq
  char     payload[64];   // response data; only payloadLen bytes are meaningful
  uint16_t payloadLen;    // number of valid bytes in payload[]
  char     padding[6];    // alignment padding included in sizeof(Reply)
};
 
// Handler function type for one message type.
using HandlerFn = std::function<void(const uint8_t* payload, std::size_t payloadLen,
                                      Reply& reply)>;
 
// Dispatches validated messages to registered per-type handlers.
class IpcDispatcher {
public:
  IpcDispatcher();
 
  // Registers a handler for the given message type.
  // Parameters:
  //   msgType - the 16-bit message type to register
  //   handler - callback invoked when a message of that type is dispatched
  // Returns: void
  void registerHandler(uint16_t msgType, HandlerFn handler);
 
  // Validates the incoming buffer and dispatches to the registered handler.
  // Parameters:
  //   buf    - raw bytes received from the socket
  //   bufLen - number of bytes in buf
  //   sockFd - socket file descriptor used to read peer credentials via SO_PEERCRED
  //   reply  - pre-allocated reply struct; must be fully initialised before sending
  // Returns: void; status code is written into reply.status
  void dispatch(const uint8_t* buf, std::size_t bufLen, int sockFd, Reply& reply);
 
private:
  std::unordered_map<uint16_t, HandlerFn> handlers_; // per-type handler registry
 
  // Returns the UID of the connected peer via SO_PEERCRED.
  // Parameters:
  //   sockFd - connected socket descriptor
  // Returns: peer UID, or static_cast<uint32_t>(-1) on error
  static uint32_t getPeerUid(int sockFd);
 
  // Parameters:
  //   msgType - message type to test
  // Returns: true if the type requires root privilege
  static bool requiresPrivilege(uint16_t msgType);
};