<commit_before>use std::os::unix::io::RawFd;

use utils::mmap;
use utils::page;
use binary::elf::program_header;

fn load_size (phdrs: &[program_header::ProgramHeader]) -> (usize, u64, u64) {
    let mut max_vaddr = 0;
    let mut min_vaddr = 0;
    for phdr in phdrs {
        if phdr.p_type != program_header::PT_LOAD {
            continue;
        }

        if phdr.p_vaddr < min_vaddr {
            min_vaddr = phdr.p_vaddr;
        }

        if phdr.p_vaddr + phdr.p_memsz > max_vaddr {
            max_vaddr = phdr.p_vaddr + phdr.p_memsz;
        }
    }

    min_vaddr = page::page_start(min_vaddr);
    max_vaddr = page::page_end(max_vaddr);
    println!("size: {:x} min_vaddr: {:x} max_vaddr: {:x}", max_vaddr - min_vaddr, min_vaddr, max_vaddr);
    return ((max_vaddr - min_vaddr) as usize, min_vaddr, max_vaddr);
}

fn reserve_address_space (phdrs: &[program_header::ProgramHeader]) -> Result <(u64, u64), String> {

    let (size, min_vaddr, max_vaddr) = load_size(&phdrs);

    let mmap_flags = mmap::MAP_PRIVATE | mmap::MAP_ANONYMOUS;
    let start = unsafe { mmap::mmap(0 as *const u64,
                                    size,
                                    mmap::PROT_NONE,
                                    mmap_flags,
                                    -1,
                                    0) };
    if start == mmap::MAP_FAILED {
        Err(format!("<dryad> Failure: anonymous mmap failed for size {:x}", size))
    } else {

        let load_bias = start - min_vaddr;
        println!("Reserved {:x} bytes @ 0x{:x} with bias {:x}", size, start, load_bias);

        Ok((start, load_bias))
    }
}

#[inline(always)]
fn pflags_to_prot (x:u32) -> isize {
    use binary::elf::program_header::{PF_X, PF_R, PF_W};

    (if x & PF_X == PF_X { mmap::PROT_EXEC } else { 0 }) |
    (if x & PF_R == PF_R { mmap::PROT_READ } else { 0 }) |
    (if x & PF_W == PF_W { mmap::PROT_WRITE } else { 0 })
}

extern {
    static __errno_location: i32;
}

pub fn load (fd: RawFd, phdrs: &[program_header::ProgramHeader]) -> Result <(), String> {
    let (start, load_bias) = try!(reserve_address_space(phdrs));

    for phdr in phdrs {

        if phdr.p_type != program_header::PT_LOAD {
            continue;
        }

        let seg_start:u64 = phdr.p_vaddr + load_bias;
        let seg_end:u64   = seg_start + phdr.p_memsz;

        let seg_page_start:u64 = page::page_start(seg_start);
        let seg_page_end:u64   = page::page_start(seg_end);

        let mut seg_file_end:u64   = seg_start + phdr.p_filesz;

        // File offsets.
        let file_start:u64 = phdr.p_offset;
        let file_end:u64   = file_start + phdr.p_filesz;

        let file_page_start:u64 = page::page_start(file_start);
        let file_length:u64 = file_end - file_page_start;

        // TODO: add error checking, if file size <= 0, if file_end greater than file_size, etc.

        println!("DATA:\n\tseg_start: {:x} seg_end: {:x} seg_page_start: {:x} seg_page_end: {:x} seg_file_end: {:x}\n\tfile_start: {:x} file_end: {:x} file_page_start: {:x} file_length: {:x}", seg_start, seg_end, seg_page_start, seg_page_end, seg_file_end, file_start, file_end, file_page_start, file_length);

        if file_length != 0 {
            let mmap_flags = mmap::MAP_FIXED | mmap::MAP_PRIVATE;
            let prot_flags = pflags_to_prot(phdr.p_flags);
            unsafe {
                let start = mmap::mmap(seg_page_start as *const u64,
                                       file_length as usize,
                                       prot_flags,
                                       mmap_flags,
                                       -1,
                                       0);
                // `start` used in load bias computation
                println!("MMAP start: {:x} map_failed: {}", start, start == mmap::MAP_FAILED);

                println!("errno: {:x}", __errno_location);
            }
        }

        seg_file_end = page::page_end(seg_file_end);
    }

    Ok(())
}
<commit_msg>solved errno mystery, and determined mmap failing for bad fd!<commit_after>use std::os::unix::io::RawFd;

use utils::mmap;
use utils::page;
use binary::elf::program_header;

fn load_size (phdrs: &[program_header::ProgramHeader]) -> (usize, u64, u64) {
    let mut max_vaddr = 0;
    let mut min_vaddr = 0;
    for phdr in phdrs {
        if phdr.p_type != program_header::PT_LOAD {
            continue;
        }

        if phdr.p_vaddr < min_vaddr {
            min_vaddr = phdr.p_vaddr;
        }

        if phdr.p_vaddr + phdr.p_memsz > max_vaddr {
            max_vaddr = phdr.p_vaddr + phdr.p_memsz;
        }
    }

    min_vaddr = page::page_start(min_vaddr);
    max_vaddr = page::page_end(max_vaddr);
    println!("size: {:x} min_vaddr: {:x} max_vaddr: {:x}", max_vaddr - min_vaddr, min_vaddr, max_vaddr);
    return ((max_vaddr - min_vaddr) as usize, min_vaddr, max_vaddr);
}

fn reserve_address_space (phdrs: &[program_header::ProgramHeader]) -> Result <(u64, u64), String> {

    let (size, min_vaddr, max_vaddr) = load_size(&phdrs);

    let mmap_flags = mmap::MAP_PRIVATE | mmap::MAP_ANONYMOUS;
    let start = unsafe { mmap::mmap(0 as *const u64,
                                    size,
                                    mmap::PROT_NONE,
                                    mmap_flags,
                                    -1,
                                    0) };
    if start == mmap::MAP_FAILED {
        Err(format!("<dryad> Failure: anonymous mmap failed for size {:x}", size))
    } else {

        let load_bias = start - min_vaddr;
        println!("Reserved {:x} bytes @ 0x{:x} with bias {:x}", size, start, load_bias);

        Ok((start, load_bias))
    }
}

#[inline(always)]
fn pflags_to_prot (x:u32) -> isize {
    use binary::elf::program_header::{PF_X, PF_R, PF_W};

    (if x & PF_X == PF_X { mmap::PROT_EXEC } else { 0 }) |
    (if x & PF_R == PF_R { mmap::PROT_READ } else { 0 }) |
    (if x & PF_W == PF_W { mmap::PROT_WRITE } else { 0 })
}

extern {
    /// musl #defines erro *(__errno_location()) ... so errno isn't a symbol in the final binary and accesses will segfault us. yay.
    fn __errno_location() -> *const i32;
}

