Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Add initial implementation for netcat #28

Open
wants to merge 19 commits into
base: master
Choose a base branch
from

Conversation

rdzhou
Copy link

@rdzhou rdzhou commented Jul 16, 2018

Main features of netcat is added. The rest remains to be added.

@mssun
Copy link
Contributor

mssun commented Jul 16, 2018

  • Please add [WIP] prefix in the title if you think it is not ready for reviewing/merging.
  • The PR didn't pass the CI because of testing (try to run cargo test first). You can add a testing file (test_nc.rs) to bypass the check.

Copy link
Contributor

@Arcterus Arcterus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I only commented on repeated issues once, so several occur more than once.

extern crate libc;
extern crate socket2;

use std;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You shouldn't need to include this.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

use mio::{Events, Event, Poll, Ready, PollOpt, Token};
use libc::{AF_UNSPEC, AF_INET, AF_INET6, AF_UNIX};
use std::io;
use std::net::{SocketAddr};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there's only one member that you are trying to use from a module, usually you'd just do use std::net::SocketAddr instead of use std::net::{SocketAddr}.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

))
}

fn build_ports(ports: &str) -> Result<Vec<u16>, MesaError>{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you include super::Result, you should be able to just do Result<Vec<u16>>. You could also just do super::Result<Vec<u16>>.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since there are not just one type of Result, I think it's better to keep all the Result consistent and make Ok and Err explicit.

let port_list = match ports.parse::<u16>() {
Ok(port) => port,
Err(_) => {
return mesaerr_result(&format!("invalid port[s] {}", ports));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that you should create a type like the following rather than using mesaerr_result() everywhere:

use std::num::ParseIntError;

#[derive(Debug, Fail)]
enum NcError {
    #[fail(display = "invalid port(s) {}: {}", ports, err)]
    ParsePort {
        #[cause] err: ParseIntError,
        ports: String,
    },
    // more errors go here
}

You can then change this function to something like:

fn build_ports(ports: &str) -> super::Result<Vec<u16>> {
    ports
        .parse::<u16>()
        .map(|port| vec![port])
        .map_err(|e| NcError::ParsePort { err: e, ports: ports.to_string() })
}

Ok(vec!(port_list))
}

fn warn(msg: &str) {
Copy link
Contributor

@Arcterus Arcterus Jul 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would be fine if the utility was written normally (i.e. as a standalone binary), but because mesabox can be included into other projects as a library, we need to be able to write to custom stdin/stdout/stderr (as in, we need to be able to write to a Vec<u8> or perhaps to a File rather than Stderr). This issue is primarily what UtilSetup is meant to solve. This function should instead be:

fn warn<S: UtilSetup>(setup: &mut S, msg: &str) {
    let _ = write!(setup.error(), "{}", msg);
}

I haven't fully checked where you use warn() (so what I'm about to say may not fully apply), but there is also display_msg!(), which prints the name of the utility + whatever you want to write to the given output stream (e.g. display_msg!(setup.error(), "{}", msg)).

I probably need to document the structure of the framework somewhere to avoid this sort of confusion.

s_addr.clone().unwrap()
} else {
let nf = NamedTempFile::new()?;
let path = String::from(nf.path().to_str().unwrap());
Copy link
Contributor

@Arcterus Arcterus Jul 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than a String, this should most likely be a Path or PathBuf. You might be able to get Path to work by giving NcOptions a lifetime and not taking ownership of ArgMatches (i.e. use &mut ArgMatches instead).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Path won't work since nc doesn't only work for unix. For TCP/UDP, the type is not path.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn’t unix_dg_tmp_socket just used for Unix sockets though? I scanned through the code briefly and didn’t notice anything that indicated otherwise, but let me know if I missed something.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes unix_dg_tmp_socket is only for unix socket. However, after I changed it to Path, I found that I had to immediately convert it to string because the functions consuming it also handle TCP/UDP and cannot take Path. Besides, no Path-related action is performed so there is no benefit to use Path.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What exactly requires conversion into a string? I believe I have this working fine using Paths locally (although to avoid some allocations the code would probably need to be restructured to not return NcOptions).

The benefit of using Path is you don't need to (most likely uselessly) check if the path is valid UTF-8 before converting it into a string.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know what you mean now. Thank you for the explanation.


let mut unix_dg_tmp_socket = String::new();

/* Get name of temporary socket for unix datagram client */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think most people use // for single-line comments in Rust.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

opts: &'a NcOptions,
poll: Poll,
net_interest: Ready,
event_stdin: EventedFd<'a>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because of UtilSetup, this will need to check setup.input().raw_fd() rather than just using stdin. If the result is None, we can just assume there is no input (it's either something like Vec<u8>, which has no file descriptor, or io::Empty).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

unix_dg_tmp_socket = if s_addr.is_some() {
s_addr.clone().unwrap()
} else {
let nf = NamedTempFile::new()?;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this actually work? I'd assume the temporary file would be dropped and deleted at the end of scope.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. It works.

self.netinbufpos >= BUFSIZE
}

fn remove_stdin(&mut self) -> std::io::Result<()> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should probably use io::Result<()> instead of std::io::Result<()>.

Copy link
Contributor

@mssun mssun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are a lot of space to improve your code quality. Please try to polish it multiple times.

build.rs Outdated
@@ -31,6 +31,7 @@ fn create_util_map() -> HashMap<&'static str, &'static str> {
hashmap.insert("head", "posix");
hashmap.insert("sh", "posix");
hashmap.insert("sleep", "posix");
hashmap.insert("nc", "networking");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this line should be put with ping (which is in the "networking section).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

let mut portlist = vec!();
let lflag = matches.is_present("l");
let mut host = String::from("127.0.0.1");
let uport:String;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be a space after :.

  • let uport: String;

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@mssun mssun changed the title Add initial implementation for netcat [WIP] Add initial implementation for netcat Jul 18, 2018
@rdzhou rdzhou force-pushed the master branch 2 times, most recently from 0bf5436 to e5f036d Compare July 26, 2018 08:06
@codecov
Copy link

codecov bot commented Aug 6, 2018

Codecov Report

Merging #28 into master will decrease coverage by 1.98%.
The diff coverage is 0%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master      #28      +/-   ##
==========================================
- Coverage   19.95%   17.96%   -1.99%     
==========================================
  Files          46       47       +1     
  Lines        4680     5198     +518     
  Branches     1081     1274     +193     
==========================================
  Hits          934      934              
- Misses       3355     3873     +518     
  Partials      391      391
Impacted Files Coverage Δ
libmesabox/src/lib.rs 59.01% <ø> (ø) ⬆️
libmesabox/src/networking/nc/mod.rs 0% <0%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update c5674c4...d98eb5c. Read the comment docs.

@mssun
Copy link
Contributor

mssun commented Sep 1, 2018

I plan to refactor your code. Could you help me to write some integration tests? Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants