예제 #1
0
파일: gsp_gpu.cpp 프로젝트: citra-emu/citra
void GSP_GPU::WriteHWRegsWithMask(Kernel::HLERequestContext& ctx) {
    IPC::RequestParser rp(ctx, 0x2, 2, 4);
    u32 reg_addr = rp.Pop<u32>();
    u32 size = rp.Pop<u32>();

    std::vector<u8> src_data = rp.PopStaticBuffer();
    std::vector<u8> mask_data = rp.PopStaticBuffer();

    IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
    rb.Push(GSP::WriteHWRegsWithMask(reg_addr, size, src_data, mask_data));
}
예제 #2
0
파일: gsp_gpu.cpp 프로젝트: citra-emu/citra
void GSP_GPU::UnregisterInterruptRelayQueue(Kernel::HLERequestContext& ctx) {
    IPC::RequestParser rp(ctx, 0x14, 0, 0);

    SessionData* session_data = GetSessionData(ctx.Session());
    session_data->interrupt_event = nullptr;
    session_data->registered = false;

    IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
    rb.Push(RESULT_SUCCESS);

    LOG_DEBUG(Service_GSP, "called");
}
예제 #3
0
파일: file.cpp 프로젝트: Dragios/Citra
void File::Close(Kernel::HLERequestContext& ctx) {
    IPC::RequestParser rp(ctx, 0x0808, 0, 0);

    // TODO(Subv): Only close the backend if this client is the only one left.
    if (connected_sessions.size() > 1)
        LOG_WARNING(Service_FS, "Closing File backend but {} clients still connected",
                    connected_sessions.size());

    backend->Close();
    IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
    rb.Push(RESULT_SUCCESS);
}
예제 #4
0
파일: ptm.cpp 프로젝트: Dragios/Citra
void CheckNew3DS(IPC::RequestBuilder& rb) {
    const bool is_new_3ds = Settings::values.is_new_3ds;

    if (is_new_3ds) {
        LOG_CRITICAL(Service_PTM, "The option 'is_new_3ds' is enabled as part of the 'System' "
                                  "settings. Citra does not fully support New 3DS emulation yet!");
    }

    rb.Push(RESULT_SUCCESS);
    rb.Push(is_new_3ds);

    LOG_WARNING(Service_PTM, "(STUBBED) called isNew3DS = 0x{:08x}", static_cast<u32>(is_new_3ds));
}
예제 #5
0
파일: frd.cpp 프로젝트: Dragios/Citra
void Module::Interface::GetFriendAttributeFlags(Kernel::HLERequestContext& ctx) {
    IPC::RequestParser rp(ctx, 0x17, 1, 2);
    u32 count = rp.Pop<u32>();
    std::vector<u8> frd_keys = rp.PopStaticBuffer();
    ASSERT(frd_keys.size() == count * sizeof(FriendKey));

    // TODO:(mailwl) figure out AttributeFlag size and zero all buffer. Assume 1 byte
    std::vector<u8> buffer(1 * count, 0);
    IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
    rb.Push(RESULT_SUCCESS);
    rb.PushStaticBuffer(buffer, 0);

    LOG_WARNING(Service_FRD, "(STUBBED) called, count={}", count);
}
예제 #6
0
파일: frd.cpp 프로젝트: Dragios/Citra
void Module::Interface::GetFriendProfile(Kernel::HLERequestContext& ctx) {
    IPC::RequestParser rp(ctx, 0x15, 1, 2);
    u32 count = rp.Pop<u32>();
    std::vector<u8> frd_keys = rp.PopStaticBuffer();
    ASSERT(frd_keys.size() == count * sizeof(FriendKey));

    std::vector<u8> buffer(sizeof(Profile) * count, 0);

    IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
    rb.Push(RESULT_SUCCESS);
    rb.PushStaticBuffer(buffer, 0);

    LOG_WARNING(Service_FRD, "(STUBBED) called, count={}", count);
}
예제 #7
0
파일: gsp_gpu.cpp 프로젝트: citra-emu/citra
void GSP_GPU::InvalidateDataCache(Kernel::HLERequestContext& ctx) {
    IPC::RequestParser rp(ctx, 0x9, 2, 2);
    u32 address = rp.Pop<u32>();
    u32 size = rp.Pop<u32>();
    auto process = rp.PopObject<Kernel::Process>();

    // TODO(purpasmart96): Verify return header on HW

    IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
    rb.Push(RESULT_SUCCESS);

    LOG_DEBUG(Service_GSP, "(STUBBED) called address=0x{:08X}, size=0x{:08X}, process={}", address,
              size, process->process_id);
}
예제 #8
0
파일: frd.cpp 프로젝트: Dragios/Citra
void Module::Interface::GetFriendKeyList(Kernel::HLERequestContext& ctx) {
    IPC::RequestParser rp(ctx, 0x11, 2, 0);
    u32 unknown = rp.Pop<u32>();
    u32 frd_count = rp.Pop<u32>();

    std::vector<u8> buffer(sizeof(FriendKey) * frd_count, 0);

    IPC::RequestBuilder rb = rp.MakeBuilder(2, 2);
    rb.Push(RESULT_SUCCESS);
    rb.Push<u32>(0); // 0 friends
    rb.PushStaticBuffer(buffer, 0);

    LOG_WARNING(Service_FRD, "(STUBBED) called, unknown={}, frd_count={}", unknown, frd_count);
}
예제 #9
0
파일: file.cpp 프로젝트: Dragios/Citra
void File::Flush(Kernel::HLERequestContext& ctx) {
    IPC::RequestParser rp(ctx, 0x0809, 0, 0);

    IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);

    const FileSessionSlot* file = GetSessionData(ctx.Session());

    // Subfiles can not be flushed.
    if (file->subfile) {
        rb.Push(FileSys::ERROR_UNSUPPORTED_OPEN_FLAGS);
        return;
    }

    backend->Flush();
    rb.Push(RESULT_SUCCESS);
}
예제 #10
0
파일: frd.cpp 프로젝트: Dragios/Citra
void Module::Interface::GetMyScreenName(Kernel::HLERequestContext& ctx) {
    IPC::RequestParser rp(ctx, 0x9, 0, 0);
    IPC::RequestBuilder rb = rp.MakeBuilder(7, 0);

    struct ScreenName {
        std::array<char16_t, 12> name;
    };

    // TODO: (mailwl) get the name from config
    ScreenName screen_name{u"Citra"};

    rb.Push(RESULT_SUCCESS);
    rb.PushRaw(screen_name);

    LOG_WARNING(Service_FRD, "(STUBBED) called");
}
예제 #11
0
파일: y2r_u.cpp 프로젝트: emmauss/citra
static void SetSendingU(Interface* self) {
    // The helper should be passed by argument to the function
    IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x00110102);
    conversion.src_U.address = rp.Pop<u32>();
    conversion.src_U.image_size = rp.Pop<u32>();
    conversion.src_U.transfer_unit = rp.Pop<u32>();
    conversion.src_U.gap = rp.Pop<u32>();
    Kernel::Handle src_process_handle = rp.PopHandle();

    IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
    rb.Push(RESULT_SUCCESS);

    LOG_DEBUG(Service_Y2R, "called image_size=0x%08X, transfer_unit=%hu, transfer_stride=%hu, "
                           "src_process_handle=0x%08X",
              conversion.src_U.image_size, conversion.src_U.transfer_unit, conversion.src_U.gap,
              src_process_handle);
}
예제 #12
0
파일: ir_rst.cpp 프로젝트: Subv/citra
/**
 * IR::Initialize service function
 *  Inputs:
 *      1 : pad state update period in ms
 *      2 : bool output raw c-stick data
 */