pub fn load (fd: RawFd, phdrs: &[program_header::ProgramHeader]) -> Result <(), String> {
    let (start, load_bias) = try!(reserve_address_space(phdrs));

    for phdr in phdrs {

        if phdr.p_type != program_header::PT_LOAD {
            continue;
        }

        let seg_start:u64 = phdr.p_vaddr + load_bias;
        let seg_end:u64   = seg_start + phdr.p_memsz;

        let seg_page_start:u64 = page::page_start(seg_start);
        let seg_page_end:u64   = page::page_start(seg_end);

        let mut seg_file_end:u64   = seg_start + phdr.p_filesz;

        // File offsets.
        let file_start:u64 = phdr.p_offset;
        let file_end:u64   = file_start + phdr.p_filesz;

        let file_page_start:u64 = page::page_start(file_start);
        let file_length:u64 = file_end - file_page_start;

        // TODO: add error checking, if file size <= 0, if file_end greater than file_size, etc.

        println!("DATA:\n\tseg_start: {:x} seg_end: {:x} seg_page_start: {:x} seg_page_end: {:x} seg_file_end: {:x}\n\tfile_start: {:x} file_end: {:x} file_page_start: {:x} file_length: {:x}", seg_start, seg_end, seg_page_start, seg_page_end, seg_file_end, file_start, file_end, file_page_start, file_length);

        if file_length != 0 {
            let mmap_flags = mmap::MAP_FIXED | mmap::MAP_PRIVATE;
            let prot_flags = pflags_to_prot(phdr.p_flags);
            unsafe {
                let start = mmap::mmap(seg_page_start as *const u64,
                                       file_length as usize,
                                       prot_flags,
                                       mmap_flags,
                                       -1,
                                       0);
                // `start` used in load bias computation
                println!("MMAP start: {:x} map_failed: {}", start, start == mmap::MAP_FAILED);

                println!("errno: {:x}", *__errno_location());
            }
        }

        seg_file_end = page::page_end(seg_file_end);
    }

    Ok(())
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::collections::HashMap;
use std::mem;

use bindgen::dependencies::Dependencies;
use bindgen::ir::{GenericPath, OpaqueItem, Path, Struct, Type, Union};
use bindgen::library::Library;

#[derive(Clone, Debug)]
pub struct TemplateSpecialization {
    pub generic: Struct,
    pub monomorphs: Vec<(Path, Vec<Type>)>,
}

impl TemplateSpecialization {
    fn new(generic: Struct) -> TemplateSpecialization {
        TemplateSpecialization {
            generic: generic,
            monomorphs: Vec::new(),
        }
    }

    pub fn add_dependencies(&self, library: &Library, out: &mut Dependencies) {
            for &(_, ref generic_values) in &self.monomorphs {
                for generic_value in generic_values {
                    generic_value.add_dependencies(library, out);
                }
            }
    }
}

#[derive(Clone, Debug)]
pub struct Monomorphs {
    replacements: HashMap<GenericPath, Path>,
    opaques: Vec<OpaqueItem>,
    structs: Vec<Struct>,
    unions: Vec<Union>,
    templates: HashMap<Path, TemplateSpecialization>,
}

impl Monomorphs {
    pub fn new() -> Monomorphs {
        Monomorphs {
            replacements: HashMap::new(),
            opaques: Vec::new(),
            structs: Vec::new(),
            unions: Vec::new(),
            templates: HashMap::new(),
        }
    }

    pub fn contains(&self, path: &GenericPath) -> bool {
        self.replacements.contains_key(path)
    }

    pub fn insert_struct(&mut self,
                         generic: &Struct,
                         monomorph: Struct,
                         parameters: Vec<Type>) {
        // Add extra information for struct instantiations so we can use template
        // specialization to make using the type more ergonomic.
        self.templates.entry(generic.name.clone())
                             .or_insert_with(|| TemplateSpecialization::new(generic.clone()))
                             .monomorphs.push((monomorph.name.clone(), parameters.clone()));

        let replacement_path = GenericPath::new(generic.name.clone(), parameters);

        debug_assert!(generic.generic_params.len() > 0);
        debug_assert!(!self.contains(&replacement_path));

        self.replacements.insert(replacement_path, monomorph.name.clone());
        self.structs.push(monomorph);
    }

    pub fn insert_union(&mut self,
                        generic: &Union,
                        monomorph: Union,
                        parameters: Vec<Type>) {
        let replacement_path = GenericPath::new(generic.name.clone(), parameters);

        debug_assert!(generic.generic_params.len() > 0);
        debug_assert!(!self.contains(&replacement_path));

        self.replacements.insert(replacement_path, monomorph.name.clone());
        self.unions.push(monomorph);
    }

    pub fn insert_opaque(&mut self,
                         generic: &OpaqueItem,
                         monomorph: OpaqueItem,
                         parameters: Vec<Type>) {
        let replacement_path = GenericPath::new(generic.name.clone(), parameters);

        debug_assert!(generic.generic_params.len() > 0);
        debug_assert!(!self.contains(&replacement_path));

        self.replacements.insert(replacement_path, monomorph.name.clone());
        self.opaques.push(monomorph);
    }

    pub fn mangle_path(&self, path: &GenericPath) -> Option<&Path> {
        self.replacements.get(path)
    }

    pub fn drain_opaques(&mut self) -> Vec<OpaqueItem> {
        mem::replace(&mut self.opaques, Vec::new())
    }

    pub fn drain_structs(&mut self) -> Vec<Struct> {
        mem::replace(&mut self.structs, Vec::new())
    }

    pub fn drain_unions(&mut self) -> Vec<Union> {
        mem::replace(&mut self.unions, Vec::new())
    }

    pub fn drain_template_specializations(&mut self) -> Vec<TemplateSpecialization> {
        let mut not_mangled = mem::replace(&mut self.templates, HashMap::new());
        let mut mangled = Vec::new();

        // The generic type arguments in `templates` need to be mangled
        for (_, mut template) in not_mangled.drain() {
            for &mut (_, ref mut generic_values) in &mut template.monomorphs {
                for generic_value in generic_values {
                    generic_value.mangle_paths(&self);
                }
            }

            mangled.push(template);
        }

        mangled
    }
}
<commit_msg>Make template specialization stable between runs<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::collections::HashMap;
use std::collections::BTreeMap;
use std::mem;

use bindgen::dependencies::Dependencies;
use bindgen::ir::{GenericPath, OpaqueItem, Path, Struct, Type, Union};
use bindgen::library::Library;

#[derive(Clone, Debug)]
pub struct TemplateSpecialization {
    pub generic: Struct,
    pub monomorphs: Vec<(Path, Vec<Type>)>,
}

impl TemplateSpecialization {
    fn new(generic: Struct) -> TemplateSpecialization {
        TemplateSpecialization {
            generic: generic,
            monomorphs: Vec::new(),
        }
    }

    pub fn add_dependencies(&self, library: &Library, out: &mut Dependencies) {
            for &(_, ref generic_values) in &self.monomorphs {
                for generic_value in generic_values {
                    generic_value.add_dependencies(library, out);
                }
            }
    }
}

#[derive(Clone, Debug)]
pub struct Monomorphs {
    replacements: HashMap<GenericPath, Path>,
    opaques: Vec<OpaqueItem>,
    structs: Vec<Struct>,
    unions: Vec<Union>,
    templates: BTreeMap<Path, TemplateSpecialization>,
}

impl Monomorphs {
    pub fn new() -> Monomorphs {
        Monomorphs {
            replacements: HashMap::new(),
            opaques: Vec::new(),
            structs: Vec::new(),
            unions: Vec::new(),
            templates: BTreeMap::new(),
        }
    }

    pub fn contains(&self, path: &GenericPath) -> bool {
        self.replacements.contains_key(path)
    }

    pub fn insert_struct(&mut self,
                         generic: &Struct,
                         monomorph: Struct,
                         parameters: Vec<Type>) {
        // Add extra information for struct instantiations so we can use template
        // specialization to make using the type more ergonomic.
        self.templates.entry(generic.name.clone())
                             .or_insert_with(|| TemplateSpecialization::new(generic.clone()))
                             .monomorphs.push((monomorph.name.clone(), parameters.clone()));

        let replacement_path = GenericPath::new(generic.name.clone(), parameters);

        debug_assert!(generic.generic_params.len() > 0);
        debug_assert!(!self.contains(&replacement_path));

        self.replacements.insert(replacement_path, monomorph.name.clone());
        self.structs.push(monomorph);
    }

    pub fn insert_union(&mut self,
                        generic: &Union,
                        monomorph: Union,
                        parameters: Vec<Type>) {
        let replacement_path = GenericPath::new(generic.name.clone(), parameters);

        debug_assert!(generic.generic_params.len() > 0);
        debug_assert!(!self.contains(&replacement_path));

        self.replacements.insert(replacement_path, monomorph.name.clone());
        self.unions.push(monomorph);
    }

    pub fn insert_opaque(&mut self,
                         generic: &OpaqueItem,
                         monomorph: OpaqueItem,
                         parameters: Vec<Type>) {
        let replacement_path = GenericPath::new(generic.name.clone(), parameters);

        debug_assert!(generic.generic_params.len() > 0);
        debug_assert!(!self.contains(&replacement_path));

        self.replacements.insert(replacement_path, monomorph.name.clone());
        self.opaques.push(monomorph);
    }

    pub fn mangle_path(&self, path: &GenericPath) -> Option<&Path> {
        self.replacements.get(path)
    }

    pub fn drain_opaques(&mut self) -> Vec<OpaqueItem> {
        mem::replace(&mut self.opaques, Vec::new())
    }

    pub fn drain_structs(&mut self) -> Vec<Struct> {
        mem::replace(&mut self.structs, Vec::new())
    }

    pub fn drain_unions(&mut self) -> Vec<Union> {
        mem::replace(&mut self.unions, Vec::new())
    }

    pub fn drain_template_specializations(&mut self) -> Vec<TemplateSpecialization> {
        let mut not_mangled = mem::replace(&mut self.templates, BTreeMap::new());
        let mut mangled = Vec::new();

        // The generic type arguments in `templates` need to be mangled
        for (_, template) in &mut not_mangled {
            for &mut (_, ref mut generic_values) in &mut template.monomorphs {
                for generic_value in generic_values {
                    generic_value.mangle_paths(&self);
                }
            }

            mangled.push(template.clone());
        }

        mangled
    }
}
<|endoftext|>


<commit_before>use seed::prelude::*;
use crate::Msg;

pub mod mersenne_utils {
    extern crate num_bigint;
    extern crate num_traits;

    use num_traits::{Pow,Num};
    use num_bigint::{BigInt,ToBigInt};

    pub fn mersennes_discovery_dates(n:usize) -> String {
        let mersennes_discovery_dates:Vec<Vec<&str>> = vec![
            //TODO: Complete this list all the way upto 50
            //TODO: We could include download links etc
            vec![""],//faux zero entry to make things easier when reading this vector
            vec!["500BC"],
            vec!["500BC"],
            vec!["275BC"],
            vec!["275BC"],
            vec!["1456"],
            vec!["1588"],
            vec!["1588"],
            vec!["1772"],
            vec!["1883"],
            vec!["1911"],
            vec!["1914"],
            vec!["1876"],
            vec!["30-Jan-1952"],
            vec!["30-Jan-1952"],
            vec!["26-Jun-1952"],
            vec!["7-Oct-1952"],
            vec!["9-Oct-1952"],
            vec!["8-Sep-1957"],
            vec!["3-Nov-1961"],
            vec!["3-Nov-1961"],
            vec!["11-May-1963"],
            vec!["16-May-1963"],
            vec!["2-Jun-1963"],
            vec!["4-Mar-1971"],
            vec!["30-Oct-1978"],
            vec!["9-Feb-1979"],
            vec!["8-Apr-1979"],
            vec!["25-Sep-1982"],
            vec!["28-Jan-1988"],
            vec!["20-Sep-1983"],
            vec!["6-Sep-1985"],
            vec!["19-Feb-1992"],
            vec!["10-Jan-1994"],
            vec!["3-Sep-1996"],
            vec!["12-Nov-1996"],
            vec!["24-Aug-1997"],
            vec!["27-Jan-1998"],
            vec!["1-Jun-1999"],
            vec!["14-Nov-2001"],
            vec!["17-Nov-2003"],
            vec!["28-May-2004"],
            vec!["26-Feb-2005"],
            vec!["15-Dec-2005"],
            vec!["4-Sep-2006"],
            vec!["23-Aug-2008"],
            vec!["06-Sep-2009"],
            vec!["12-Apr-2008"],
            vec!["25-Jan-2013"],
            vec!["07-Jan-2016"],
            vec!["26-Dec-2017"],
        ];

        mersennes_discovery_dates[n][0].to_owned()
    }

    pub fn mersennes() -> Vec<Vec<usize>> {
        vec![
            //vec![p,digits]
            vec![0,     0],//faux zero entry to make things easier when reading this vector
            vec![2,     1],
            vec![3,     1],
            vec![5,     2],
            vec![7,     3],
            vec![13,    4],
            vec![17,    6],
            vec![19,    6],
            vec![31,   10],
            vec![61,   19],
            vec![89,   27],
            vec![107,  33],
            vec![127,  39],
            vec![521,  157],
            vec![607,  183],
            vec![1279, 386],
            vec![2203, 664],
            vec![2281, 687],
            vec![3217, 969],
            vec![4253,1281],
            vec![4423,1332],
            vec![9689,2917],
            vec![9941,2993],
            vec![11213,3376],
            vec![19937,6002],
            vec![21701,6533],
            vec![23209,6987],
            vec![44497,13395],
            vec![86243,25962],
            vec![110503,33265],
            vec![132049,39751],
            vec![216091,65050],
            vec![756839,227832],
            vec![859433,258716],
            vec![1257787,378632],
            vec![1398269,420921],
            vec![2976221,895832],
            vec![3021377,909526],
            vec![6972593,2098960],
            vec![13466917,4053946],
            vec![20996011,6320430],
            vec![24036583,7235733],
            vec![25964951,7816230],
            vec![30402457,9152052],
            vec![32582657,9808358],
            vec![37156667,11185272],
            vec![42643801,12837064],
            vec![43112609,12978189],
            vec![57885161,17425170],
            vec![74207281,22338618],
            vec![77232917,23249425],
        ]
    }

    pub fn nth_mersenne_prime (candidate:&str) -> u64 {
        let big_candidate:BigInt = num_bigint::BigInt::from_str_radix(&candidate, 10).unwrap();
        let mersennes:Vec<Vec<usize>> = mersennes();

        let mut answer:u64 = 0;
        let big_two:BigInt = 2.to_bigint().unwrap();
        for n in 1..mersennes.len() {
            let mprime:BigInt = big_two.pow(mersennes[n][0]) - 1;
            if big_candidate == mprime {
                answer = n as u64;
                break
            } else if big_candidate < mprime {
                break
            }
        }

        answer
    }
}

pub fn render() -> seed::dom_types::Node<Msg> {
    let mut html = vec![];

    let mersennes = mersenne_utils::mersennes();

    for n in 1..mersennes.len() {
        let download_txt:String = vec!["https://static.bigprimes.net/archive/mersenne/M",&n.to_string(),".txt"].into_iter().collect();
        let download_zip:String = vec!["https://static.bigprimes.net/archive/mersenne/M",&n.to_string(),".zip"].into_iter().collect();
        html.push(
            tr![
                td![n.to_string()],
                td!["2",sup![mersennes[n][0].to_string()],"-1"],
                td![mersennes[n][1].to_string()],
                td![mersenne_utils::mersennes_discovery_dates(n)],
                if n >= 30 {a![attrs!{At::Href => download_zip},"ZIP"]} else {a![attrs!{At::Href => download_txt},"TXT"]}
            ]
        );
    }

    html.reverse();

    div![
        h1!["The Mersenne Numbers"],
        br![],
        br![],
        br![],
        table![
            attrs!{At::Class => "mersennetable text"},
            tbody![
                tr![
                    td![
                        b!["No."]
                    ],
                    td![
                        b!["Prime"]
                    ],
                    td![
                        b!["Digits"]
                    ],
                    td![
                        b!["Discovered"]
                    ],
                    td![
                        b!["Download"]
                    ]
                ],
                html
            ]
        ]
    ]
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn mersennes_discovery_dates_test() {
        assert_eq!(mersenne_utils::mersennes_discovery_dates(0), "");
        assert_eq!(mersenne_utils::mersennes_discovery_dates(50), "26-Dec-2017");
    }
}<commit_msg>Added nth_mersenne_prime() unit tests<commit_after>use seed::prelude::*;
use crate::Msg;

pub mod mersenne_utils {
    extern crate num_bigint;
    extern crate num_traits;

    use num_traits::{Pow,Num};
    use num_bigint::{BigInt,ToBigInt};

    pub fn mersennes_discovery_dates(n:usize) -> String {
        let mersennes_discovery_dates:Vec<Vec<&str>> = vec![
            //TODO: Complete this list all the way upto 50
            //TODO: We could include download links etc
            vec![""],//faux zero entry to make things easier when reading this vector
            vec!["500BC"],
            vec!["500BC"],
            vec!["275BC"],
            vec!["275BC"],
            vec!["1456"],
            vec!["1588"],
            vec!["1588"],
            vec!["1772"],
            vec!["1883"],
            vec!["1911"],
            vec!["1914"],
            vec!["1876"],
            vec!["30-Jan-1952"],
            vec!["30-Jan-1952"],
            vec!["26-Jun-1952"],
            vec!["7-Oct-1952"],
            vec!["9-Oct-1952"],
            vec!["8-Sep-1957"],
            vec!["3-Nov-1961"],
            vec!["3-Nov-1961"],
            vec!["11-May-1963"],
            vec!["16-May-1963"],
            vec!["2-Jun-1963"],
            vec!["4-Mar-1971"],
            vec!["30-Oct-1978"],
            vec!["9-Feb-1979"],
            vec!["8-Apr-1979"],
            vec!["25-Sep-1982"],
            vec!["28-Jan-1988"],
            vec!["20-Sep-1983"],
            vec!["6-Sep-1985"],
            vec!["19-Feb-1992"],
            vec!["10-Jan-1994"],
            vec!["3-Sep-1996"],
            vec!["12-Nov-1996"],
            vec!["24-Aug-1997"],
            vec!["27-Jan-1998"],
            vec!["1-Jun-1999"],
            vec!["14-Nov-2001"],
            vec!["17-Nov-2003"],
            vec!["28-May-2004"],
            vec!["26-Feb-2005"],
            vec!["15-Dec-2005"],
            vec!["4-Sep-2006"],
            vec!["23-Aug-2008"],
            vec!["06-Sep-2009"],
            vec!["12-Apr-2008"],
            vec!["25-Jan-2013"],
            vec!["07-Jan-2016"],
            vec!["26-Dec-2017"],
        ];

        mersennes_discovery_dates[n][0].to_owned()
    }

    pub fn mersennes() -> Vec<Vec<usize>> {
        vec![
            //vec![p,digits]
            vec![0,     0],//faux zero entry to make things easier when reading this vector
            vec![2,     1],
            vec![3,     1],
            vec![5,     2],
            vec![7,     3],
            vec![13,    4],
            vec![17,    6],
            vec![19,    6],
            vec![31,   10],
            vec![61,   19],
            vec![89,   27],
            vec![107,  33],
            vec![127,  39],
            vec![521,  157],
            vec![607,  183],
            vec![1279, 386],
            vec![2203, 664],
            vec![2281, 687],
            vec![3217, 969],
            vec![4253,1281],
            vec![4423,1332],
            vec![9689,2917],
            vec![9941,2993],
            vec![11213,3376],
            vec![19937,6002],
            vec![21701,6533],
            vec![23209,6987],
            vec![44497,13395],
            vec![86243,25962],
            vec![110503,33265],
            vec![132049,39751],
            vec![216091,65050],
            vec![756839,227832],
            vec![859433,258716],
            vec![1257787,378632],
            vec![1398269,420921],
            vec![2976221,895832],
            vec![3021377,909526],
            vec![6972593,2098960],
            vec![13466917,4053946],
            vec![20996011,6320430],
            vec![24036583,7235733],
            vec![25964951,7816230],
            vec![30402457,9152052],
            vec![32582657,9808358],
            vec![37156667,11185272],
            vec![42643801,12837064],
            vec![43112609,12978189],
            vec![57885161,17425170],
            vec![74207281,22338618],
            vec![77232917,23249425],
        ]
    }

    pub fn nth_mersenne_prime (candidate:&str) -> u64 {
        let big_candidate:BigInt = num_bigint::BigInt::from_str_radix(&candidate, 10).unwrap();
        let mersennes:Vec<Vec<usize>> = mersennes();

        let mut answer:u64 = 0;
        let big_two:BigInt = 2.to_bigint().unwrap();
        for n in 1..mersennes.len() {
            let mprime:BigInt = big_two.pow(mersennes[n][0]) - 1;
            if big_candidate == mprime {
                answer = n as u64;
                break
            } else if big_candidate < mprime {
                break
            }
        }

        answer
    }
}

pub fn render() -> seed::dom_types::Node<Msg> {
    let mut html = vec![];

    let mersennes = mersenne_utils::mersennes();

    for n in 1..mersennes.len() {
        let download_txt:String = vec!["https://static.bigprimes.net/archive/mersenne/M",&n.to_string(),".txt"].into_iter().collect();
        let download_zip:String = vec!["https://static.bigprimes.net/archive/mersenne/M",&n.to_string(),".zip"].into_iter().collect();
        html.push(
            tr![
                td![n.to_string()],
                td!["2",sup![mersennes[n][0].to_string()],"-1"],
                td![mersennes[n][1].to_string()],
                td![mersenne_utils::mersennes_discovery_dates(n)],
                if n >= 30 {a![attrs!{At::Href => download_zip},"ZIP"]} else {a![attrs!{At::Href => download_txt},"TXT"]}
            ]
        );
    }

    html.reverse();

    div![
        h1!["The Mersenne Numbers"],
        br![],
        br![],
        br![],
        table![
            attrs!{At::Class => "mersennetable text"},
            tbody![
                tr![
                    td![
                        b!["No."]
                    ],
                    td![
                        b!["Prime"]
                    ],
                    td![
                        b!["Digits"]
                    ],
                    td![
                        b!["Discovered"]
                    ],
                    td![
                        b!["Download"]
                    ]
                ],
                html
            ]
        ]
    ]
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn mersennes_discovery_dates_test() {
        assert_eq!(mersenne_utils::mersennes_discovery_dates(0), "");
        assert_eq!(mersenne_utils::mersennes_discovery_dates(50), "26-Dec-2017");
    }

    #[test]
    fn nth_mersenne_prime_test() {
        assert_eq!(mersenne_utils::nth_mersenne_prime("127"), 4);
        assert_eq!(mersenne_utils::nth_mersenne_prime("9"), 0);
    }
}<|endoftext|>


<commit_before>//! Error module.
//! Contains traits and Constants for error printing.

use std::fmt;
use std::fmt::Debug;
use position::span::Span;
extern crate ansi_term;
use self::ansi_term::Color::*;
use self::ansi_term::Color;

/// Color code for errors used throughout entire error reporting system.
///
#[deprecated(since = "0.5.0")]
pub const ERROR_COLORS: [Color; 4] = [
    Red, Cyan, Green, Cyan,
];

/// Enum for error levels.
#[derive(Debug, Copy, Clone)]
pub enum ErrorLevel {Warning, Error}

impl fmt::Display for ErrorLevel {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", match self {
            &ErrorLevel::Warning => Yellow,
            &ErrorLevel::Error   => Red,
        }.paint(format!("{:?}", self)))
    }
}

/// Color for names which are printed by the compiler.
pub const NAME_COLOR: Color = Green;

/// Color for modules when printed by the compiler.
pub const MODULE_COLOR: Color = Cyan;

/// Color for dividing bars used when displaying errors.
pub const BAR_COLOR: Color = Cyan;

/// Color for info line displayed.
pub const INFO_COLOR: Color = Blue;

/// Color for underlining arrows for error spans.
pub const ARROW_COLOR: Color = Red;

/// Color for source code that is displayed in error reporting.
pub const CONTENT_COLOR: Color = Green;

/// Trait for Errors. Any error used throughout the wright compiler/interpreter must implement
/// this trait for consistency.
pub trait Error<'source> : Debug + Sized {
    /// Return the name of the error.
    fn get_name(&self)   -> &str;

    /// Return the module or location the error came from.
    fn get_module(&self) -> &str;

    /// Returns the error level.
    fn get_level(&self) -> ErrorLevel;

    /// Returns a vector of the content spans of the offending content.
    ///
    /// If there are no spans (the vector is empty) then line numbers will not
    /// be used in error reporting. (The entire source will be printed.)
    ///
    /// Spans must be single line only. (The error is invalid otherwise.)
    fn get_spans(&self)  -> &Vec<Span>;

    /// Return information about the error.
    ///
    /// The first entry is displayed as the error information at the top of the error
    /// and the following ones are displayed next to the the underlining string for each span.
    ///
    /// Any additional information (past the appropriate number for the given set of spans)
    /// will not show up in the error report.
    ///
    /// If the vector is empty or too short then each informative will default to an empty string
    /// except for the first one, which defaults to "An error occurred."
    fn get_info(&self)   -> &Vec<&str>;

    /// Return a reference to the source code of the module (file) containing the error.
    /// Or the source of the error if it was not in code.
    ///
    /// If line numbers are not being used, the full source returned by this
    /// function will be printed.
    ///
    /// The error will be invalid if the source is not long enough to contain the errors found.
    fn get_lines(&self)  -> &'source Vec<&'source str>;

    /// Check to see if the error is valid.
    /// (Checks to make sure there are the appropriate numbers of spans,
    /// informatics, and source lines).
    ///
    /// # Errors
    /// - If any of the spans from get_spans are multiple lines.
    /// - If any of the spans are outside of the of the source module/file.
    fn validate(&self) -> Result<(), ()> {
        if !self.get_spans()
            .iter()
            .all(|span| !span.is_multiple_lines()) {return Err(());}
        if self.get_spans().len() > 0 && self.get_spans().last().unwrap()
            .get_end().get_line() > self.get_lines().len() {return Err(());}
        Ok(())
    }

    /// Turn error into one which can be displayed.
    /// (ErrorToDisplay implements fmt::Display)
    ///
    /// # Panics
    /// Panics if validate() returns an Err().
    fn get_displayable(&self) ->  ErrorToDisplay<'source> {
        self.validate().unwrap();
        let result = ErrorToDisplay {
            level:         self.get_level(),
            name:          self.get_name().to_string(),
            module:        self.get_module().to_string(),
            line_info:     ErrorToDisplay::get_line_info(self.get_spans()),
            error_info:    self.get_info().iter().map(|s| s.to_string()).collect(),
            source_lines:  self.get_lines(),
            spans:         self.get_spans().clone(),
        };
        return result;
    }

    /// Displays a given error via the get_displayable method.
    ///
    /// # Panics
    /// Panics if validate() returns and Err().
    fn display(&self) {
        self.get_displayable().display();
    }
}

