diff --git a/openssl/Cargo.lock b/openssl/Cargo.lock index a495041..07af0f6 100644 --- a/openssl/Cargo.lock +++ b/openssl/Cargo.lock @@ -2,8 +2,8 @@ name = "steven_openssl" version = "0.0.1" dependencies = [ - "libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -16,11 +16,10 @@ dependencies = [ ] [[package]] -name = "gcc" -version = "0.3.13" +name = "gdi32-sys" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "advapi32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -29,6 +28,11 @@ name = "libc" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "libc" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "libressl-pnacl-sys" version = "2.1.6" @@ -39,13 +43,14 @@ dependencies = [ [[package]] name = "openssl-sys" -version = "0.6.5" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gcc 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "gdi32-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "libressl-pnacl-sys 2.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "user32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -79,6 +84,15 @@ dependencies = [ "rand 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "user32-sys" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "winapi" version = "0.2.3" diff --git a/openssl/src/lib.rs b/openssl/src/lib.rs index 8b30da4..78857f7 100644 --- a/openssl/src/lib.rs +++ b/openssl/src/lib.rs @@ -1,3 +1,4 @@ +#![feature(unique)] #![allow(dead_code)] extern crate libc; use std::mem; @@ -54,7 +55,7 @@ extern { } pub struct EVPCipher { - internal: *mut EVP_CIPHER_CTX, + internal: ptr::Unique, block_size: usize, } @@ -62,17 +63,17 @@ pub struct EVPCipher { impl EVPCipher { pub fn new(key: &Vec, iv: &Vec, decrypt: bool) -> EVPCipher { unsafe { - let e = EVPCipher { - internal: EVP_CIPHER_CTX_new(), + let mut e = EVPCipher { + internal: ptr::Unique::new(EVP_CIPHER_CTX_new()), block_size: EVP_CIPHER_block_size(EVP_aes_128_cfb8()) as usize, }; - EVP_CIPHER_CTX_init(e.internal); + EVP_CIPHER_CTX_init(e.internal.get_mut()); if decrypt { - if EVP_DecryptInit_ex(e.internal, EVP_aes_128_cfb8(), ptr::null_mut(), key.as_ptr(), iv.as_ptr()) == 0 { + if EVP_DecryptInit_ex(e.internal.get_mut(), EVP_aes_128_cfb8(), ptr::null_mut(), key.as_ptr(), iv.as_ptr()) == 0 { panic!("Init error"); } } else { - if EVP_EncryptInit_ex(e.internal, EVP_aes_128_cfb8(), ptr::null_mut(), key.as_ptr(), iv.as_ptr()) == 0 { + if EVP_EncryptInit_ex(e.internal.get_mut(), EVP_aes_128_cfb8(), ptr::null_mut(), key.as_ptr(), iv.as_ptr()) == 0 { panic!("Init error"); } } @@ -84,7 +85,7 @@ impl EVPCipher { unsafe { let mut out = Vec::with_capacity(data.len()); let mut out_len: libc::c_int = 0; - if EVP_DecryptUpdate(self.internal, out.as_mut_ptr(), &mut out_len, data.as_ptr(), data.len() as libc::c_int) == 0 { + if EVP_DecryptUpdate(self.internal.get_mut(), out.as_mut_ptr(), &mut out_len, data.as_ptr(), data.len() as libc::c_int) == 0 { panic!("Decrypt error") } out.set_len(out_len as usize); @@ -96,7 +97,7 @@ impl EVPCipher { unsafe { let mut out = Vec::with_capacity(data.len()); let mut out_len: libc::c_int = 0; - if EVP_EncryptUpdate(self.internal, out.as_mut_ptr(), &mut out_len, data.as_ptr(), data.len() as libc::c_int) == 0 { + if EVP_EncryptUpdate(self.internal.get_mut(), out.as_mut_ptr(), &mut out_len, data.as_ptr(), data.len() as libc::c_int) == 0 { panic!("Encrypt error") } out.set_len(out_len as usize); @@ -109,8 +110,8 @@ impl EVPCipher { impl Drop for EVPCipher { fn drop(&mut self) { unsafe { - EVP_CIPHER_CTX_cleanup(self.internal); - EVP_CIPHER_CTX_free(self.internal); + EVP_CIPHER_CTX_cleanup(self.internal.get_mut()); + EVP_CIPHER_CTX_free(self.internal.get_mut()); } } } diff --git a/src/main.rs b/src/main.rs index 72e0e2e..205eaf0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -52,6 +52,8 @@ pub mod chunk_builder; use std::sync::{Arc, RwLock, Mutex}; use std::marker::PhantomData; +use std::thread; +use std::sync::mpsc; const CL_BRAND: console::CVar = console::CVar { ty: PhantomData, @@ -73,6 +75,51 @@ pub struct Game { server: server::Server, chunk_builder: chunk_builder::ChunkBuilder, + + connect_reply: Option>>, +} + +impl Game { + pub fn connect_to(&mut self, address: &str) { + let (tx, rx) = mpsc::channel(); + self.connect_reply = Some(rx); + let address = address.to_owned(); + let resources = self.resource_manager.clone(); + thread::spawn(move || { + tx.send(server::Server::connect(resources, &address)).unwrap(); + }); + } + + pub fn tick(&mut self) { + let mut clear_reply = false; + if let Some(ref recv) = self.connect_reply { + if let Ok(server) = recv.try_recv() { + clear_reply = true; + match server { + Ok(val) => { + self.screen_sys.pop_screen(); + self.server = val; + }, + Err(err) => { + let msg = match err { + protocol::Error::Disconnect(val) => val, + err => { + let mut msg = format::TextComponent::new(&format!("{}", err)); + msg.modifier.color = Some(format::Color::Red); + format::Component::Text(msg) + }, + }; + self.screen_sys.replace_screen(Box::new(screen::ServerList::new( + Some(msg) + ))); + } + } + } + } + if clear_reply { + self.connect_reply = None; + } + } } fn main() { @@ -135,6 +182,7 @@ fn main() { should_close: false, mouse_pos: (0, 0), chunk_builder: chunk_builder::ChunkBuilder::new(textures), + connect_reply: None, }; while !game.should_close { @@ -157,6 +205,7 @@ fn main() { game.renderer.camera.yaw = 0.0; } + game.tick(); game.server.tick(); game.chunk_builder.tick(&mut game.server.world, &mut game.renderer); diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs index dbd9572..6549828 100644 --- a/src/protocol/mod.rs +++ b/src/protocol/mod.rs @@ -631,6 +631,7 @@ pub enum State { #[derive(Debug)] pub enum Error { Err(String), + Disconnect(format::Component), IOError(io::Error), } @@ -644,6 +645,7 @@ impl ::std::error::Error for Error { fn description(&self) -> &str { match *self { Error::Err(ref val) => &val[..], + Error::Disconnect(_) => "Disconnect", Error::IOError(ref e) => e.description(), } } @@ -653,6 +655,7 @@ impl ::std::fmt::Display for Error { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { match *self { Error::Err(ref val) => write!(f, "protocol error: {}", val), + Error::Disconnect(ref val) => write!(f, "{}", val), Error::IOError(ref e) => e.fmt(f), } } @@ -660,10 +663,10 @@ impl ::std::fmt::Display for Error { pub struct Conn { stream: TcpStream, - host: String, - port: u16, + pub host: String, + pub port: u16, direction: Direction, - state: State, + pub state: State, cipher: Option, diff --git a/src/render/mod.rs b/src/render/mod.rs index 364a3b0..73dc185 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -317,6 +317,10 @@ impl Renderer { self.ui.tick(width, height); } + pub fn clear_chunks(&mut self) { + self.chunks.clear(); + } + fn ensure_element_buffer(&mut self, size: usize) { if self.element_buffer_size < size { let (data, ty) = self::generate_element_buffer(size); diff --git a/src/screen/connecting.rs b/src/screen/connecting.rs new file mode 100644 index 0000000..14bda45 --- /dev/null +++ b/src/screen/connecting.rs @@ -0,0 +1,101 @@ +// Copyright 2016 Matthew Collins +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::rc::Rc; + +use ui; +use render; +use format::{self, Component, TextComponent}; + +pub struct Connecting { + elements: Option, + target: String, +} + +struct UIElements { + logo: ui::logo::Logo, + elements: ui::Collection, +} + + +impl Connecting { + pub fn new(target: &str) -> Connecting { + Connecting { + elements: None, + target: target.to_owned(), + } + } +} + +impl super::Screen for Connecting { + fn on_active(&mut self, renderer: &mut render::Renderer, ui_container: &mut ui::Container) { + let logo = ui::logo::Logo::new(renderer.resources.clone(), renderer, ui_container); + let mut elements = ui::Collection::new(); + + let mut connect_msg = ui::Formatted::new( + renderer, + Component::Text(TextComponent::new("Connecting to")), + 0.0, -16.0 + ); + connect_msg.set_v_attach(ui::VAttach::Middle); + connect_msg.set_h_attach(ui::HAttach::Center); + elements.add(ui_container.add(connect_msg)); + + let mut msg = TextComponent::new(&self.target); + msg.modifier.color = Some(format::Color::Yellow); + let mut server_msg = ui::Formatted::new( + renderer, + Component::Text(msg), + 0.0, 16.0 + ); + server_msg.set_v_attach(ui::VAttach::Middle); + server_msg.set_h_attach(ui::HAttach::Center); + elements.add(ui_container.add(server_msg)); + + // Disclaimer + let mut warn = ui::Text::new(renderer, + "Not affiliated with Mojang/Minecraft", + 5.0, + 5.0, + 255, + 200, + 200); + warn.set_v_attach(ui::VAttach::Bottom); + warn.set_h_attach(ui::HAttach::Right); + elements.add(ui_container.add(warn)); + + self.elements = Some(UIElements { + logo: logo, + elements: elements, + }); + } + fn on_deactive(&mut self, _renderer: &mut render::Renderer, ui_container: &mut ui::Container) { + // Clean up + { + let elements = self.elements.as_mut().unwrap(); + elements.logo.remove(ui_container); + elements.elements.remove_all(ui_container); + } + self.elements = None + } + + fn tick(&mut self, + _delta: f64, + renderer: &mut render::Renderer, + ui_container: &mut ui::Container) { + let elements = self.elements.as_mut().unwrap(); + + elements.logo.tick(renderer, ui_container); + } +} diff --git a/src/screen/mod.rs b/src/screen/mod.rs index 9e7ec23..2db8b6a 100644 --- a/src/screen/mod.rs +++ b/src/screen/mod.rs @@ -16,6 +16,7 @@ mod server_list; pub use self::server_list::*; mod login; pub use self::login::*; +pub mod connecting; use std::rc::Rc; diff --git a/src/screen/server_list.rs b/src/screen/server_list.rs index eb0828d..07988fc 100644 --- a/src/screen/server_list.rs +++ b/src/screen/server_list.rs @@ -179,8 +179,9 @@ impl ServerList { }); })); - back.add_click_func(Rc::new(move |_, _| { - println!("Connecting to {}", address); + back.add_click_func(Rc::new(move |game, _| { + game.screen_sys.replace_screen(Box::new(super::connecting::Connecting::new(&address))); + game.connect_to(&address); })); } diff --git a/src/server.rs b/src/server.rs index bcc15c3..05ea3a1 100644 --- a/src/server.rs +++ b/src/server.rs @@ -28,6 +28,42 @@ pub struct Server { } impl Server { + + pub fn connect(resources: Arc>, address: &str) -> Result { + let mut conn = try!(protocol::Conn::new(address)); + + let host = conn.host.clone(); + let port = conn.port; + try!(conn.write_packet(protocol::packet::handshake::serverbound::Handshake { + protocol_version: protocol::VarInt(protocol::SUPPORTED_PROTOCOL), + host: host, + port: port, + next: protocol::VarInt(2), + })); + conn.state = protocol::State::Login; + try!(conn.write_packet(protocol::packet::login::serverbound::LoginStart { + username: "Thinkofdeath".to_owned() + })); + + let packet = match conn.read_packet().unwrap() { + protocol::packet::Packet::EncryptionRequest(val) => val, + protocol::packet::Packet::LoginDisconnect(val) => { + return Err(protocol::Error::Disconnect(val.reason)); + }, + val => panic!("Wrong packet: {:?}", val), + }; + + unimplemented!(); + + let version = resources.read().unwrap().version(); + Ok(Server { + conn: Some(conn), + world: world::World::new(), + resources: resources, + version: version, + }) + } + pub fn dummy_server(resources: Arc>) -> Server { let mut world = world::World::new(); let mut rng = rand::thread_rng();