summaryrefslogtreecommitdiffstats
path: root/src/core/hle/kernel/server_session.h
blob: 09b835ff85d21807740fb0d7cbcd05750c813d6a (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
163
164
// Copyright 2014 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.

#pragma once

#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "core/hle/kernel/object.h"
#include "core/hle/kernel/wait_object.h"
#include "core/hle/result.h"

namespace Kernel {

class ClientPort;
class ClientSession;
class HLERequestContext;
class KernelCore;
class ServerSession;
class Session;
class SessionRequestHandler;
class Thread;

/**
 * Kernel object representing the server endpoint of an IPC session. Sessions are the basic CTR-OS
 * primitive for communication between different processes, and are used to implement service calls
 * to the various system services.
 *
 * To make a service call, the client must write the command header and parameters to the buffer
 * located at offset 0x80 of the TLS (Thread-Local Storage) area, then execute a SendSyncRequest
 * SVC call with its ClientSession handle. The kernel will read the command header, using it to
 * marshall the parameters to the process at the server endpoint of the session.
 * After the server replies to the request, the response is marshalled back to the caller's
 * TLS buffer and control is transferred back to it.
 */
class ServerSession final : public WaitObject {
public:
    std::string GetTypeName() const override {
        return "ServerSession";
    }

    std::string GetName() const override {
        return name;
    }

    static const HandleType HANDLE_TYPE = HandleType::ServerSession;
    HandleType GetHandleType() const override {
        return HANDLE_TYPE;
    }

    Session* GetParent() {
        return parent.get();
    }

    const Session* GetParent() const {
        return parent.get();
    }

    using SessionPair = std::pair<SharedPtr<ServerSession>, SharedPtr<ClientSession>>;

    /**
     * Creates a pair of ServerSession and an associated ClientSession.
     * @param kernel      The kernal instance to create the session pair under.
     * @param name        Optional name of the ports.
     * @param client_port Optional The ClientPort that spawned this session.
     * @return The created session tuple
     */
    static SessionPair CreateSessionPair(KernelCore& kernel, const std::string& name = "Unknown",
                                         SharedPtr<ClientPort> client_port = nullptr);

    /**
     * Sets the HLE handler for the session. This handler will be called to service IPC requests
     * instead of the regular IPC machinery. (The regular IPC machinery is currently not
     * implemented.)
     */
    void SetHleHandler(std::shared_ptr<SessionRequestHandler> hle_handler_) {
        hle_handler = std::move(hle_handler_);
    }

    /**
     * Handle a sync request from the emulated application.
     * @param thread Thread that initiated the request.
     * @returns ResultCode from the operation.
     */
    ResultCode HandleSyncRequest(SharedPtr<Thread> thread);

    bool ShouldWait(const Thread* thread) const override;

    void Acquire(Thread* thread) override;

    /// Called when a client disconnection occurs.
    void ClientDisconnected();

    /// Adds a new domain request handler to the collection of request handlers within
    /// this ServerSession instance.
    void AppendDomainRequestHandler(std::shared_ptr<SessionRequestHandler> handler);

    /// Retrieves the total number of domain request handlers that have been
    /// appended to this ServerSession instance.
    std::size_t NumDomainRequestHandlers() const;

    /// Returns true if the session has been converted to a domain, otherwise False
    bool IsDomain() const {
        return !IsSession();
    }

    /// Returns true if this session has not been converted to a domain, otherwise false.
    bool IsSession() const {
        return domain_request_handlers.empty();
    }

    /// Converts the session to a domain at the end of the current command
    void ConvertToDomain() {
        convert_to_domain = true;
    }

private:
    explicit ServerSession(KernelCore& kernel);
    ~ServerSession() override;

    /**
     * Creates a server session. The server session can have an optional HLE handler,
     * which will be invoked to handle the IPC requests that this session receives.
     * @param kernel The kernel instance to create this server session under.
     * @param name Optional name of the server session.
     * @return The created server session
     */
    static ResultVal<SharedPtr<ServerSession>> Create(KernelCore& kernel,
                                                      std::string name = "Unknown");

    /// Handles a SyncRequest to a domain, forwarding the request to the proper object or closing an
    /// object handle.
    ResultCode HandleDomainSyncRequest(Kernel::HLERequestContext& context);

    /// The parent session, which links to the client endpoint.
    std::shared_ptr<Session> parent;

    /// This session's HLE request handler (applicable when not a domain)
    std::shared_ptr<SessionRequestHandler> hle_handler;

    /// This is the list of domain request handlers (after conversion to a domain)
    std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers;

    /// List of threads that are pending a response after a sync request. This list is processed in
    /// a LIFO manner, thus, the last request will be dispatched first.
    /// TODO(Subv): Verify if this is indeed processed in LIFO using a hardware test.
    std::vector<SharedPtr<Thread>> pending_requesting_threads;

    /// Thread whose request is currently being handled. A request is considered "handled" when a
    /// response is sent via svcReplyAndReceive.
    /// TODO(Subv): Find a better name for this.
    SharedPtr<Thread> currently_handling;

    /// When set to True, converts the session to a domain at the end of the command
    bool convert_to_domain{};

    /// The name of this session (optional)
    std::string name;
};

} // namespace Kernel