static void Initialize(Interface* self) {
    IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x02, 2, 0);
    update_period = static_cast<int>(rp.Pop<u32>());
    raw_c_stick = rp.Pop<bool>();

    if (raw_c_stick)
        LOG_ERROR(Service_IR, "raw C-stick data is not implemented!");

    next_pad_index = 0;
    is_device_reload_pending.store(true);
    CoreTiming::ScheduleEvent(msToCycles(update_period), update_callback_id);

    IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
    rb.Push(RESULT_SUCCESS);

    LOG_DEBUG(Service_IR, "called. update_period=%d, raw_c_stick=%d", update_period, raw_c_stick);
}
예제 #13
0
파일: gsp_gpu.cpp 프로젝트: citra-emu/citra
void GSP_GPU::ReadHWRegs(Kernel::HLERequestContext& ctx) {
    IPC::RequestParser rp(ctx, 0x4, 2, 0);
    u32 reg_addr = rp.Pop<u32>();
    u32 input_size = rp.Pop<u32>();

    static constexpr u32 MaxReadSize = 0x80;
    u32 size = std::min(input_size, MaxReadSize);

    if ((reg_addr % 4) != 0 || reg_addr >= 0x420000) {
        IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
        rb.Push(ERR_REGS_OUTOFRANGE_OR_MISALIGNED);
        LOG_ERROR(Service_GSP, "Invalid address 0x{:08x}", reg_addr);
        return;
    }

    // size should be word-aligned
    if ((size % 4) != 0) {
        IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
        rb.Push(ERR_REGS_MISALIGNED);
        LOG_ERROR(Service_GSP, "Invalid size 0x{:08x}", size);
        return;
    }

    std::vector<u8> buffer(size);
    for (u32 offset = 0; offset < size; ++offset) {
        HW::Read<u8>(buffer[offset], REGS_BEGIN + reg_addr + offset);
    }

    IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
    rb.Push(RESULT_SUCCESS);
    rb.PushStaticBuffer(std::move(buffer), 0);
}
예제 #14
0
파일: file.cpp 프로젝트: Dragios/Citra
void File::SetSize(Kernel::HLERequestContext& ctx) {
    IPC::RequestParser rp(ctx, 0x0805, 2, 0);
    u64 size = rp.Pop<u64>();

    FileSessionSlot* file = GetSessionData(ctx.Session());

    IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);

    // SetSize can not be called on subfiles.
    if (file->subfile) {
        rb.Push(FileSys::ERROR_UNSUPPORTED_OPEN_FLAGS);
        return;
    }

    file->size = size;
    backend->SetSize(size);
    rb.Push(RESULT_SUCCESS);
}
예제 #15
0
파일: nfc.cpp 프로젝트: DaMan69/citra
void Module::Interface::StartTagScanning(Kernel::HLERequestContext& ctx) {
    IPC::RequestParser rp(ctx, 0x05, 1, 0); // 0x00050040
    u16 in_val = rp.Pop<u16>();

    ResultCode result = RESULT_SUCCESS;

    // TODO(shinyquagsire23): Implement NFC tag detection, for now stub result
    result = ResultCode(ErrCodes::CommandInvalidForState, ErrorModule::NFC,
                        ErrorSummary::InvalidState, ErrorLevel::Status);

    if (result == RESULT_SUCCESS) {
        nfc->nfc_tag_state = TagState::TagInRange;
        nfc->tag_in_range_event->Signal();
    }

    IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
    rb.Push(result);
    LOG_WARNING(Service_NFC, "(STUBBED) called, in_val=%04x", in_val);
}
예제 #16
0
파일: file.cpp 프로젝트: Dragios/Citra
void File::Write(Kernel::HLERequestContext& ctx) {
    IPC::RequestParser rp(ctx, 0x0803, 4, 2);
    u64 offset = rp.Pop<u64>();
    u32 length = rp.Pop<u32>();
    u32 flush = rp.Pop<u32>();
    auto& buffer = rp.PopMappedBuffer();
    LOG_TRACE(Service_FS, "Write {}: offset=0x{:x} length={}, flush=0x{:x}", GetName(), offset,
              length, flush);

    IPC::RequestBuilder rb = rp.MakeBuilder(2, 2);

    const FileSessionSlot* file = GetSessionData(ctx.Session());

    // Subfiles can not be written to
    if (file->subfile) {
        rb.Push(FileSys::ERROR_UNSUPPORTED_OPEN_FLAGS);
        rb.Push<u32>(0);
        rb.PushMappedBuffer(buffer);
        return;
    }

    std::vector<u8> data(length);
    buffer.Read(data.data(), 0, data.size());
    ResultVal<std::size_t> written = backend->Write(offset, data.size(), flush != 0, data.data());
    if (written.Failed()) {
        rb.Push(written.Code());
        rb.Push<u32>(0);
    } else {
        rb.Push(RESULT_SUCCESS);
        rb.Push<u32>(static_cast<u32>(*written));
    }
    rb.PushMappedBuffer(buffer);
}
예제 #17
0
파일: http_c.cpp 프로젝트: Dragios/Citra
void HTTP_C::InitializeConnectionSession(Kernel::HLERequestContext& ctx) {
    IPC::RequestParser rp(ctx, 0x8, 1, 2);
    const Context::Handle context_handle = rp.Pop<u32>();
    u32 pid = rp.PopPID();

    auto* session_data = GetSessionData(ctx.Session());
    ASSERT(session_data);

    if (session_data->initialized) {
        LOG_ERROR(Service_HTTP, "Tried to initialize an already initialized session");
        IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
        rb.Push(ERROR_STATE_ERROR);
        return;
    }

    // TODO(Subv): Check that the input PID matches the PID that created the context.
    auto itr = contexts.find(context_handle);
    if (itr == contexts.end()) {
        IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
        rb.Push(ResultCode(ErrCodes::ContextNotFound, ErrorModule::HTTP, ErrorSummary::InvalidState,
                           ErrorLevel::Permanent));
        return;
    }

    session_data->initialized = true;
    session_data->session_id = ++session_counter;
    // Bind the context to the current session.
    session_data->current_http_context = context_handle;

    IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
    rb.Push(RESULT_SUCCESS);
    LOG_DEBUG(Service_HTTP, "called, context_id={} pid={}", context_handle, pid);
}
예제 #18
0
파일: http_c.cpp 프로젝트: Dragios/Citra
void HTTP_C::CloseClientCertContext(Kernel::HLERequestContext& ctx) {
    IPC::RequestParser rp(ctx, 0x34, 1, 0);
    ClientCertContext::Handle cert_handle = rp.Pop<u32>();

    auto* session_data = GetSessionData(ctx.Session());
    ASSERT(session_data);

    if (client_certs.find(cert_handle) == client_certs.end()) {
        LOG_ERROR(Service_HTTP, "Command called with a unkown client cert handle {}", cert_handle);
        IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
        // This just return success without doing anything
        rb.Push(RESULT_SUCCESS);
        return;
    }

    if (client_certs[cert_handle].session_id != session_data->session_id) {
        LOG_ERROR(Service_HTTP, "called from another main session");
        IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
        // This just return success without doing anything
        rb.Push(RESULT_SUCCESS);
        return;
    }

    client_certs.erase(cert_handle);
    session_data->num_client_certs--;

    IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
    rb.Push(RESULT_SUCCESS);

    LOG_DEBUG(Service_HTTP, "called, cert_handle={}", cert_handle);
}
예제 #19
0
파일: file.cpp 프로젝트: Dragios/Citra
void File::OpenLinkFile(Kernel::HLERequestContext& ctx) {
    LOG_WARNING(Service_FS, "(STUBBED) File command OpenLinkFile {}", GetName());
    using Kernel::ClientSession;
    using Kernel::ServerSession;
    using Kernel::SharedPtr;
    IPC::RequestParser rp(ctx, 0x080C, 0, 0);
    IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
    auto sessions = system.Kernel().CreateSessionPair(GetName());
    auto server = std::get<SharedPtr<ServerSession>>(sessions);
    ClientConnected(server);

    FileSessionSlot* slot = GetSessionData(server);
    const FileSessionSlot* original_file = GetSessionData(ctx.Session());

    slot->priority = original_file->priority;
    slot->offset = 0;
    slot->size = backend->GetSize();
    slot->subfile = false;

    rb.Push(RESULT_SUCCESS);
    rb.PushMoveObjects(std::get<SharedPtr<ClientSession>>(sessions));
}
예제 #20
0
파일: http_c.cpp 프로젝트: Dragios/Citra
void HTTP_C::OpenClientCertContext(Kernel::HLERequestContext& ctx) {
    IPC::RequestParser rp(ctx, 0x32, 2, 4);
    u32 cert_size = rp.Pop<u32>();
    u32 key_size = rp.Pop<u32>();
    Kernel::MappedBuffer& cert_buffer = rp.PopMappedBuffer();
    Kernel::MappedBuffer& key_buffer = rp.PopMappedBuffer();

    auto* session_data = GetSessionData(ctx.Session());
    ASSERT(session_data);

    ResultCode result(RESULT_SUCCESS);

    if (!session_data->initialized) {
        LOG_ERROR(Service_HTTP, "Command called without Initialize");
        result = ERROR_STATE_ERROR;
    } else if (session_data->current_http_context) {
        LOG_ERROR(Service_HTTP, "Command called with a bound context");
        result = ERROR_NOT_IMPLEMENTED;
    } else if (session_data->num_client_certs >= 2) {
        LOG_ERROR(Service_HTTP, "tried to load more then 2 client certs");
        result = ERROR_TOO_MANY_CLIENT_CERTS;
    } else {
        ++client_certs_counter;
        client_certs[client_certs_counter].handle = client_certs_counter;
        client_certs[client_certs_counter].certificate.resize(cert_size);
        cert_buffer.Read(&client_certs[client_certs_counter].certificate[0], 0, cert_size);
        client_certs[client_certs_counter].private_key.resize(key_size);
        cert_buffer.Read(&client_certs[client_certs_counter].private_key[0], 0, key_size);
        client_certs[client_certs_counter].session_id = session_data->session_id;

        ++session_data->num_client_certs;
    }

    LOG_DEBUG(Service_HTTP, "called, cert_size {}, key_size {}", cert_size, key_size);
    IPC::RequestBuilder rb = rp.MakeBuilder(1, 4);
    rb.Push(result);
    rb.PushMappedBuffer(cert_buffer);
    rb.PushMappedBuffer(key_buffer);
}
예제 #21
0
파일: ptm.cpp 프로젝트: Dragios/Citra
void Module::Interface::GetStepHistory(Kernel::HLERequestContext& ctx) {
    IPC::RequestParser rp(ctx, 0xB, 3, 2);

    u32 hours = rp.Pop<u32>();
    u64 start_time = rp.Pop<u64>();
    auto& buffer = rp.PopMappedBuffer();
    ASSERT_MSG(sizeof(u16) * hours == buffer.GetSize(),
               "Buffer for steps count has incorrect size");

    // Stub: set zero steps count for every hour
    for (u32 i = 0; i < hours; ++i) {
        const u16_le steps_per_hour = 0;
        buffer.Write(&steps_per_hour, i * sizeof(u16), sizeof(u16));
    }

    IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
    rb.Push(RESULT_SUCCESS);
    rb.PushMappedBuffer(buffer);

    LOG_WARNING(Service_PTM, "(STUBBED) called, from time(raw): 0x{:x}, for {} hours", start_time,
                hours);
}
예제 #22
0
파일: file.cpp 프로젝트: Dragios/Citra
void File::OpenSubFile(Kernel::HLERequestContext& ctx) {
    IPC::RequestParser rp(ctx, 0x0801, 4, 0);
    s64 offset = rp.PopRaw<s64>();
    s64 size = rp.PopRaw<s64>();

    IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);

    const FileSessionSlot* original_file = GetSessionData(ctx.Session());

    if (original_file->subfile) {
        // OpenSubFile can not be called on a file which is already as subfile
        rb.Push(FileSys::ERROR_UNSUPPORTED_OPEN_FLAGS);
        return;
    }

    if (offset < 0 || size < 0) {
        rb.Push(FileSys::ERR_WRITE_BEYOND_END);
        return;
    }

    std::size_t end = offset + size;

    // TODO(Subv): Check for overflow and return ERR_WRITE_BEYOND_END

    if (end > original_file->size) {
        rb.Push(FileSys::ERR_WRITE_BEYOND_END);
        return;
    }

    using Kernel::ClientSession;
    using Kernel::ServerSession;
    using Kernel::SharedPtr;
    auto sessions = system.Kernel().CreateSessionPair(GetName());
    auto server = std::get<SharedPtr<ServerSession>>(sessions);
    ClientConnected(server);

    FileSessionSlot* slot = GetSessionData(server);
    slot->priority = original_file->priority;
    slot->offset = offset;
    slot->size = size;
    slot->subfile = true;

    rb.Push(RESULT_SUCCESS);
    rb.PushMoveObjects(std::get<SharedPtr<ClientSession>>(sessions));
}
예제 #23
0
파일: http_c.cpp 프로젝트: Dragios/Citra
void HTTP_C::CloseContext(Kernel::HLERequestContext& ctx) {
    IPC::RequestParser rp(ctx, 0x3, 1, 0);

    u32 context_handle = rp.Pop<u32>();

    LOG_WARNING(Service_HTTP, "(STUBBED) called, handle={}", context_handle);

    auto* session_data = GetSessionData(ctx.Session());
    ASSERT(session_data);

    if (!session_data->initialized) {
        LOG_ERROR(Service_HTTP, "Tried to close a context on an uninitialized session");
        IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
        rb.Push(ERROR_STATE_ERROR);
        return;
    }

    ASSERT_MSG(!session_data->current_http_context,
               "Unimplemented CloseContext on context-bound session");

    auto itr = contexts.find(context_handle);
    if (itr == contexts.end()) {
        // The real HTTP module just silently fails in this case.
        IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
        rb.Push(RESULT_SUCCESS);
        LOG_ERROR(Service_HTTP, "called, context {} not found", context_handle);
        return;
    }

    // TODO(Subv): What happens if you try to close a context that's currently being used?
    ASSERT(itr->second.state == RequestState::NotStarted);

    // TODO(Subv): Make sure that only the session that created the context can close it.

    contexts.erase(itr);
    session_data->num_http_contexts--;

    IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
    rb.Push(RESULT_SUCCESS);
}
예제 #24
0
파일: ir_rst.cpp 프로젝트: namkazt/citra
void IR_RST::GetHandles(Kernel::HLERequestContext& ctx) {
    IPC::RequestParser rp(ctx, 0x01, 0, 0);
    IPC::RequestBuilder rb = rp.MakeBuilder(1, 3);
    rb.Push(RESULT_SUCCESS);
    rb.PushMoveObjects(shared_memory, update_event);
}
예제 #25
0
파일: http_c.cpp 프로젝트: Dragios/Citra
void HTTP_C::OpenDefaultClientCertContext(Kernel::HLERequestContext& ctx) {
    IPC::RequestParser rp(ctx, 0x33, 1, 0);
    u8 cert_id = rp.Pop<u8>();

    auto* session_data = GetSessionData(ctx.Session());
    ASSERT(session_data);

    if (!session_data->initialized) {
        LOG_ERROR(Service_HTTP, "Command called without Initialize");
        IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
        rb.Push(ERROR_STATE_ERROR);
        return;
    }

    if (session_data->current_http_context) {
        LOG_ERROR(Service_HTTP, "Command called with a bound context");
        IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
        rb.Push(ERROR_NOT_IMPLEMENTED);
        return;
    }

    if (session_data->num_client_certs >= 2) {
        LOG_ERROR(Service_HTTP, "tried to load more then 2 client certs");
        IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
        rb.Push(ERROR_TOO_MANY_CLIENT_CERTS);
        return;
    }

    constexpr u8 default_cert_id = 0x40;
    if (cert_id != default_cert_id) {
        LOG_ERROR(Service_HTTP, "called with invalid cert_id {}", cert_id);
        IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
        rb.Push(ERROR_WRONG_CERT_ID);
        return;
    }

    if (!ClCertA.init) {
        LOG_ERROR(Service_HTTP, "called but ClCertA is missing");
        IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
        rb.Push(static_cast<ResultCode>(-1));
        return;
    }

    const auto& it = std::find_if(client_certs.begin(), client_certs.end(),
                                  [default_cert_id, &session_data](const auto& i) {
                                      return default_cert_id == i.second.cert_id &&
                                             session_data->session_id == i.second.session_id;
                                  });

    if (it != client_certs.end()) {
        IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
        rb.Push(RESULT_SUCCESS);
        rb.Push<u32>(it->first);

        LOG_DEBUG(Service_HTTP, "called, with an already loaded cert_id={}", cert_id);
        return;
    }

    ++client_certs_counter;
    client_certs[client_certs_counter].handle = client_certs_counter;
    client_certs[client_certs_counter].certificate = ClCertA.certificate;
    client_certs[client_certs_counter].private_key = ClCertA.private_key;
    client_certs[client_certs_counter].session_id = session_data->session_id;
    ++session_data->num_client_certs;

    IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
    rb.Push(RESULT_SUCCESS);
    rb.Push<u32>(client_certs_counter);

    LOG_DEBUG(Service_HTTP, "called, cert_id={}", cert_id);
}
예제 #26
0
파일: http_c.cpp 프로젝트: Dragios/Citra
void HTTP_C::AddPostDataAscii(Kernel::HLERequestContext& ctx) {
    IPC::RequestParser rp(ctx, 0x12, 3, 4);
    const u32 context_handle = rp.Pop<u32>();
    const u32 name_size = rp.Pop<u32>();
    const u32 value_size = rp.Pop<u32>();
    const std::vector<u8> name_buffer = rp.PopStaticBuffer();
    Kernel::MappedBuffer& value_buffer = rp.PopMappedBuffer();

    // Copy the name_buffer into a string without the \0 at the end
    const std::string name(name_buffer.begin(), name_buffer.end() - 1);

    // Copy the value_buffer into a string without the \0 at the end
    std::string value(value_size - 1, '\0');
    value_buffer.Read(&value[0], 0, value_size - 1);

    auto* session_data = GetSessionData(ctx.Session());
    ASSERT(session_data);

    if (!session_data->initialized) {
        LOG_ERROR(Service_HTTP, "Tried to add post data on an uninitialized session");
        IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
        rb.Push(ERROR_STATE_ERROR);
        rb.PushMappedBuffer(value_buffer);
        return;
    }

    // This command can only be called with a bound context
    if (!session_data->current_http_context) {
        LOG_ERROR(Service_HTTP, "Command called without a bound context");

        IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
        rb.Push(ResultCode(ErrorDescription::NotImplemented, ErrorModule::HTTP,
                           ErrorSummary::Internal, ErrorLevel::Permanent));
        rb.PushMappedBuffer(value_buffer);
        return;
    }

    if (session_data->current_http_context != context_handle) {
        LOG_ERROR(Service_HTTP,
                  "Tried to add post data on a mismatched session input context={} session "
                  "context={}",
                  context_handle, *session_data->current_http_context);
        IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
        rb.Push(ERROR_STATE_ERROR);
        rb.PushMappedBuffer(value_buffer);
        return;
    }

    auto itr = contexts.find(context_handle);
    ASSERT(itr != contexts.end());

    if (itr->second.state != RequestState::NotStarted) {
        LOG_ERROR(Service_HTTP,
                  "Tried to add post data on a context that has already been started.");
        IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
        rb.Push(ResultCode(ErrCodes::InvalidRequestState, ErrorModule::HTTP,
                           ErrorSummary::InvalidState, ErrorLevel::Permanent));
        rb.PushMappedBuffer(value_buffer);
        return;
    }

    ASSERT(std::find_if(itr->second.post_data.begin(), itr->second.post_data.end(),
                        [&name](const Context::PostData& m) -> bool { return m.name == name; }) ==
           itr->second.post_data.end());

    itr->second.post_data.emplace_back(name, value);

    IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
    rb.Push(RESULT_SUCCESS);
    rb.PushMappedBuffer(value_buffer);

    LOG_DEBUG(Service_HTTP, "called, name={}, value={}, context_handle={}", name, value,
              context_handle);
}
예제 #27
0
파일: http_c.cpp 프로젝트: Dragios/Citra
void HTTP_C::CreateContext(Kernel::HLERequestContext& ctx) {
    IPC::RequestParser rp(ctx, 0x2, 2, 2);
    const u32 url_size = rp.Pop<u32>();
    RequestMethod method = rp.PopEnum<RequestMethod>();
    Kernel::MappedBuffer& buffer = rp.PopMappedBuffer();

    // Copy the buffer into a string without the \0 at the end of the buffer
    std::string url(url_size, '\0');
    buffer.Read(&url[0], 0, url_size - 1);

    LOG_DEBUG(Service_HTTP, "called, url_size={}, url={}, method={}", url_size, url,
              static_cast<u32>(method));

    auto* session_data = GetSessionData(ctx.Session());
    ASSERT(session_data);

    if (!session_data->initialized) {
        LOG_ERROR(Service_HTTP, "Tried to create a context on an uninitialized session");
        IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
        rb.Push(ERROR_STATE_ERROR);
        rb.PushMappedBuffer(buffer);
        return;
    }

    // This command can only be called without a bound session.
    if (session_data->current_http_context) {
        LOG_ERROR(Service_HTTP, "Command called with a bound context");

        IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
        rb.Push(ResultCode(ErrorDescription::NotImplemented, ErrorModule::HTTP,
                           ErrorSummary::Internal, ErrorLevel::Permanent));
        rb.PushMappedBuffer(buffer);
        return;
    }

    static constexpr std::size_t MaxConcurrentHTTPContexts = 8;
    if (session_data->num_http_contexts >= MaxConcurrentHTTPContexts) {
        // There can only be 8 HTTP contexts open at the same time for any particular session.
        LOG_ERROR(Service_HTTP, "Tried to open too many HTTP contexts");

        IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
        rb.Push(ResultCode(ErrCodes::TooManyContexts, ErrorModule::HTTP, ErrorSummary::InvalidState,
                           ErrorLevel::Permanent));
        rb.PushMappedBuffer(buffer);
        return;
    }

    if (method == RequestMethod::None || static_cast<u32>(method) >= TotalRequestMethods) {
        LOG_ERROR(Service_HTTP, "invalid request method={}", static_cast<u32>(method));

        IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
        rb.Push(ResultCode(ErrCodes::InvalidRequestMethod, ErrorModule::HTTP,
                           ErrorSummary::InvalidState, ErrorLevel::Permanent));
        rb.PushMappedBuffer(buffer);
        return;
    }

    contexts.emplace(++context_counter, Context());
    contexts[context_counter].url = std::move(url);
    contexts[context_counter].method = method;
    contexts[context_counter].state = RequestState::NotStarted;
    // TODO(Subv): Find a correct default value for this field.
    contexts[context_counter].socket_buffer_size = 0;
    contexts[context_counter].handle = context_counter;
    contexts[context_counter].session_id = session_data->session_id;

    session_data->num_http_contexts++;

    IPC::RequestBuilder rb = rp.MakeBuilder(2, 2);
    rb.Push(RESULT_SUCCESS);
    rb.Push<u32>(context_counter);
    rb.PushMappedBuffer(buffer);
}