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)); }
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"); }
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); }
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)); }
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); }
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); }
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); }
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); }
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); }
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"); }
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); }
/** * 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); }
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); }
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); }
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); }
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); }
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); }
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); }
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)); }
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); }
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); }
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)); }
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); }
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); }
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); }
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); }
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); }