Skip to content
Snippets Groups Projects
Commit dbe18b92 authored by jD91mZM2's avatar jD91mZM2
Browse files

Merge branch 'netdb' into 'master'

Netdb

See merge request !156
parents 3dbf9f87 07eb658a
No related branches found
No related tags found
1 merge request!156Netdb
Pipeline #1207 failed
Showing
with 1385 additions and 52 deletions
...@@ -10,6 +10,7 @@ pub mod fnmatch; ...@@ -10,6 +10,7 @@ pub mod fnmatch;
pub mod grp; pub mod grp;
pub mod inttypes; pub mod inttypes;
pub mod locale; pub mod locale;
pub mod netdb;
pub mod netinet_in; pub mod netinet_in;
//pub mod pthread; //pub mod pthread;
pub mod pwd; pub mod pwd;
......
sys_includes = ["sys/socket.h", "netinet/in.h"]
include_guard = "_NETDB_H"
language = "C"
style = "Tag"
[enum]
prefix_with_name = true
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use alloc::String;
use alloc::Vec;
#[derive(Clone, Debug)]
pub struct DnsAnswer {
pub name: String,
pub a_type: u16,
pub a_class: u16,
pub ttl_a: u16,
pub ttl_b: u16,
pub data: Vec<u8>
}
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
pub use self::answer::DnsAnswer;
pub use self::query::DnsQuery;
use core::slice;
use core::u16;
use alloc::String;
use alloc::Vec;
mod answer;
mod query;
#[allow(non_camel_case_types)]
#[derive(Copy, Clone, Debug, Default)]
#[repr(packed)]
pub struct n16 {
inner: u16
}
impl n16 {
pub fn as_bytes(&self) -> &[u8] {
unsafe { slice::from_raw_parts((&self.inner as *const u16) as *const u8, 2) }
}
pub fn from_bytes(bytes: &[u8]) -> Self {
n16 {
inner: unsafe { slice::from_raw_parts(bytes.as_ptr() as *const u16, bytes.len()/2)[0] }
}
}
}
impl From<u16> for n16 {
fn from(value: u16) -> Self {
n16 {
inner: value.to_be()
}
}
}
impl From<n16> for u16 {
fn from(value: n16) -> Self {
u16::from_be(value.inner)
}
}
#[derive(Clone, Debug)]
pub struct Dns {
pub transaction_id: u16,
pub flags: u16,
pub queries: Vec<DnsQuery>,
pub answers: Vec<DnsAnswer>
}
impl Dns {
pub fn compile(&self) -> Vec<u8> {
let mut data = Vec::new();
macro_rules! push_u8 {
($value:expr) => {
data.push($value);
};
};
macro_rules! push_n16 {
($value:expr) => {
data.extend_from_slice(n16::from($value).as_bytes());
};
};
push_n16!(self.transaction_id);
push_n16!(self.flags);
push_n16!(self.queries.len() as u16);
push_n16!(self.answers.len() as u16);
push_n16!(0);
push_n16!(0);
for query in self.queries.iter() {
for part in query.name.split('.') {
push_u8!(part.len() as u8);
data.extend_from_slice(part.as_bytes());
}
push_u8!(0);
push_n16!(query.q_type);
push_n16!(query.q_class);
}
data
}
pub fn parse(data: &[u8]) -> Result<Self, String> {
let name_ind = 0b11000000;
let mut i = 0;
macro_rules! pop_u8 {
() => {
{
i += 1;
if i > data.len() {
return Err(format!("{}: {}: pop_u8", file!(), line!()));
}
data[i - 1]
}
};
};
macro_rules! pop_n16 {
() => {
{
i += 2;
if i > data.len() {
return Err(format!("{}: {}: pop_n16", file!(), line!()));
}
u16::from(n16::from_bytes(&data[i - 2 .. i]))
}
};
};
macro_rules! pop_data {
() => {
{
let mut data = Vec::new();
let data_len = pop_n16!();
for _data_i in 0..data_len {
data.push(pop_u8!());
}
data
}
};
};
macro_rules! pop_name {
() => {
{
let mut name = String::new();
let old_i = i;
loop {
let name_len = pop_u8!();
if name_len & name_ind == name_ind {
i -= 1;
i = (pop_n16!() - ((name_ind as u16) << 8)) as usize;
continue;
}
if name_len == 0 {
break;
}
if ! name.is_empty() {
name.push('.');
}
for _name_i in 0..name_len {
name.push(pop_u8!() as char);
}
}
if i <= old_i {
i = old_i + 2;
}
name
}
};
};
let transaction_id = pop_n16!();
let flags = pop_n16!();
let queries_len = pop_n16!();
let answers_len = pop_n16!();
pop_n16!();
pop_n16!();
let mut queries = Vec::new();
for _query_i in 0..queries_len {
queries.push(DnsQuery {
name: pop_name!(),
q_type: pop_n16!(),
q_class: pop_n16!()
});
}
let mut answers = Vec::new();
for _answer_i in 0..answers_len {
answers.push(DnsAnswer {
name: pop_name!(),
a_type: pop_n16!(),
a_class: pop_n16!(),
ttl_a: pop_n16!(),
ttl_b: pop_n16!(),
data: pop_data!()
});
}
Ok(Dns {
transaction_id: transaction_id,
flags: flags,
queries: queries,
answers: answers,
})
}
}
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use alloc::String;
#[derive(Clone, Debug)]
pub struct DnsQuery {
pub name: String,
pub q_type: u16,
pub q_class: u16
}
use alloc::string::String;
use platform::rawfile::RawFile;
use platform::Line;
use platform::rlb::RawLineBuffer;
use c_str::CString;
pub fn get_dns_server() -> String {
let fd = match RawFile::open(&CString::new("/etc/resolv.conf").unwrap(), 0, 0) {
Ok(fd) => fd,
Err(_) => return String::new() // TODO: better error handling
};
let mut rlb = RawLineBuffer::new(*fd);
while let Line::Some(line) = rlb.next() {
if line.starts_with(b"nameserver ") {
return String::from_utf8(line[11..].to_vec()).unwrap_or_default();
}
}
// TODO: better error handling
String::new()
}
This diff is collapsed.
use alloc::string::String;
use c_str::CString;
use platform::rawfile::file_read_all;
pub fn get_dns_server() -> String {
String::from_utf8(file_read_all(&CString::new("/etc/net/dns").unwrap()).unwrap()).unwrap()
}
...@@ -7,7 +7,7 @@ pub type in_addr_t = u32; ...@@ -7,7 +7,7 @@ pub type in_addr_t = u32;
pub type in_port_t = u16; pub type in_port_t = u16;
#[repr(C)] #[repr(C)]
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy, Default)]
pub struct in_addr { pub struct in_addr {
pub s_addr: in_addr_t, pub s_addr: in_addr_t,
} }
...@@ -18,10 +18,12 @@ pub struct in6_addr { ...@@ -18,10 +18,12 @@ pub struct in6_addr {
} }
#[repr(C)] #[repr(C)]
#[derive(Debug, Default)]
pub struct sockaddr_in { pub struct sockaddr_in {
pub sin_family: sa_family_t, pub sin_family: sa_family_t,
pub sin_port: in_port_t, pub sin_port: in_port_t,
pub sin_addr: in_addr, pub sin_addr: in_addr,
pub _pad: [c_char; 8],
} }
#[repr(C)] #[repr(C)]
......
...@@ -7,7 +7,7 @@ use c_str::CStr; ...@@ -7,7 +7,7 @@ use c_str::CStr;
use header::{errno, fcntl}; use header::{errno, fcntl};
use platform; use platform;
use platform::types::*; use platform::types::*;
use platform::RawFile; use platform::{Line, RawFile, RawLineBuffer};
use platform::{Pal, Sys}; use platform::{Pal, Sys};
#[repr(C)] #[repr(C)]
...@@ -56,54 +56,16 @@ where ...@@ -56,54 +56,16 @@ where
Err(_) => return OptionPasswd::Error, Err(_) => return OptionPasswd::Error,
}; };
let mut buf = Vec::new(); let mut rlb = RawLineBuffer::new(*file);
let mut newline = None;
loop { loop {
// TODO when nll becomes a thing: let line = match rlb.next() {
// let mut newline; Line::Error => return OptionPasswd::Error,
Line::EOF => return OptionPasswd::NotFound,
// WORKAROUND: Line::Some(line) => line
if let Some(newline) = newline { };
buf.drain(..newline + 1);
}
// Read until newline
loop {
newline = buf.iter().position(|b| *b == b'\n');
if newline.is_some() {
break;
}
let len = buf.len();
if len >= buf.capacity() {
buf.reserve(1024);
}
unsafe {
let capacity = buf.capacity();
buf.set_len(capacity);
}
let read = Sys::read(*file, &mut buf[len..]);
unsafe {
buf.set_len(len + read as usize);
}
if read == 0 {
return OptionPasswd::NotFound;
}
if read < 0 {
return OptionPasswd::Error;
}
}
// Parse into passwd // Parse into passwd
let newline = newline.unwrap(); // safe because it doesn't break the loop otherwise
let line = &buf[..newline];
let mut parts: [&[u8]; 7] = [&[]; 7]; let mut parts: [&[u8]; 7] = [&[]; 7];
for (i, part) in line.splitn(7, |b| *b == b':').enumerate() { for (i, part) in line.splitn(7, |b| *b == b':').enumerate() {
parts[i] = part; parts[i] = part;
......
use core::fmt::Write as CoreWrite; use core::fmt::Write as CoreWrite;
use core::{slice, str}; use core::{slice, str, ptr};
use platform::types::*; use platform::types::*;
use platform::{self, Write}; use platform::{self, Write};
...@@ -61,8 +61,11 @@ pub unsafe fn printf<W: Write>(w: W, format: *const c_char, mut ap: VaList) -> c ...@@ -61,8 +61,11 @@ pub unsafe fn printf<W: Write>(w: W, format: *const c_char, mut ap: VaList) -> c
let a = ap.get::<*const c_char>(); let a = ap.get::<*const c_char>();
found_percent = false; found_percent = false;
if a != ptr::null() {
w.write_str(str::from_utf8_unchecked(platform::c_str(a))) w.write_str(str::from_utf8_unchecked(platform::c_str(a)))
} else {
w.write_str("NULL")
}
} }
'u' => { 'u' => {
let a = ap.get::<c_uint>(); let a = ap.get::<c_uint>();
......
...@@ -109,6 +109,7 @@ pub unsafe extern "C" fn strcasecmp(mut first: *const c_char, mut second: *const ...@@ -109,6 +109,7 @@ pub unsafe extern "C" fn strcasecmp(mut first: *const c_char, mut second: *const
} }
0 0
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn strncasecmp( pub unsafe extern "C" fn strncasecmp(
mut first: *const c_char, mut first: *const c_char,
......
sys_includes = ["stddef.h", "stdint.h", "sys/types.h"] sys_includes = ["stddef.h", "stdint.h", "sys/types.h"]
include_guard = "_SYS_SOCKET_H" include_guard = "_SYS_SOCKET_H"
style = "Tag" style = "Both"
language = "C" language = "C"
[defines] [defines]
......
...@@ -14,6 +14,7 @@ pub type sa_family_t = u16; ...@@ -14,6 +14,7 @@ pub type sa_family_t = u16;
pub type socklen_t = u32; pub type socklen_t = u32;
#[repr(C)] #[repr(C)]
#[derive(Default)]
pub struct sockaddr { pub struct sockaddr {
pub sa_family: sa_family_t, pub sa_family: sa_family_t,
data: [c_char; 14], data: [c_char; 14],
......
...@@ -44,7 +44,7 @@ pub(crate) const MON_NAMES: [&str; 12] = [ ...@@ -44,7 +44,7 @@ pub(crate) const MON_NAMES: [&str; 12] = [
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
]; ];
pub(crate) const CLOCK_REALTIME: clockid_t = 0; pub const CLOCK_REALTIME: clockid_t = 0;
pub const CLOCK_MONOTONIC: clockid_t = 1; pub const CLOCK_MONOTONIC: clockid_t = 1;
pub(crate) const CLOCK_PROCESS_CPUTIME_ID: clockid_t = 2; pub(crate) const CLOCK_PROCESS_CPUTIME_ID: clockid_t = 2;
......
...@@ -29,6 +29,9 @@ pub use self::rawfile::RawFile; ...@@ -29,6 +29,9 @@ pub use self::rawfile::RawFile;
pub mod rawfile; pub mod rawfile;
pub use self::rlb::{Line, RawLineBuffer};
pub mod rlb;
use self::types::*; use self::types::*;
pub mod types; pub mod types;
......
use alloc::Vec;
use core::ops::Deref; use core::ops::Deref;
use super::{types::*, Pal, Sys}; use super::{types::*, Pal, Sys};
...@@ -46,3 +47,34 @@ impl Deref for RawFile { ...@@ -46,3 +47,34 @@ impl Deref for RawFile {
&self.0 &self.0
} }
} }
pub fn file_read_all(path: &CStr) -> Result<Vec<u8>, ()> {
let file = RawFile::open(path, 0, 0o644)?;
let mut buf = Vec::new();
let mut len = 0;
loop {
if len >= buf.capacity() {
buf.reserve(32);
unsafe {
let capacity = buf.capacity();
buf.set_len(capacity);
}
}
let read = Sys::read(*file, &mut buf[len..]);
len += read as usize;
if read == 0 {
unsafe { buf.set_len(len); }
return Ok(buf);
}
if read < 0 {
unsafe { buf.set_len(len); }
return Err(());
}
}
}
use alloc::vec::Vec;
use platform::{Pal, Sys};
use platform::types::*;
use header::unistd::{lseek, SEEK_SET};
/// Implements an `Iterator` which returns on either newline or EOF.
#[derive(Clone)]
pub struct RawLineBuffer {
pub fd: c_int,
buf: Vec<u8>,
newline: Option<usize>,
read: usize
}
#[derive(PartialEq)]
pub enum Line<'a> {
Error,
EOF,
Some(&'a [u8])
}
impl RawLineBuffer {
pub const fn new(fd: c_int) -> Self {
Self {
fd: fd,
buf: Vec::new(),
newline: None,
read: 0
}
}
// Can't use iterators because we want to return a reference.
// See https://stackoverflow.com/a/30422716/5069285
pub fn next(&mut self) -> Line {
// Remove last line
if let Some(newline) = self.newline {
self.buf.drain(..newline + 1);
}
loop {
// Exit if newline was read already
self.newline = self.buf.iter().position(|b| *b == b'\n');
if self.newline.is_some() {
break;
}
let len = self.buf.len();
if len >= self.buf.capacity() {
self.buf.reserve(1024);
}
// Create buffer of what's left in the vector, uninitialized memory
unsafe {
let capacity = self.buf.capacity();
self.buf.set_len(capacity);
}
let read = Sys::read(self.fd, &mut self.buf[len..]);
let read_usize = read.max(0) as usize;
// Remove all uninitialized memory that wasn't read
unsafe {
self.buf.set_len(len + read_usize);
}
self.read += read_usize;
if read == 0 {
return Line::EOF;
}
if read < 0 {
return Line::Error;
}
}
let newline = self.newline.unwrap(); // safe because it doesn't break the loop otherwise
Line::Some(&self.buf[..newline])
}
/// Return the byte position of the start of the line
pub fn line_pos(&self) -> usize {
self.read - self.buf.len()
}
/// Seek to a byte position in the file
pub fn seek(&mut self, pos: usize) -> off_t {
let ret = lseek(self.fd, pos as i64, SEEK_SET);
if ret != !0 {
self.read = pos;
}
ret
}
}
...@@ -107,6 +107,7 @@ impl<'a> From<&'a timespec> for redox_timespec { ...@@ -107,6 +107,7 @@ impl<'a> From<&'a timespec> for redox_timespec {
} }
#[repr(C)] #[repr(C)]
#[derive(Default)]
pub struct stat { pub struct stat {
pub st_dev: dev_t, pub st_dev: dev_t,
pub st_ino: ino_t, pub st_ino: ino_t,
......
...@@ -10,17 +10,18 @@ EXPECT_BINS=\ ...@@ -10,17 +10,18 @@ EXPECT_BINS=\
fnmatch \ fnmatch \
locale \ locale \
math \ math \
netdb \
select \ select \
setjmp \ setjmp \
signal \ signal \
stdio/all \ stdio/all \
stdio/setvbuf \
stdio/freopen \ stdio/freopen \
stdio/fwrite \ stdio/fwrite \
stdio/getc_unget \ stdio/getc_unget \
stdio/printf \ stdio/printf \
stdio/rename \ stdio/rename \
stdio/scanf \ stdio/scanf \
stdio/setvbuf \
stdio/sprintf \ stdio/sprintf \
stdlib/a64l \ stdlib/a64l \
stdlib/atof \ stdlib/atof \
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment