Skip to content

Instantly share code, notes, and snippets.

@sajattack
Created August 16, 2021 09:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sajattack/801c32e3e9e61c12c28858133e21fb8b to your computer and use it in GitHub Desktop.
Save sajattack/801c32e3e9e61c12c28858133e21fb8b to your computer and use it in GitHub Desktop.
psp-tls-downloader
#![no_std]
#![no_main]
extern crate alloc;
use psp::sys;
use drogue_tls::blocking::*;
use drogue_network::addr::HostSocketAddr;
use drogue_network::dns::Dns;
use drogue_network::dns::AddrType;
use rand_chacha::ChaCha20Rng;
use rand_chacha::rand_core::SeedableRng;
psp::module!("tls-weather", 1, 1);
mod net;
#[no_mangle]
fn psp_main() {
psp::enable_home_button();
unsafe {
load_modules();
init();
psp::sys::sceNetApctlConnect(1);
loop {
let mut state: psp::sys::ApctlState = core::mem::zeroed();
psp::sys::sceNetApctlGetState(&mut state);
if let psp::sys::ApctlState::GotIp = state {
break;
}
psp::sys::sceKernelDelayThread(50_000);
}
}
download_url("https://paulsajna.com/resume.pdf", "ms0:/PSP/GAME/tls-downloader/resume.pdf");
}
fn download_url(url: &str, filename: &str) {
let (_protocol, rest) = url.split_once("://").unwrap();
let (hostname, path) = rest.split_once("/").unwrap();
let socket = net::Socket::open().expect("failed to open socket");
let dns_resolver = net::DnsResolver::new();
let addr = dns_resolver.gethostbyname(hostname, AddrType::IPv4).expect("dns failed");
socket.connect(HostSocketAddr::new(addr, 443)).unwrap();
let mut seed: u64 = 0;
unsafe {
sys::sceRtcGetCurrentTick(&mut seed as *mut u64);
}
let rng = ChaCha20Rng::seed_from_u64(seed);
let mut record_buffer = [0u8; 32768];
let tls_context = TlsContext::new(rng, &mut record_buffer).with_server_name(hostname);
let mut tls: TlsConnection<ChaCha20Rng, net::Socket, Aes128GcmSha256> =
TlsConnection::new(tls_context, socket);
tls.open().expect("error establishing TLS connection");
let get_req = alloc::format!("GET /{} HTTP/1.1\r\nHost: {}\r\nUser-Agent: A fucking PSP!\r\n\r\n", path, hostname);
tls.write(get_req.as_bytes()).expect("error writing data");
let mut rx_buf = [0u8; 16384];
let sz_read = tls.read(&mut rx_buf).expect("error reading header");
// this code is brittle af
let packet1 = unsafe { alloc::string::String::from_utf8_unchecked(rx_buf.to_vec()) };
let header_end = packet1.find("\r\n\r\n").unwrap()+4;
let temp = packet1.split_once("Content-Length: ").unwrap();
let content_length_str = temp.1.split_once("\r\n").unwrap().0;
let content_length = content_length_str.parse::<usize>().expect("parse content_length error");
psp::dprintln!("file size: {}", content_length);
let file_cstr = alloc::string::String::from(filename) + "\0";
let fd = unsafe { sys::sceIoOpen(file_cstr.as_bytes().as_ptr(), sys::IoOpenFlags::CREAT | sys::IoOpenFlags::RD_WR, 0o777) };
unsafe { sys::sceIoWrite(fd, rx_buf[header_end..sz_read].as_ptr() as *const _, sz_read-header_end) };
let mut size_read = sz_read-header_end;
psp::dprintln!("read {}/{} bytes", size_read, content_length);
while size_read < content_length - rx_buf.len() {
let sz = tls.read(&mut rx_buf).expect("error reading data");
unsafe {
sys::sceIoWrite(fd, rx_buf.as_ptr() as *const _, sz);
}
size_read += sz;
psp::dprintln!("read {}/{} bytes", size_read, content_length);
}
let rem = content_length - size_read;
let sz = tls.read(&mut rx_buf).expect("error reading remainder");
unsafe {
sys::sceIoWrite(fd, rx_buf.as_ptr() as *const _, rem);
}
size_read += sz;
psp::dprintln!("read {}/{} bytes", size_read, content_length);
unsafe { sys::sceIoClose(fd) };
}
unsafe fn load_modules() {
psp::sys::sceUtilityLoadNetModule(psp::sys::NetModule::NetCommon);
psp::sys::sceUtilityLoadNetModule(psp::sys::NetModule::NetInet);
}
unsafe fn init() {
psp::sys::sceNetInit(0x20000, 0x20, 0x1000, 0x20, 0x1000);
psp::sys::sceNetInetInit();
psp::sys::sceNetResolverInit();
psp::sys::sceNetApctlInit(0x1600, 42);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment