Created
August 13, 2021 07:29
-
-
Save sajattack/6abab634c5f35a242dbf5e4f43b88f56 to your computer and use it in GitHub Desktop.
tls-weather
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#![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); | |
} | |
} | |
let (sz, buf) = get_url("https://www.victoriaweather.ca/stations/UVicSci/current.xml").unwrap(); | |
let mut text = unsafe { alloc::string::String::from_utf8_unchecked(buf[..sz].to_vec()) }; | |
text = text.replace("\r", ""); | |
psp::dprintln!("{}", text); | |
} | |
/// takes a url such as https://www.victoriaweather.ca/stations/UVicSci/current.xml | |
fn get_url(url: &str) -> Result<(usize, [u8; 8192]), ()> { | |
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; 8192]; | |
tls.read(&mut rx_buf).expect("error reading header"); | |
let sz = tls.read(&mut rx_buf).expect("error reading data"); | |
Ok((sz, rx_buf)) | |
} | |
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); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use psp::sys; | |
use drogue_tls::TlsError; | |
use drogue_network::addr::*; | |
use heapless::String; | |
use heapless::consts::U256; | |
use core::ffi::c_void; | |
#[derive(Clone, Copy)] | |
#[repr(C)] | |
pub struct Socket(i32); | |
impl Socket { | |
pub fn open() -> Result<Socket,()> { | |
let sock = unsafe { sys::sceNetInetSocket(netc::AF_INET as i32, netc::SOCK_STREAM, 0) }; | |
if sock < 0 { | |
Err(()) | |
} else { | |
Ok(Socket(sock)) | |
} | |
} | |
pub fn connect(&self, remote: HostSocketAddr) -> Result<(), ()> { | |
match remote.as_socket_addr() { | |
SocketAddr::V4(v4) => { | |
let octets = v4.ip().octets(); | |
let sin_addr = u32::from_le_bytes(octets); | |
let port = v4.port().to_be(); | |
let sockaddr_in = netc::sockaddr_in { | |
sin_len: core::mem::size_of::<netc::sockaddr_in>() as u8, | |
sin_family: netc::AF_INET, | |
sin_port: port, | |
sin_addr: netc::in_addr(sin_addr), | |
sin_zero: [0u8; 8], | |
}; | |
let sockaddr = unsafe { core::mem::transmute::<netc::sockaddr_in, netc::sockaddr>(sockaddr_in) }; | |
if unsafe { sys::sceNetInetConnect(self.0, &sockaddr, core::mem::size_of::<netc::sockaddr_in>() as u32) } < 0 { | |
unsafe { psp::dprintln!("0x{:08x}", sys::sceNetInetGetErrno()); } | |
Err(()) | |
} else { | |
Ok(()) | |
} | |
} | |
SocketAddr::V6(_) => { | |
Err(()) | |
} | |
} | |
} | |
fn _read(self, buf: &mut [u8]) -> Result<usize, ()> { | |
let result = unsafe { sys::sceNetInetRecv(self.0, buf.as_mut_ptr() as *mut c_void, buf.len(), 0) }; | |
if (result as i32) < 0 { | |
Err(()) | |
} else { | |
Ok(result as usize) | |
} | |
} | |
fn _write(&self, buf: &[u8]) -> Result<usize, ()> { | |
let result = unsafe { sys::sceNetInetSend(self.0, buf.as_ptr() as *const c_void, buf.len(), 0) }; | |
if (result as i32) < 0 { | |
Err(()) | |
} else { | |
Ok(result as usize) | |
} | |
} | |
} | |
impl drogue_tls::traits::Read for Socket { | |
fn read<'m>(&'m mut self, buf: &'m mut [u8]) -> Result<usize, TlsError> { | |
self._read(buf).map_err(|_| TlsError::InternalError) | |
} | |
} | |
impl drogue_tls::traits::Write for Socket { | |
fn write<'m>(&'m mut self, buf: &'m [u8]) -> Result<usize, TlsError> { | |
self._write(buf).map_err(|_| TlsError::InternalError) | |
} | |
} | |
pub struct DnsResolver; | |
impl DnsResolver { | |
pub fn new() -> DnsResolver { | |
DnsResolver | |
} | |
} | |
impl drogue_network::dns::Dns for DnsResolver { | |
type Error = drogue_network::dns::DnsError; | |
fn gethostbyname(&self, hostname: &str, addr_type: drogue_network::dns::AddrType) -> Result<HostAddr, Self::Error> { | |
match addr_type { | |
drogue_network::dns::AddrType::IPv4 => { | |
let mut dns_buf = [0u8; 1024]; | |
let mut rid: i32 = 0; | |
let hostname = alloc::string::String::from(hostname) + "\0"; | |
let result = unsafe { sys::sceNetResolverCreate(&mut rid as *mut _ as *mut i32, &mut dns_buf as *mut _ as *mut _, dns_buf.len() as u32) }; | |
if result < 0 { | |
psp::dprintln!("Create Error: {:x}", result); | |
return Err(drogue_network::dns::DnsError::NoSuchHost); | |
} | |
let mut in_addr: netc::in_addr = unsafe { core::mem::zeroed() }; | |
let result = unsafe { sys::sceNetResolverStartNtoA(rid, hostname.as_bytes().as_ptr(), &mut in_addr, 5, 5) }; | |
if result < 0 { | |
psp::dprintln!("NtoA Error: {:x}", result); | |
return Err(drogue_network::dns::DnsError::NoSuchHost); | |
} else { | |
let octets = u32::to_le_bytes(in_addr.0); | |
unsafe { sys::sceNetResolverDelete(rid); } | |
Ok(HostAddr::new(IpAddr::V4(Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3])), None)) | |
} | |
} | |
_ => Err(drogue_network::dns::DnsError::UnsupportedAddressType) | |
} | |
} | |
fn gethostbyaddr(&self, addr: IpAddr) -> Result<String<U256>, Self::Error> { | |
let mut dns_buf = [0u8; 1024]; | |
let mut hostname_buf = heapless::Vec::<_, U256>::new(); | |
let hostname: heapless::String<U256>; | |
let mut rid: i32 = 0; | |
if unsafe { sys::sceNetResolverCreate(&mut rid as *mut _ as *mut i32, &mut dns_buf[0] as *mut u8 as *mut _, dns_buf.len() as u32) } < 0 { | |
return Err(drogue_network::dns::DnsError::NoSuchHost); | |
} | |
match addr { | |
IpAddr::V6(_) => { | |
return Err(drogue_network::dns::DnsError::UnsupportedAddressType); | |
}, | |
IpAddr::V4(v4) => { | |
let octets = v4.octets(); | |
let ipv4addr = u32::from_le_bytes(octets); | |
let result = unsafe { sys::sceNetResolverStartAtoN(rid, ipv4addr as *const u32 as *const netc::in_addr, hostname_buf.as_mut_ptr(), hostname_buf.len() as u32, 5, 5) }; | |
if result < 0 { | |
return Err(drogue_network::dns::DnsError::NoSuchHost); | |
} else { | |
unsafe { | |
hostname = String::from_utf8_unchecked(hostname_buf); | |
} | |
} | |
unsafe { sys::sceNetResolverDelete(rid); } | |
Ok(hostname) | |
} | |
} | |
} | |
} | |
#[allow(nonstandard_style)] | |
pub mod netc { | |
pub const AF_INET: u8 = 2; | |
pub const SOCK_STREAM: i32 = 1; | |
// pub type sa_family_t = u8; | |
pub use psp::sys::in_addr; | |
pub use psp::sys::sockaddr; | |
#[repr(C)] | |
//#[derive(Copy, Clone)] | |
pub struct sockaddr_in { | |
pub sin_len: u8, | |
pub sin_family: u8, | |
pub sin_port: u16, | |
pub sin_addr: in_addr, | |
pub sin_zero: [u8; 8] | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment