summaryrefslogtreecommitdiffstats
path: root/src/core/hle/service/service.h
blob: 2293b473ac93d2ec8fb706c2bf64b9daf2d1bd56 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
// Copyright 2014 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.

#pragma once

#include <cstddef>
#include <string>
#include <unordered_map>
#include <boost/container/flat_map.hpp>
#include "common/common_types.h"
#include "core/hle/ipc.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/result.h"
#include "core/memory.h"

////////////////////////////////////////////////////////////////////////////////////////////////////
// Namespace Service

namespace Service {

static const int kMaxPortSize = 8; ///< Maximum size of a port name (8 characters)
static const u32 DefaultMaxSessions = 10; ///< Arbitrary default number of maximum connections to an HLE service

/**
 * Interface implemented by HLE Session handlers.
 * This can be provided to a ServerSession in order to hook into several relevant events (such as a new connection or a SyncRequest)
 * so they can be implemented in the emulator.
 */
class SessionRequestHandler {
public:
    /**
     * Dispatches and handles a sync request from the emulated application.
     * @param server_session The ServerSession that was triggered for this sync request,
     * it should be used to differentiate which client (As in ClientSession) we're answering to.
     * @returns ResultCode the result code of the translate operation.
     */
    ResultCode HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session);

    /**
     * Signals that a client has just connected to this HLE handler and keeps the
     * associated ServerSession alive for the duration of the connection.
     * @param server_session Owning pointer to the ServerSession associated with the connection.
     */
    void ClientConnected(Kernel::SharedPtr<Kernel::ServerSession> server_session);

    /**
     * Signals that a client has just disconnected from this HLE handler and releases the
     * associated ServerSession.
     * @param server_session ServerSession associated with the connection.
     */
    void ClientDisconnected(Kernel::SharedPtr<Kernel::ServerSession> server_session);

protected:
    /**
     * Handles a sync request from the emulated application and writes the response to the command buffer.
     * TODO(Subv): Use a wrapper structure to hold all the information relevant to
     * this request (ServerSession, Originator thread, Translated command buffer, etc).
     */
    virtual void HandleSyncRequestImpl(Kernel::SharedPtr<Kernel::ServerSession> server_session) = 0;

private:
    /**
     * Performs command buffer translation for this request.
     * The command buffer from the ServerSession thread's TLS is copied into a
     * buffer and all descriptors in the buffer are processed.
     * TODO(Subv): Implement this function, currently we do not support multiple processes running at once,
     * but once that is implemented we'll need to properly translate all descriptors in the command buffer.
     */
    ResultCode TranslateRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session);

    /// List of sessions that are connected to this handler.
    /// A ServerSession whose server endpoint is an HLE implementation is kept alive by this list for the duration of the connection.
    std::vector<Kernel::SharedPtr<Kernel::ServerSession>> connected_sessions;
};

/**
 * Framework for implementing HLE service handlers which dispatch incoming SyncRequests based on a table mapping header ids to handler functions.
 */
class Interface : public SessionRequestHandler {
public:
    /**
     * Creates an HLE interface with the specified max sessions.
     * @param max_sessions Maximum number of sessions that can be
     * connected to this service at the same time.
     */
    Interface(u32 max_sessions = DefaultMaxSessions);

    virtual ~Interface();

    std::string GetName() const {
        return GetPortName();
    }

    virtual void SetVersion(u32 raw_version) {
        version.raw = raw_version;
    }

    /**
     * Gets the maximum allowed number of sessions that can be connected to this service at the same time.
     * @returns The maximum number of connections allowed.
     */
    u32 GetMaxSessions() const { return max_sessions; }

    typedef void (*Function)(Interface*);

    struct FunctionInfo {
        u32 id;
        Function func;
        const char* name;
    };

    /**
     * Gets the string name used by CTROS for a service
     * @return Port name of service
     */
    virtual std::string GetPortName() const {
        return "[UNKNOWN SERVICE PORT]";
    }

protected:
    void HandleSyncRequestImpl(Kernel::SharedPtr<Kernel::ServerSession> server_session) override;

    /**
     * Registers the functions in the service
     */
    template <size_t N>
    inline void Register(const FunctionInfo (&functions)[N]) {
        Register(functions, N);
    }

    void Register(const FunctionInfo* functions, size_t n);

    union {
        u32 raw;
        BitField<0, 8, u32> major;
        BitField<8, 8, u32> minor;
        BitField<16, 8, u32> build;
        BitField<24, 8, u32> revision;
    } version = {};

private:
    u32 max_sessions; ///< Maximum number of concurrent sessions that this service can handle.
    boost::container::flat_map<u32, FunctionInfo> m_functions;
};

/// Initialize ServiceManager
void Init();

/// Shutdown ServiceManager
void Shutdown();

/// Map of named ports managed by the kernel, which can be retrieved using the ConnectToPort SVC.
extern std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_kernel_named_ports;
/// Map of services registered with the "srv:" service, retrieved using GetServiceHandle.
extern std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_srv_services;

/// Adds a service to the services table
void AddService(Interface* interface_);

} // namespace