#[derive(Debug, Clone)]
/// ErrorToDisplay is an intermediate type used to go from a raw error
/// into a format that can be printed easily.
pub struct ErrorToDisplay<'source> {
    level:          ErrorLevel,
    name:           String,
    module:         String,
    line_info:      String,
    error_info:     Vec<String>,
    source_lines:   &'source Vec<&'source str>,
    spans:          Vec<Span>,
}

impl<'source> ErrorToDisplay<'source> {
    /// Prints this error into the terminal.
    pub fn display(&self) {
        println!("{}", self);
    }
    // not pub because it doesn't need to be and it is pretty specific.
    /// Takes vec of spans and uses it to set line info.
    fn get_line_info(span_vec: &Vec<Span>) -> String {
        if span_vec.is_empty() {"".to_string()}
        else {
            format!("on line {}.", span_vec.last().unwrap().get_start().get_line())
        }
    }
}

impl<'source> fmt::Display for ErrorToDisplay<'source> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let width = 5;
        let five = " ".repeat(width);
        let bar = BAR_COLOR.paint("|");
        let info = self.clone().error_info;
        let mut info_iter = info.iter();
        let no_span = self.spans.is_empty();
        let mut span_iter = self.spans.iter();
        writeln!(f, "{level}: {n} in {m} {l_info}\n{f}{info}\n{f} {b}",
            level = format!("{}", self.level),
            n = NAME_COLOR.paint(self.name.clone()),
            m = MODULE_COLOR.paint(self.module.clone()),
            l_info = self.line_info,
            f = five,
            b = bar,
            info = INFO_COLOR.paint(info_iter.next()
                .unwrap_or(&"An Error Occurred.".to_string())
                .as_str()),
        )?;
        while let Some(span) = span_iter.next() {
            let current_line: &str = self.source_lines
                .get(span.get_start()
                    .get_line()-1)
                .unwrap().trim_right();
            let mut arrow_line = String::new();
            current_line.chars().take(span.get_start().get_col()).for_each(|c| {
                match c {
                    '\t' => arrow_line.push('\t'),
                    _    => arrow_line.push(' '),
                }
            });
            arrow_line.push_str("^".repeat(span.get_end().get_col()-span.get_start().get_col())
                .as_str());
            writeln!(f, "{prev:>w$} {b} {p_line}\n{cur:>w$} {b} {c_line}\n{f} {b} {a_line} {info}",
                prev = span.get_start().get_line()-1,
                cur = span.get_start().get_line(),
                p_line = CONTENT_COLOR.paint(
                    self.source_lines.get(span.get_start().get_line()-2).unwrap().trim_right()),
                c_line = CONTENT_COLOR.paint(current_line),
                w = width,
                b = bar,
                f = five,
                a_line = ARROW_COLOR.paint(arrow_line),
                info = INFO_COLOR.paint(info_iter.next()
                    .unwrap_or(&"".to_string())
                    .as_str()),
            )?;
        }
        if no_span {
            for line in self.source_lines {
                writeln!(f, "{f} {b} {l}",
                    f= five,
                    b = bar,
                    l = CONTENT_COLOR.paint(*line),
                )?;
            }
        }
        writeln!(f, "{} {}", five, bar)
    }
}<commit_msg>Typo.<commit_after>//! Error module.
//! Contains traits and Constants for error printing.

use std::fmt;
use std::fmt::Debug;
use position::span::Span;
extern crate ansi_term;
use self::ansi_term::Color::*;
use self::ansi_term::Color;

/// Color code for errors used throughout entire error reporting system.
#[deprecated(since = "0.5.0")]
pub const ERROR_COLORS: [Color; 4] = [
    Red, Cyan, Green, Cyan,
];

/// Enum for error levels.
#[derive(Debug, Copy, Clone)]
pub enum ErrorLevel {Warning, Error}

impl fmt::Display for ErrorLevel {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", match self {
            &ErrorLevel::Warning => Yellow,
            &ErrorLevel::Error   => Red,
        }.paint(format!("{:?}", self)))
    }
}

/// Color for names which are printed by the compiler.
pub const NAME_COLOR: Color = Green;

/// Color for modules when printed by the compiler.
pub const MODULE_COLOR: Color = Cyan;

/// Color for dividing bars used when displaying errors.
pub const BAR_COLOR: Color = Cyan;

/// Color for info line displayed.
pub const INFO_COLOR: Color = Blue;

/// Color for underlining arrows for error spans.
pub const ARROW_COLOR: Color = Red;

/// Color for source code that is displayed in error reporting.
pub const CONTENT_COLOR: Color = Green;

/// Trait for Errors. Any error used throughout the wright compiler/interpreter must implement
/// this trait for consistency.
pub trait Error<'source> : Debug + Sized {
    /// Return the name of the error.
    fn get_name(&self)   -> &str;

    /// Return the module or location the error came from.
    fn get_module(&self) -> &str;

    /// Returns the error level.
    fn get_level(&self) -> ErrorLevel;

    /// Returns a vector of the content spans of the offending content.
    ///
    /// If there are no spans (the vector is empty) then line numbers will not
    /// be used in error reporting. (The entire source will be printed.)
    ///
    /// Spans must be single line only. (The error is invalid otherwise.)
    fn get_spans(&self)  -> &Vec<Span>;

    /// Return information about the error.
    ///
    /// The first entry is displayed as the error information at the top of the error
    /// and the following ones are displayed next to the the underlining string for each span.
    ///
    /// Any additional information (past the appropriate number for the given set of spans)
    /// will not show up in the error report.
    ///
    /// If the vector is empty or too short then each informative will default to an empty string
    /// except for the first one, which defaults to "An error occurred."
    fn get_info(&self)   -> &Vec<&str>;

    /// Return a reference to the source code of the module (file) containing the error.
    /// Or the source of the error if it was not in code.
    ///
    /// If line numbers are not being used, the full source returned by this
    /// function will be printed.
    ///
    /// The error will be invalid if the source is not long enough to contain the errors found.
    fn get_lines(&self)  -> &'source Vec<&'source str>;

    /// Check to see if the error is valid.
    /// (Checks to make sure there are the appropriate numbers of spans,
    /// informatics, and source lines).
    ///
    /// # Errors
    /// - If any of the spans from get_spans are multiple lines.
    /// - If any of the spans are outside of the of the source module/file.
    fn validate(&self) -> Result<(), ()> {
        if !self.get_spans()
            .iter()
            .all(|span| !span.is_multiple_lines()) {return Err(());}
        if self.get_spans().len() > 0 && self.get_spans().last().unwrap()
            .get_end().get_line() > self.get_lines().len() {return Err(());}
        Ok(())
    }

    /// Turn error into one which can be displayed.
    /// (ErrorToDisplay implements fmt::Display)
    ///
    /// # Panics
    /// Panics if validate() returns an Err().
    fn get_displayable(&self) ->  ErrorToDisplay<'source> {
        self.validate().unwrap();
        let result = ErrorToDisplay {
            level:         self.get_level(),
            name:          self.get_name().to_string(),
            module:        self.get_module().to_string(),
            line_info:     ErrorToDisplay::get_line_info(self.get_spans()),
            error_info:    self.get_info().iter().map(|s| s.to_string()).collect(),
            source_lines:  self.get_lines(),
            spans:         self.get_spans().clone(),
        };
        return result;
    }

    /// Displays a given error via the get_displayable method.
    ///
    /// # Panics
    /// Panics if validate() returns and Err().
    fn display(&self) {
        self.get_displayable().display();
    }
}

#[derive(Debug, Clone)]
/// ErrorToDisplay is an intermediate type used to go from a raw error
/// into a format that can be printed easily.
pub struct ErrorToDisplay<'source> {
    level:          ErrorLevel,
    name:           String,
    module:         String,
    line_info:      String,
    error_info:     Vec<String>,
    source_lines:   &'source Vec<&'source str>,
    spans:          Vec<Span>,
}

impl<'source> ErrorToDisplay<'source> {
    /// Prints this error into the terminal.
    pub fn display(&self) {
        println!("{}", self);
    }
    // not pub because it doesn't need to be and it is pretty specific.
    /// Takes vec of spans and uses it to set line info.
    fn get_line_info(span_vec: &Vec<Span>) -> String {
        if span_vec.is_empty() {"".to_string()}
        else {
            format!("on line {}.", span_vec.last().unwrap().get_start().get_line())
        }
    }
}

impl<'source> fmt::Display for ErrorToDisplay<'source> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let width = 5;
        let five = " ".repeat(width);
        let bar = BAR_COLOR.paint("|");
        let info = self.clone().error_info;
        let mut info_iter = info.iter();
        let no_span = self.spans.is_empty();
        let mut span_iter = self.spans.iter();
        writeln!(f, "{level}: {n} in {m} {l_info}\n{f}{info}\n{f} {b}",
            level = format!("{}", self.level),
            n = NAME_COLOR.paint(self.name.clone()),
            m = MODULE_COLOR.paint(self.module.clone()),
            l_info = self.line_info,
            f = five,
            b = bar,
            info = INFO_COLOR.paint(info_iter.next()
                .unwrap_or(&"An Error Occurred.".to_string())
                .as_str()),
        )?;
        while let Some(span) = span_iter.next() {
            let current_line: &str = self.source_lines
                .get(span.get_start()
                    .get_line()-1)
                .unwrap().trim_right();
            let mut arrow_line = String::new();
            current_line.chars().take(span.get_start().get_col()).for_each(|c| {
                match c {
                    '\t' => arrow_line.push('\t'),
                    _    => arrow_line.push(' '),
                }
            });
            arrow_line.push_str("^".repeat(span.get_end().get_col()-span.get_start().get_col())
                .as_str());
            writeln!(f, "{prev:>w$} {b} {p_line}\n{cur:>w$} {b} {c_line}\n{f} {b} {a_line} {info}",
                prev = span.get_start().get_line()-1,
                cur = span.get_start().get_line(),
                p_line = CONTENT_COLOR.paint(
                    self.source_lines.get(span.get_start().get_line()-2).unwrap().trim_right()),
                c_line = CONTENT_COLOR.paint(current_line),
                w = width,
                b = bar,
                f = five,
                a_line = ARROW_COLOR.paint(arrow_line),
                info = INFO_COLOR.paint(info_iter.next()
                    .unwrap_or(&"".to_string())
                    .as_str()),
            )?;
        }
        if no_span {
            for line in self.source_lines {
                writeln!(f, "{f} {b} {l}",
                    f= five,
                    b = bar,
                    l = CONTENT_COLOR.paint(*line),
                )?;
            }
        }
        writeln!(f, "{} {}", five, bar)
    }
}<|endoftext|>


<commit_before>// Copyright 2020 The Grin Developers
//
// 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::fs::File;
use std::io::{self, Read};
use std::net::{Shutdown, SocketAddr, TcpListener, TcpStream};
use std::path::PathBuf;
use std::sync::Arc;
use std::thread;
use std::time::Duration;

use crate::chain;
use crate::core::core;
use crate::core::core::hash::Hash;
use crate::core::global;
use crate::core::pow::Difficulty;
use crate::handshake::Handshake;
use crate::peer::Peer;
use crate::peers::Peers;
use crate::store::PeerStore;
use crate::types::{
	Capabilities, ChainAdapter, Error, NetAdapter, P2PConfig, PeerAddr, PeerInfo, ReasonForBan,
	TxHashSetRead,
};
use crate::util::StopState;
use chrono::prelude::{DateTime, Utc};

/// P2P server implementation, handling bootstrapping to find and connect to
/// peers, receiving connections from other peers and keep track of all of them.
pub struct Server {
	pub config: P2PConfig,
	capabilities: Capabilities,
	handshake: Arc<Handshake>,
	pub peers: Arc<Peers>,
	stop_state: Arc<StopState>,
}

