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::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 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); }