// TODO TLS
impl Server {
	/// Creates a new idle p2p server with no peers
	pub fn new(
		db_root: &str,
		capab: Capabilities,
		config: P2PConfig,
		adapter: Arc<dyn ChainAdapter>,
		genesis: Hash,
		stop_state: Arc<StopState>,
	) -> Result<Server, Error> {
		Ok(Server {
			config: config.clone(),
			capabilities: capab,
			handshake: Arc::new(Handshake::new(genesis, config.clone())),
			peers: Arc::new(Peers::new(PeerStore::new(db_root)?, adapter, config)),
			stop_state,
		})
	}

	/// Starts a new TCP server and listen to incoming connections. This is a
	/// blocking call until the TCP server stops.
	pub fn listen(&self) -> Result<(), Error> {
		// start TCP listener and handle incoming connections
		let addr = SocketAddr::new(self.config.host, self.config.port);
		let listener = TcpListener::bind(addr)?;
		listener.set_nonblocking(true)?;

		let sleep_time = Duration::from_millis(5);
		loop {
			// Pause peer ingress connection request. Only for tests.
			if self.stop_state.is_paused() {
				thread::sleep(Duration::from_secs(1));
				continue;
			}

			match listener.accept() {
				Ok((stream, peer_addr)) => {
					// We want out TCP stream to be in blocking mode.
					// The TCP listener is in nonblocking mode so we *must* explicitly
					// move the accepted TCP stream into blocking mode (or all kinds of
					// bad things can and will happen).
					// A nonblocking TCP listener will accept nonblocking TCP streams which
					// we do not want.
					stream.set_nonblocking(false)?;

					let peer_addr = PeerAddr(peer_addr);

					if self.check_undesirable(&stream) {
						// Shutdown the incoming TCP connection if it is not desired
						if let Err(e) = stream.shutdown(Shutdown::Both) {
							debug!("Error shutting down conn: {:?}", e);
						}
						continue;
					}
					match self.handle_new_peer(stream) {
						Err(Error::ConnectionClose) => debug!("shutting down, ignoring a new peer"),
						Err(e) => {
							debug!("Error accepting peer {}: {:?}", peer_addr.to_string(), e);
							let _ = self.peers.add_banned(peer_addr, ReasonForBan::BadHandshake);
						}
						Ok(_) => {}
					}
				}
				Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
					// nothing to do, will retry in next iteration
				}
				Err(e) => {
					debug!("Couldn't establish new client connection: {:?}", e);
				}
			}
			if self.stop_state.is_stopped() {
				break;
			}
			thread::sleep(sleep_time);
		}
		Ok(())
	}

	/// Asks the server to connect to a new peer. Directly returns the peer if
	/// we're already connected to the provided address.
	pub fn connect(&self, addr: PeerAddr) -> Result<Arc<Peer>, Error> {
		if self.stop_state.is_stopped() {
			return Err(Error::ConnectionClose);
		}

		if Peer::is_denied(&self.config, addr) {
			debug!("connect_peer: peer {} denied, not connecting.", addr);
			return Err(Error::ConnectionClose);
		}

		if global::is_production_mode() {
			let hs = self.handshake.clone();
			let addrs = hs.addrs.read();
			if addrs.contains(&addr) {
				debug!("connect: ignore connecting to PeerWithSelf, addr: {}", addr);
				return Err(Error::PeerWithSelf);
			}
		}

		if let Some(p) = self.peers.get_connected_peer(addr) {
			// if we're already connected to the addr, just return the peer
			trace!("connect_peer: already connected {}", addr);
			return Ok(p);
		}

		trace!(
			"connect_peer: on {}:{}. connecting to {}",
			self.config.host,
			self.config.port,
			addr
		);
		match TcpStream::connect_timeout(&addr.0, Duration::from_secs(10)) {
			Ok(stream) => {
				let addr = SocketAddr::new(self.config.host, self.config.port);
				let total_diff = self.peers.total_difficulty()?;

				let peer = Peer::connect(
					stream,
					self.capabilities,
					total_diff,
					PeerAddr(addr),
					&self.handshake,
					self.peers.clone(),
				)?;
				let peer = Arc::new(peer);
				self.peers.add_connected(peer.clone())?;
				Ok(peer)
			}
			Err(e) => {
				trace!(
					"connect_peer: on {}:{}. Could not connect to {}: {:?}",
					self.config.host,
					self.config.port,
					addr,
					e
				);
				Err(Error::Connection(e))
			}
		}
	}

	fn handle_new_peer(&self, stream: TcpStream) -> Result<(), Error> {
		if self.stop_state.is_stopped() {
			return Err(Error::ConnectionClose);
		}
		let total_diff = self.peers.total_difficulty()?;

		// accept the peer and add it to the server map
		let peer = Peer::accept(
			stream,
			self.capabilities,
			total_diff,
			&self.handshake,
			self.peers.clone(),
		)?;
		self.peers.add_connected(Arc::new(peer))?;
		Ok(())
	}

	/// Checks whether there's any reason we don't want to accept an incoming peer
	/// connection. There can be a few of them:
	/// 1. Accepting the peer connection would exceed the configured maximum allowed
	/// inbound peer count. Note that seed nodes may wish to increase the default
	/// value for PEER_LISTENER_BUFFER_COUNT to help with network bootstrapping.
	/// A default buffer of 8 peers is allowed to help with network growth.
	/// 2. The peer has been previously banned and the ban period hasn't
	/// expired yet.
	/// 3. We're already connected to a peer at the same IP. While there are
	/// many reasons multiple peers can legitimately share identical IP
	/// addresses (NAT), network distribution is improved if they choose
	/// different sets of peers themselves. In addition, it prevent potential
	/// duplicate connections, malicious or not.
	fn check_undesirable(&self, stream: &TcpStream) -> bool {
		if self.peers.peer_inbound_count()
			>= self.config.peer_max_inbound_count() + self.config.peer_listener_buffer_count()
		{
			debug!("Accepting new connection will exceed peer limit, refusing connection.");
			return true;
		}
		if let Ok(peer_addr) = stream.peer_addr() {
			let peer_addr = PeerAddr(peer_addr);
			if self.peers.is_banned(peer_addr) {
				debug!("Peer {} banned, refusing connection.", peer_addr);
				return true;
			}
			// The call to is_known() can fail due to contention on the peers map.
			// If it fails we want to default to refusing the connection.
			match self.peers.is_known(peer_addr) {
				Ok(true) => {
					debug!("Peer {} already known, refusing connection.", peer_addr);
					return true;
				}
				Err(_) => {
					error!(
						"Peer {} is_known check failed, refusing connection.",
						peer_addr
					);
					return true;
				}
				_ => (),
			}
		}
		false
	}

	pub fn stop(&self) {
		self.stop_state.stop();
		self.peers.stop();
	}

	/// Pause means: stop all the current peers connection, only for tests.
	/// Note:
	/// 1. must pause the 'seed' thread also, to avoid the new egress peer connection
	/// 2. must pause the 'p2p-server' thread also, to avoid the new ingress peer connection.
	pub fn pause(&self) {
		self.peers.stop();
	}
}

/// A no-op network adapter used for testing.
pub struct DummyAdapter {}

impl ChainAdapter for DummyAdapter {
	fn total_difficulty(&self) -> Result<Difficulty, chain::Error> {
		Ok(Difficulty::min())
	}
	fn total_height(&self) -> Result<u64, chain::Error> {
		Ok(0)
	}
	fn get_transaction(&self, _h: Hash) -> Option<core::Transaction> {
		None
	}

	fn tx_kernel_received(&self, _h: Hash, _peer_info: &PeerInfo) -> Result<bool, chain::Error> {
		Ok(true)
	}
	fn transaction_received(
		&self,
		_: core::Transaction,
		_stem: bool,
	) -> Result<bool, chain::Error> {
		Ok(true)
	}
	fn compact_block_received(
		&self,
		_cb: core::CompactBlock,
		_peer_info: &PeerInfo,
	) -> Result<bool, chain::Error> {
		Ok(true)
	}
	fn header_received(
		&self,
		_bh: core::BlockHeader,
		_peer_info: &PeerInfo,
	) -> Result<bool, chain::Error> {
		Ok(true)
	}
	fn block_received(
		&self,
		_: core::Block,
		_: &PeerInfo,
		_: chain::Options,
	) -> Result<bool, chain::Error> {
		Ok(true)
	}
	fn headers_received(
		&self,
		_: &[core::BlockHeader],
		_: &PeerInfo,
	) -> Result<bool, chain::Error> {
		Ok(true)
	}
	fn locate_headers(&self, _: &[Hash]) -> Result<Vec<core::BlockHeader>, chain::Error> {
		Ok(vec![])
	}
	fn get_block(&self, _: Hash) -> Option<core::Block> {
		None
	}
	fn kernel_data_read(&self) -> Result<File, chain::Error> {
		unimplemented!()
	}
	fn kernel_data_write(&self, _reader: &mut dyn Read) -> Result<bool, chain::Error> {
		unimplemented!()
	}
	fn txhashset_read(&self, _h: Hash) -> Option<TxHashSetRead> {
		unimplemented!()
	}

	fn txhashset_archive_header(&self) -> Result<core::BlockHeader, chain::Error> {
		unimplemented!()
	}

	fn txhashset_receive_ready(&self) -> bool {
		false
	}

	fn txhashset_write(
		&self,
		_h: Hash,
		_txhashset_data: File,
		_peer_info: &PeerInfo,
	) -> Result<bool, chain::Error> {
		Ok(false)
	}

	fn txhashset_download_update(
		&self,
		_start_time: DateTime<Utc>,
		_downloaded_size: u64,
		_total_size: u64,
	) -> bool {
		false
	}

	fn get_tmp_dir(&self) -> PathBuf {
		unimplemented!()
	}

	fn get_tmpfile_pathname(&self, _tmpfile_name: String) -> PathBuf {
		unimplemented!()
	}
}

impl NetAdapter for DummyAdapter {
	fn find_peer_addrs(&self, _: Capabilities) -> Vec<PeerAddr> {
		vec![]
	}
	fn peer_addrs_received(&self, _: Vec<PeerAddr>) {}
	fn peer_difficulty(&self, _: PeerAddr, _: Difficulty, _: u64) {}
	fn is_banned(&self, _: PeerAddr) -> bool {
		false
	}
}
<commit_msg>Convert ipv4-mapped ipv6 when accepting peer (#3225)<commit_after>// Copyright 2020 The Grin Developers
//
// 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::fs::File;
use std::io::{self, Read};
use std::net::{IpAddr, Shutdown, SocketAddr, SocketAddrV4, TcpListener, TcpStream};
use std::path::PathBuf;
use std::sync::Arc;
use std::thread;
use std::time::Duration;

use crate::chain;
use crate::core::core;
use crate::core::core::hash::Hash;
use crate::core::global;
use crate::core::pow::Difficulty;
use crate::handshake::Handshake;
use crate::peer::Peer;
use crate::peers::Peers;
use crate::store::PeerStore;
use crate::types::{
	Capabilities, ChainAdapter, Error, NetAdapter, P2PConfig, PeerAddr, PeerInfo, ReasonForBan,
	TxHashSetRead,
};
use crate::util::StopState;
use chrono::prelude::{DateTime, Utc};

/// P2P server implementation, handling bootstrapping to find and connect to
/// peers, receiving connections from other peers and keep track of all of them.
pub struct Server {
	pub config: P2PConfig,
	capabilities: Capabilities,
	handshake: Arc<Handshake>,
	pub peers: Arc<Peers>,
	stop_state: Arc<StopState>,
}

// TODO TLS
impl Server {
	/// Creates a new idle p2p server with no peers
	pub fn new(
		db_root: &str,
		capab: Capabilities,
		config: P2PConfig,
		adapter: Arc<dyn ChainAdapter>,
		genesis: Hash,
		stop_state: Arc<StopState>,
	) -> Result<Server, Error> {
		Ok(Server {
			config: config.clone(),
			capabilities: capab,
			handshake: Arc::new(Handshake::new(genesis, config.clone())),
			peers: Arc::new(Peers::new(PeerStore::new(db_root)?, adapter, config)),
			stop_state,
		})
	}

	/// Starts a new TCP server and listen to incoming connections. This is a
	/// blocking call until the TCP server stops.
	pub fn listen(&self) -> Result<(), Error> {
		// start TCP listener and handle incoming connections
		let addr = SocketAddr::new(self.config.host, self.config.port);
		let listener = TcpListener::bind(addr)?;
		listener.set_nonblocking(true)?;

		let sleep_time = Duration::from_millis(5);
		loop {
			// Pause peer ingress connection request. Only for tests.
			if self.stop_state.is_paused() {
				thread::sleep(Duration::from_secs(1));
				continue;
			}

			match listener.accept() {
				Ok((stream, peer_addr)) => {
					// We want out TCP stream to be in blocking mode.
					// The TCP listener is in nonblocking mode so we *must* explicitly
					// move the accepted TCP stream into blocking mode (or all kinds of
					// bad things can and will happen).
					// A nonblocking TCP listener will accept nonblocking TCP streams which
					// we do not want.
					stream.set_nonblocking(false)?;

					let mut peer_addr = PeerAddr(peer_addr);

					// attempt to see if it an ipv4-mapped ipv6
					// if yes convert to ipv4
					if peer_addr.0.is_ipv6() {
						if let IpAddr::V6(ipv6) = peer_addr.0.ip() {
							if let Some(ipv4) = ipv6.to_ipv4() {
								peer_addr = PeerAddr(SocketAddr::V4(SocketAddrV4::new(
									ipv4,
									peer_addr.0.port(),
								)))
							}
						}
					}

					if self.check_undesirable(&stream) {
						// Shutdown the incoming TCP connection if it is not desired
						if let Err(e) = stream.shutdown(Shutdown::Both) {
							debug!("Error shutting down conn: {:?}", e);
						}
						continue;
					}
					match self.handle_new_peer(stream) {
						Err(Error::ConnectionClose) => debug!("shutting down, ignoring a new peer"),
						Err(e) => {
							debug!("Error accepting peer {}: {:?}", peer_addr.to_string(), e);
							let _ = self.peers.add_banned(peer_addr, ReasonForBan::BadHandshake);
						}
						Ok(_) => {}
					}
				}
				Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
					// nothing to do, will retry in next iteration
				}
				Err(e) => {
					debug!("Couldn't establish new client connection: {:?}", e);
				}
			}
			if self.stop_state.is_stopped() {
				break;
			}
			thread::sleep(sleep_time);
		}
		Ok(())
	}

	/// Asks the server to connect to a new peer. Directly returns the peer if
	/// we're already connected to the provided address.
	pub fn connect(&self, addr: PeerAddr) -> Result<Arc<Peer>, Error> {
		if self.stop_state.is_stopped() {
			return Err(Error::ConnectionClose);
		}

		if Peer::is_denied(&self.config, addr) {
			debug!("connect_peer: peer {} denied, not connecting.", addr);
			return Err(Error::ConnectionClose);
		}

		if global::is_production_mode() {
			let hs = self.handshake.clone();
			let addrs = hs.addrs.read();
			if addrs.contains(&addr) {
				debug!("connect: ignore connecting to PeerWithSelf, addr: {}", addr);
				return Err(Error::PeerWithSelf);
			}
		}

		if let Some(p) = self.peers.get_connected_peer(addr) {
			// if we're already connected to the addr, just return the peer
			trace!("connect_peer: already connected {}", addr);
			return Ok(p);
		}

		trace!(
			"connect_peer: on {}:{}. connecting to {}",
			self.config.host,
			self.config.port,
			addr
		);
		match TcpStream::connect_timeout(&addr.0, Duration::from_secs(10)) {
			Ok(stream) => {
				let addr = SocketAddr::new(self.config.host, self.config.port);
				let total_diff = self.peers.total_difficulty()?;

				let peer = Peer::connect(
					stream,
					self.capabilities,
					total_diff,
					PeerAddr(addr),
					&self.handshake,
					self.peers.clone(),
				)?;
				let peer = Arc::new(peer);
				self.peers.add_connected(peer.clone())?;
				Ok(peer)
			}
			Err(e) => {
				trace!(
					"connect_peer: on {}:{}. Could not connect to {}: {:?}",
					self.config.host,
					self.config.port,
					addr,
					e
				);
				Err(Error::Connection(e))
			}
		}
	}

	fn handle_new_peer(&self, stream: TcpStream) -> Result<(), Error> {
		if self.stop_state.is_stopped() {
			return Err(Error::ConnectionClose);
		}
		let total_diff = self.peers.total_difficulty()?;

		// accept the peer and add it to the server map
		let peer = Peer::accept(
			stream,
			self.capabilities,
			total_diff,
			&self.handshake,
			self.peers.clone(),
		)?;
		self.peers.add_connected(Arc::new(peer))?;
		Ok(())
	}

	/// Checks whether there's any reason we don't want to accept an incoming peer
	/// connection. There can be a few of them:
	/// 1. Accepting the peer connection would exceed the configured maximum allowed
	/// inbound peer count. Note that seed nodes may wish to increase the default
	/// value for PEER_LISTENER_BUFFER_COUNT to help with network bootstrapping.
	/// A default buffer of 8 peers is allowed to help with network growth.
	/// 2. The peer has been previously banned and the ban period hasn't
	/// expired yet.
	/// 3. We're already connected to a peer at the same IP. While there are
	/// many reasons multiple peers can legitimately share identical IP
	/// addresses (NAT), network distribution is improved if they choose
	/// different sets of peers themselves. In addition, it prevent potential
	/// duplicate connections, malicious or not.
	fn check_undesirable(&self, stream: &TcpStream) -> bool {
		if self.peers.peer_inbound_count()
			>= self.config.peer_max_inbound_count() + self.config.peer_listener_buffer_count()
		{
			debug!("Accepting new connection will exceed peer limit, refusing connection.");
			return true;
		}
		if let Ok(peer_addr) = stream.peer_addr() {
			let peer_addr = PeerAddr(peer_addr);
			if self.peers.is_banned(peer_addr) {
				debug!("Peer {} banned, refusing connection.", peer_addr);
				return true;
			}
			// The call to is_known() can fail due to contention on the peers map.
			// If it fails we want to default to refusing the connection.
			match self.peers.is_known(peer_addr) {
				Ok(true) => {
					debug!("Peer {} already known, refusing connection.", peer_addr);
					return true;
				}
				Err(_) => {
					error!(
						"Peer {} is_known check failed, refusing connection.",
						peer_addr
					);
					return true;
				}
				_ => (),
			}
		}
		false
	}

	pub fn stop(&self) {
		self.stop_state.stop();
		self.peers.stop();
	}

	/// Pause means: stop all the current peers connection, only for tests.
	/// Note:
	/// 1. must pause the 'seed' thread also, to avoid the new egress peer connection
	/// 2. must pause the 'p2p-server' thread also, to avoid the new ingress peer connection.
	pub fn pause(&self) {
		self.peers.stop();
	}
}

/// A no-op network adapter used for testing.
pub struct DummyAdapter {}

impl ChainAdapter for DummyAdapter {
	fn total_difficulty(&self) -> Result<Difficulty, chain::Error> {
		Ok(Difficulty::min())
	}
	fn total_height(&self) -> Result<u64, chain::Error> {
		Ok(0)
	}
	fn get_transaction(&self, _h: Hash) -> Option<core::Transaction> {
		None
	}

	fn tx_kernel_received(&self, _h: Hash, _peer_info: &PeerInfo) -> Result<bool, chain::Error> {
		Ok(true)
	}
	fn transaction_received(
		&self,
		_: core::Transaction,
		_stem: bool,
	) -> Result<bool, chain::Error> {
		Ok(true)
	}
	fn compact_block_received(
		&self,
		_cb: core::CompactBlock,
		_peer_info: &PeerInfo,
	) -> Result<bool, chain::Error> {
		Ok(true)
	}
	fn header_received(
		&self,
		_bh: core::BlockHeader,
		_peer_info: &PeerInfo,
	) -> Result<bool, chain::Error> {
		Ok(true)
	}
	fn block_received(
		&self,
		_: core::Block,
		_: &PeerInfo,
		_: chain::Options,
	) -> Result<bool, chain::Error> {
		Ok(true)
	}
	fn headers_received(
		&self,
		_: &[core::BlockHeader],
		_: &PeerInfo,
	) -> Result<bool, chain::Error> {
		Ok(true)
	}
	fn locate_headers(&self, _: &[Hash]) -> Result<Vec<core::BlockHeader>, chain::Error> {
		Ok(vec![])
	}
	fn get_block(&self, _: Hash) -> Option<core::Block> {
		None
	}
	fn kernel_data_read(&self) -> Result<File, chain::Error> {
		unimplemented!()
	}
	fn kernel_data_write(&self, _reader: &mut dyn Read) -> Result<bool, chain::Error> {
		unimplemented!()
	}
	fn txhashset_read(&self, _h: Hash) -> Option<TxHashSetRead> {
		unimplemented!()
	}

	fn txhashset_archive_header(&self) -> Result<core::BlockHeader, chain::Error> {
		unimplemented!()
	}

	fn txhashset_receive_ready(&self) -> bool {
		false
	}

	fn txhashset_write(
		&self,
		_h: Hash,
		_txhashset_data: File,
		_peer_info: &PeerInfo,
	) -> Result<bool, chain::Error> {
		Ok(false)
	}

	fn txhashset_download_update(
		&self,
		_start_time: DateTime<Utc>,
		_downloaded_size: u64,
		_total_size: u64,
	) -> bool {
		false
	}

	fn get_tmp_dir(&self) -> PathBuf {
		unimplemented!()
	}

	fn get_tmpfile_pathname(&self, _tmpfile_name: String) -> PathBuf {
		unimplemented!()
	}
}

impl NetAdapter for DummyAdapter {
	fn find_peer_addrs(&self, _: Capabilities) -> Vec<PeerAddr> {
		vec![]
	}
	fn peer_addrs_received(&self, _: Vec<PeerAddr>) {}
	fn peer_difficulty(&self, _: PeerAddr, _: Difficulty, _: u64) {}
	fn is_banned(&self, _: PeerAddr) -> bool {
		false
	}
}
<|endoftext|>


<commit_before>//! Crate `ruma_api` contains core types used to define the requests and responses for each endpoint
//! in the various [Matrix](https://matrix.org) API specifications.
//! These types can be shared by client and server code for all Matrix APIs.
//!
//! When implementing a new Matrix API, each endpoint has a request type which implements
//! `Endpoint`, and a response type connected via an associated type.
//!
//! An implementation of `Endpoint` contains all the information about the HTTP method, the path and
//! input parameters for requests, and the structure of a successful response.
//! Such types can then be used by client code to make requests, and by server code to fulfill
//! those requests.

#![doc(html_favicon_url = "https://www.ruma.io/favicon.ico")]
#![warn(rust_2018_idioms)]
#![deny(missing_copy_implementations, missing_debug_implementations, missing_docs)]

use std::{
    convert::{TryFrom, TryInto},
    error::Error as StdError,
};

use http::Method;

/// Generates a `ruma_api::Endpoint` from a concise definition.
///
/// The macro expects the following structure as input:
///
/// ```text
/// ruma_api! {
///     metadata: {
///         description: &'static str,
///         method: http::Method,
///         name: &'static str,
///         path: &'static str,
///         rate_limited: bool,
///         authentication: ruma_api::AuthScheme,
///     }
///
///     request: {
///         // Struct fields for each piece of data required
///         // to make a request to this API endpoint.
///     }
///
///     response: {
///         // Struct fields for each piece of data expected
///         // in the response from this API endpoint.
///     }
///
///     // The error returned when a response fails, defaults to `Void`.
///     error: path::to::Error
/// }
/// ```
///
/// This will generate a `ruma_api::Metadata` value to be used for the `ruma_api::Endpoint`'s
/// associated constant, single `Request` and `Response` structs, and the necessary trait
/// implementations to convert the request into a `http::Request` and to create a response from
/// a `http::Response` and vice versa.
///
/// The details of each of the three sections of the macros are documented below.
///
/// ## Metadata
///
/// * `description`: A short description of what the endpoint does.
/// * `method`: The HTTP method used for requests to the endpoint. It's not necessary to import
///   `http::Method`'s associated constants. Just write the value as if it was imported, e.g.
///   `GET`.
/// * `name`: A unique name for the endpoint. Generally this will be the same as the containing
///   module.
/// * `path`: The path component of the URL for the endpoint, e.g. "/foo/bar". Components of
///   the path that are parameterized can indicate a variable by using a Rust identifier
///   prefixed with a colon, e.g. `/foo/:some_parameter`. A corresponding query string
///   parameter will be expected in the request struct (see below for details).
/// * `rate_limited`: Whether or not the endpoint enforces rate limiting on requests.
/// * `authentication`: What authentication scheme the endpoint uses.
///
/// ## Request
///
/// The request block contains normal struct field definitions.
/// Doc comments and attributes are allowed as normal.
/// There are also a few special attributes available to control how the struct is converted
/// into a `http::Request`:
///
/// * `#[ruma_api(header = HEADER_NAME)]`: Fields with this attribute will be treated as HTTP
///   headers on the request. The value must implement `AsRef<str>`. Generally this is a
///   `String`. The attribute value shown above as `HEADER_NAME` must be a header name constant
///   from `http::header`, e.g. `CONTENT_TYPE`.
/// * `#[ruma_api(path)]`: Fields with this attribute will be inserted into the matching path
///   component of the request URL.
/// * `#[ruma_api(query)]`: Fields with this attribute will be inserting into the URL's query
///   string.
/// * `#[ruma_api(query_map)]`: Instead of individual query fields, one query_map field, of any
///   type that implements `IntoIterator<Item = (String, String)>` (e.g. `HashMap<String,
///   String>`, can be used for cases where an endpoint supports arbitrary query parameters.
///
/// Any field that does not include one of these attributes will be part of the request's JSON
/// body.
///
/// ## Response
///
/// Like the request block, the response block consists of normal struct field definitions.
/// Doc comments and attributes are allowed as normal.
/// There is also a special attribute available to control how the struct is created from a
/// `http::Request`:
///
/// * `#[ruma_api(header = HEADER_NAME)]`: Fields with this attribute will be treated as HTTP
///   headers on the response. The value must implement `AsRef<str>`. Generally this is a
///   `String`. The attribute value shown above as `HEADER_NAME` must be a header name constant
///   from `http::header`, e.g. `CONTENT_TYPE`.
///
/// Any field that does not include the above attribute will be expected in the response's JSON
/// body.
///
/// ## Newtype bodies
///
/// Both the request and response block also support "newtype bodies" by using the
/// `#[ruma_api(body)]` attribute on a field. If present on a field, the entire request or
/// response body will be treated as the value of the field. This allows you to treat the
/// entire request or response body as a specific type, rather than a JSON object with named
/// fields. Only one field in each struct can be marked with this attribute. It is an error to
/// have a newtype body field and normal body fields within the same struct.
///
/// There is another kind of newtype body that is enabled with `#[ruma_api(raw_body)]`. It is
/// used for endpoints in which the request or response body can be arbitrary bytes instead of
/// a JSON objects. A field with `#[ruma_api(raw_body)]` needs to have the type `Vec<u8>`.
///
/// # Examples
///
/// ```
/// pub mod some_endpoint {
///     use ruma_api_macros::ruma_api;
///
///     ruma_api! {
///         metadata: {
///             description: "Does something.",
///             method: POST,
///             name: "some_endpoint",
///             path: "/_matrix/some/endpoint/:baz",
///             rate_limited: false,
///             authentication: None,
///         }
///
///         request: {
///             pub foo: String,
///
///             #[ruma_api(header = CONTENT_TYPE)]
///             pub content_type: String,
///
///             #[ruma_api(query)]
///             pub bar: String,
///
///             #[ruma_api(path)]
///             pub baz: String,
///         }
///
///         response: {
///             #[ruma_api(header = CONTENT_TYPE)]
///             pub content_type: String,
///
///             pub value: String,
///         }
///     }
/// }
///
/// pub mod newtype_body_endpoint {
///     use ruma_api_macros::ruma_api;
///     use serde::{Deserialize, Serialize};
///
///     #[derive(Clone, Debug, Deserialize, Serialize)]
///     pub struct MyCustomType {
///         pub foo: String,
///     }
///
///     ruma_api! {
///         metadata: {
///             description: "Does something.",
///             method: PUT,
///             name: "newtype_body_endpoint",
///             path: "/_matrix/some/newtype/body/endpoint",
///             rate_limited: false,
///             authentication: None,
///         }
///
///         request: {
///             #[ruma_api(raw_body)]
///             pub file: Vec<u8>,
///         }
///
///         response: {
///             #[ruma_api(body)]
///             pub my_custom_type: MyCustomType,
///         }
///     }
/// }
/// ```
///
/// ## Fallible deserialization
///
/// All request and response types also derive [`Outgoing`][trait@ruma_serde::Outgoing]. As such,
/// to allow fallible deserialization, you can use the `#[wrap_incoming]` attribute. For details,
/// see the documentation for [the derive macro](derive@ruma_serde::Outgoing).
// TODO: Explain the concept of fallible deserialization before jumping to
// `ruma_serde::Outgoing`
pub use ruma_api_macros::ruma_api;

pub mod error;
/// This module is used to support the generated code from ruma-api-macros.
/// It is not considered part of ruma-api's public API.
#[doc(hidden)]
pub mod exports {
    pub use http;
    pub use percent_encoding;
    pub use ruma_serde;
    pub use serde;
    pub use serde_json;
}

use error::{FromHttpRequestError, FromHttpResponseError, IntoHttpError};

/// Gives users the ability to define their own serializable / deserializable errors.
pub trait EndpointError: StdError + Sized + 'static {
    /// Tries to construct `Self` from an `http::Response`.
    ///
    /// This will always return `Err` variant when no `error` field is defined in
    /// the `ruma_api` macro.
    fn try_from_response(
        response: http::Response<Vec<u8>>,
    ) -> Result<Self, error::ResponseDeserializationError>;
}

/// A request type for a Matrix API endpoint. (trait used for sending requests)
pub trait OutgoingRequest {
    /// A type capturing the expected error conditions the server can return.
    type EndpointError: EndpointError;

    /// Response type returned when the request is successful.
    type IncomingResponse: TryFrom<
        http::Response<Vec<u8>>,
        Error = FromHttpResponseError<Self::EndpointError>,
    >;

    /// Metadata about the endpoint.
    const METADATA: Metadata;

    /// Tries to convert this request into an `http::Request`.
    ///
    /// This method should only fail when called on endpoints that require authentication. It may
    /// also fail with a serialization error in case of bugs in Ruma though.
    ///
    /// The endpoints path will be appended to the given `base_url`, for example
    /// `https://matrix.org`. Since all paths begin with a slash, it is not necessary for the
    /// `base_url` to have a trailing slash. If it has one however, it will be ignored.
    fn try_into_http_request(
        self,
        base_url: &str,
        access_token: Option<&str>,
    ) -> Result<http::Request<Vec<u8>>, IntoHttpError>;
}

/// A request type for a Matrix API endpoint. (trait used for receiving requests)
pub trait IncomingRequest: Sized {
    /// A type capturing the error conditions that can be returned in the response.
    type EndpointError: EndpointError;

    /// Response type to return when the request is successful.
    type OutgoingResponse: TryInto<http::Response<Vec<u8>>, Error = IntoHttpError>;

    /// Metadata about the endpoint.
    const METADATA: Metadata;

    /// Tries to turn the given `http::Request` into this request type.
    fn try_from_http_request(req: http::Request<Vec<u8>>) -> Result<Self, FromHttpRequestError>;
}

/// Marker trait for requests that don't require authentication. (for the client side)
pub trait OutgoingNonAuthRequest: OutgoingRequest {}

/// Marker trait for requests that don't require authentication. (for the server side)
pub trait IncomingNonAuthRequest: IncomingRequest {}

/// Authentication scheme used by the endpoint.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum AuthScheme {
    /// No authentication is performed.
    None,

    /// Authentication is performed by including an access token in the `Authentication` http
    /// header, or an `access_token` query parameter.
    ///
    /// It is recommended to use the header over the query parameter.
    AccessToken,

    /// Authentication is performed by including X-Matrix signatures in the request headers,
    /// as defined in the federation API.
    ServerSignatures,

    /// Authentication is performed by setting the `access_token` query parameter.
    QueryOnlyAccessToken,
}

/// Metadata about an API endpoint.
#[derive(Clone, Debug)]
pub struct Metadata {
    /// A human-readable description of the endpoint.
    pub description: &'static str,

    /// The HTTP method used by this endpoint.
    pub method: Method,

    /// A unique identifier for this endpoint.
    pub name: &'static str,

    /// The path of this endpoint's URL, with variable names where path parameters should be filled
    /// in during a request.
    pub path: &'static str,

    /// Whether or not this endpoint is rate limited by the server.
    pub rate_limited: bool,

    /// What authentication scheme the server uses for this endpoint.
    pub authentication: AuthScheme,
}

#[doc(hidden)]
#[macro_export]
macro_rules! try_deserialize {
    ($kind:ident, $call:expr $(,)?) => {
        $crate::try_deserialize!(@$kind, $kind, $call)
    };
    (@request, $kind:ident, $call:expr) => {
        match $call {
            Ok(val) => val,
            Err(err) => return Err($crate::error::RequestDeserializationError::new(err, $kind).into()),
        }
    };
    (@response, $kind:ident, $call:expr) => {
        match $call {
            Ok(val) => val,
            Err(err) => return Err($crate::error::ResponseDeserializationError::new(err, $kind).into()),
        }
    };
}
<commit_msg>Re-format<commit_after>//! Crate `ruma_api` contains core types used to define the requests and responses for each endpoint
//! in the various [Matrix](https://matrix.org) API specifications.
//! These types can be shared by client and server code for all Matrix APIs.
//!
//! When implementing a new Matrix API, each endpoint has a request type which implements
//! `Endpoint`, and a response type connected via an associated type.
//!
//! An implementation of `Endpoint` contains all the information about the HTTP method, the path and
//! input parameters for requests, and the structure of a successful response.
//! Such types can then be used by client code to make requests, and by server code to fulfill
//! those requests.

#![doc(html_favicon_url = "https://www.ruma.io/favicon.ico")]
#![warn(rust_2018_idioms)]
#![deny(missing_copy_implementations, missing_debug_implementations, missing_docs)]

use std::{
    convert::{TryFrom, TryInto},
    error::Error as StdError,
};

use http::Method;

/// Generates a `ruma_api::Endpoint` from a concise definition.
///
/// The macro expects the following structure as input:
///
/// ```text
/// ruma_api! {
///     metadata: {
///         description: &'static str,
///         method: http::Method,
///         name: &'static str,
///         path: &'static str,
///         rate_limited: bool,
///         authentication: ruma_api::AuthScheme,
///     }
///
///     request: {
///         // Struct fields for each piece of data required
///         // to make a request to this API endpoint.
///     }
///
///     response: {
///         // Struct fields for each piece of data expected
///         // in the response from this API endpoint.
///     }
///
///     // The error returned when a response fails, defaults to `Void`.
///     error: path::to::Error
/// }
/// ```
///
/// This will generate a `ruma_api::Metadata` value to be used for the `ruma_api::Endpoint`'s
/// associated constant, single `Request` and `Response` structs, and the necessary trait
/// implementations to convert the request into a `http::Request` and to create a response from
/// a `http::Response` and vice versa.
///
/// The details of each of the three sections of the macros are documented below.
///
/// ## Metadata
///
/// * `description`: A short description of what the endpoint does.
/// * `method`: The HTTP method used for requests to the endpoint. It's not necessary to import
///   `http::Method`'s associated constants. Just write the value as if it was imported, e.g.
///   `GET`.
/// * `name`: A unique name for the endpoint. Generally this will be the same as the containing
///   module.
/// * `path`: The path component of the URL for the endpoint, e.g. "/foo/bar". Components of
///   the path that are parameterized can indicate a variable by using a Rust identifier
///   prefixed with a colon, e.g. `/foo/:some_parameter`. A corresponding query string
///   parameter will be expected in the request struct (see below for details).
/// * `rate_limited`: Whether or not the endpoint enforces rate limiting on requests.
/// * `authentication`: What authentication scheme the endpoint uses.
///
/// ## Request
///
/// The request block contains normal struct field definitions.
/// Doc comments and attributes are allowed as normal.
/// There are also a few special attributes available to control how the struct is converted
/// into a `http::Request`:
///
/// * `#[ruma_api(header = HEADER_NAME)]`: Fields with this attribute will be treated as HTTP
///   headers on the request. The value must implement `AsRef<str>`. Generally this is a
///   `String`. The attribute value shown above as `HEADER_NAME` must be a header name constant
///   from `http::header`, e.g. `CONTENT_TYPE`.
/// * `#[ruma_api(path)]`: Fields with this attribute will be inserted into the matching path
///   component of the request URL.
/// * `#[ruma_api(query)]`: Fields with this attribute will be inserting into the URL's query
///   string.
/// * `#[ruma_api(query_map)]`: Instead of individual query fields, one query_map field, of any
///   type that implements `IntoIterator<Item = (String, String)>` (e.g. `HashMap<String,
///   String>`, can be used for cases where an endpoint supports arbitrary query parameters.
///
/// Any field that does not include one of these attributes will be part of the request's JSON
/// body.
///
/// ## Response
///
/// Like the request block, the response block consists of normal struct field definitions.
/// Doc comments and attributes are allowed as normal.
/// There is also a special attribute available to control how the struct is created from a
/// `http::Request`:
///
/// * `#[ruma_api(header = HEADER_NAME)]`: Fields with this attribute will be treated as HTTP
///   headers on the response. The value must implement `AsRef<str>`. Generally this is a
///   `String`. The attribute value shown above as `HEADER_NAME` must be a header name constant
///   from `http::header`, e.g. `CONTENT_TYPE`.
///
/// Any field that does not include the above attribute will be expected in the response's JSON
/// body.
///
/// ## Newtype bodies
///
/// Both the request and response block also support "newtype bodies" by using the
/// `#[ruma_api(body)]` attribute on a field. If present on a field, the entire request or
/// response body will be treated as the value of the field. This allows you to treat the
/// entire request or response body as a specific type, rather than a JSON object with named
/// fields. Only one field in each struct can be marked with this attribute. It is an error to
/// have a newtype body field and normal body fields within the same struct.
///
/// There is another kind of newtype body that is enabled with `#[ruma_api(raw_body)]`. It is
/// used for endpoints in which the request or response body can be arbitrary bytes instead of
/// a JSON objects. A field with `#[ruma_api(raw_body)]` needs to have the type `Vec<u8>`.
///
/// # Examples
///
/// ```
/// pub mod some_endpoint {
///     use ruma_api_macros::ruma_api;
///
///     ruma_api! {
///         metadata: {
///             description: "Does something.",
///             method: POST,
///             name: "some_endpoint",
///             path: "/_matrix/some/endpoint/:baz",
///             rate_limited: false,
///             authentication: None,
///         }
///
///         request: {
///             pub foo: String,
///
///             #[ruma_api(header = CONTENT_TYPE)]
///             pub content_type: String,
///
///             #[ruma_api(query)]
///             pub bar: String,
///
///             #[ruma_api(path)]
///             pub baz: String,
///         }
///
///         response: {
///             #[ruma_api(header = CONTENT_TYPE)]
///             pub content_type: String,
///
///             pub value: String,
///         }
///     }
/// }
///
/// pub mod newtype_body_endpoint {
///     use ruma_api_macros::ruma_api;
///     use serde::{Deserialize, Serialize};
///
///     #[derive(Clone, Debug, Deserialize, Serialize)]
///     pub struct MyCustomType {
///         pub foo: String,
///     }
///
///     ruma_api! {
///         metadata: {
///             description: "Does something.",
///             method: PUT,
///             name: "newtype_body_endpoint",
///             path: "/_matrix/some/newtype/body/endpoint",
///             rate_limited: false,
///             authentication: None,
///         }
///
///         request: {
///             #[ruma_api(raw_body)]
///             pub file: Vec<u8>,
///         }
///
///         response: {
///             #[ruma_api(body)]
///             pub my_custom_type: MyCustomType,
///         }
///     }
/// }
/// ```
///
/// ## Fallible deserialization
///
/// All request and response types also derive [`Outgoing`][trait@ruma_serde::Outgoing]. As
/// such, to allow fallible deserialization, you can use the `#[wrap_incoming]` attribute. For
/// details, see the documentation for [the derive macro](derive@ruma_serde::Outgoing).
// TODO: Explain the concept of fallible deserialization before jumping to
// `ruma_serde::Outgoing`
pub use ruma_api_macros::ruma_api;

pub mod error;
/// This module is used to support the generated code from ruma-api-macros.
/// It is not considered part of ruma-api's public API.
#[doc(hidden)]
pub mod exports {
    pub use http;
    pub use percent_encoding;
    pub use ruma_serde;
    pub use serde;
    pub use serde_json;
}

use error::{FromHttpRequestError, FromHttpResponseError, IntoHttpError};

/// Gives users the ability to define their own serializable / deserializable errors.
pub trait EndpointError: StdError + Sized + 'static {
    /// Tries to construct `Self` from an `http::Response`.
    ///
    /// This will always return `Err` variant when no `error` field is defined in
    /// the `ruma_api` macro.
    fn try_from_response(
        response: http::Response<Vec<u8>>,
    ) -> Result<Self, error::ResponseDeserializationError>;
}

/// A request type for a Matrix API endpoint. (trait used for sending requests)
pub trait OutgoingRequest {
    /// A type capturing the expected error conditions the server can return.
    type EndpointError: EndpointError;

    /// Response type returned when the request is successful.
    type IncomingResponse: TryFrom<
        http::Response<Vec<u8>>,
        Error = FromHttpResponseError<Self::EndpointError>,
    >;

    /// Metadata about the endpoint.
    const METADATA: Metadata;

    /// Tries to convert this request into an `http::Request`.
    ///
    /// This method should only fail when called on endpoints that require authentication. It may
    /// also fail with a serialization error in case of bugs in Ruma though.
    ///
    /// The endpoints path will be appended to the given `base_url`, for example
    /// `https://matrix.org`. Since all paths begin with a slash, it is not necessary for the
    /// `base_url` to have a trailing slash. If it has one however, it will be ignored.
    fn try_into_http_request(
        self,
        base_url: &str,
        access_token: Option<&str>,
    ) -> Result<http::Request<Vec<u8>>, IntoHttpError>;
}

/// A request type for a Matrix API endpoint. (trait used for receiving requests)
pub trait IncomingRequest: Sized {
    /// A type capturing the error conditions that can be returned in the response.
    type EndpointError: EndpointError;

    /// Response type to return when the request is successful.
    type OutgoingResponse: TryInto<http::Response<Vec<u8>>, Error = IntoHttpError>;

    /// Metadata about the endpoint.
    const METADATA: Metadata;

    /// Tries to turn the given `http::Request` into this request type.
    fn try_from_http_request(req: http::Request<Vec<u8>>) -> Result<Self, FromHttpRequestError>;
}

/// Marker trait for requests that don't require authentication. (for the client side)
pub trait OutgoingNonAuthRequest: OutgoingRequest {}

/// Marker trait for requests that don't require authentication. (for the server side)
pub trait IncomingNonAuthRequest: IncomingRequest {}

/// Authentication scheme used by the endpoint.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum AuthScheme {
    /// No authentication is performed.
    None,

    /// Authentication is performed by including an access token in the `Authentication` http
    /// header, or an `access_token` query parameter.
    ///
    /// It is recommended to use the header over the query parameter.
    AccessToken,

    /// Authentication is performed by including X-Matrix signatures in the request headers,
    /// as defined in the federation API.
    ServerSignatures,

    /// Authentication is performed by setting the `access_token` query parameter.
    QueryOnlyAccessToken,
}

/// Metadata about an API endpoint.
#[derive(Clone, Debug)]
pub struct Metadata {
    /// A human-readable description of the endpoint.
    pub description: &'static str,

    /// The HTTP method used by this endpoint.
    pub method: Method,

    /// A unique identifier for this endpoint.
    pub name: &'static str,

    /// The path of this endpoint's URL, with variable names where path parameters should be filled
    /// in during a request.
    pub path: &'static str,

    /// Whether or not this endpoint is rate limited by the server.
    pub rate_limited: bool,

    /// What authentication scheme the server uses for this endpoint.
    pub authentication: AuthScheme,
}

#[doc(hidden)]
#[macro_export]
macro_rules! try_deserialize {
    ($kind:ident, $call:expr $(,)?) => {
        $crate::try_deserialize!(@$kind, $kind, $call)
    };
    (@request, $kind:ident, $call:expr) => {
        match $call {
            Ok(val) => val,
            Err(err) => return Err($crate::error::RequestDeserializationError::new(err, $kind).into()),
        }
    };
    (@response, $kind:ident, $call:expr) => {
        match $call {
            Ok(val) => val,
            Err(err) => return Err($crate::error::ResponseDeserializationError::new(err, $kind).into()),
        }
    };
}
<|endoftext|>