|
17 | 17 |
|
18 | 18 | use fmt;
|
19 | 19 | use from_str::FromStr;
|
| 20 | +use io::{mod, IoResult, IoError}; |
| 21 | +use io::net; |
20 | 22 | use iter::Iterator;
|
21 | 23 | use option::{Option, None, Some};
|
| 24 | +use result::{Ok, Err}; |
22 | 25 | use str::StrSlice;
|
23 | 26 | use slice::{MutableCloneableSlice, MutableSlice, ImmutableSlice};
|
| 27 | +use vec::Vec; |
24 | 28 |
|
25 | 29 | pub type Port = u16;
|
26 | 30 |
|
@@ -348,6 +352,109 @@ impl FromStr for SocketAddr {
|
348 | 352 | }
|
349 | 353 | }
|
350 | 354 |
|
| 355 | +pub trait ToSocketAddr { |
| 356 | + fn to_socket_addr(&self) -> IoResult<SocketAddr> { |
| 357 | + self.to_socket_addr_all() |
| 358 | + .and_then(|v| v.into_iter().next().ok_or_else(|| IoError { |
| 359 | + kind: io::InvalidInput, |
| 360 | + desc: "no address available", |
| 361 | + detail: None |
| 362 | + })) |
| 363 | + } |
| 364 | + |
| 365 | + #[inline] |
| 366 | + fn to_socket_addr_all(&self) -> IoResult<Vec<SocketAddr>> { |
| 367 | + self.to_socket_addr().map(|a| vec![a]) |
| 368 | + } |
| 369 | +} |
| 370 | + |
| 371 | +impl ToSocketAddr for SocketAddr { |
| 372 | + #[inline] |
| 373 | + fn to_socket_addr(&self) -> IoResult<SocketAddr> { Ok(*self) } |
| 374 | +} |
| 375 | + |
| 376 | +impl ToSocketAddr for (IpAddr, u16) { |
| 377 | + #[inline] |
| 378 | + fn to_socket_addr(&self) -> IoResult<SocketAddr> { |
| 379 | + let (ip, port) = *self; |
| 380 | + Ok(SocketAddr { ip: ip, port: port }) |
| 381 | + } |
| 382 | +} |
| 383 | + |
| 384 | +fn resolve_socket_addr(s: &str, p: u16) -> IoResult<Vec<SocketAddr>> { |
| 385 | + net::get_host_addresses(s) |
| 386 | + .map(|v| v.into_iter().map(|a| SocketAddr { ip: a, port: p }).collect()) |
| 387 | +} |
| 388 | + |
| 389 | +fn parse_and_resolve_socket_addr(s: &str) -> IoResult<Vec<SocketAddr>> { |
| 390 | + macro_rules! try_opt( |
| 391 | + ($e:expr, $msg:expr) => ( |
| 392 | + match $e { |
| 393 | + Some(r) => r, |
| 394 | + None => return Err(IoError { |
| 395 | + kind: io::InvalidInput, |
| 396 | + desc: $msg, |
| 397 | + detail: None |
| 398 | + }) |
| 399 | + } |
| 400 | + ) |
| 401 | + ) |
| 402 | + |
| 403 | + // split the string by ':' and convert the second part to u16 |
| 404 | + let mut parts_iter = s.rsplitn(2, ':'); |
| 405 | + let port_str = try_opt!(parts_iter.next(), "invalid socket address"); |
| 406 | + let host = try_opt!(parts_iter.next(), "invalid socket address"); |
| 407 | + let port: u16 = try_opt!(FromStr::from_str(port_str), "invalid port value"); |
| 408 | + resolve_socket_addr(host, port) |
| 409 | +} |
| 410 | + |
| 411 | +impl<'a> ToSocketAddr for (&'a str, u16) { |
| 412 | + fn to_socket_addr_all(&self) -> IoResult<Vec<SocketAddr>> { |
| 413 | + let (host, port) = *self; |
| 414 | + |
| 415 | + // try to parse the host as a regular IpAddr first |
| 416 | + match FromStr::from_str(host) { |
| 417 | + Some(addr) => return Ok(vec![SocketAddr { |
| 418 | + ip: addr, |
| 419 | + port: port |
| 420 | + }]), |
| 421 | + None => {} |
| 422 | + } |
| 423 | + |
| 424 | + resolve_socket_addr(host, port) |
| 425 | + } |
| 426 | +} |
| 427 | + |
| 428 | +// accepts strings like 'localhost:12345' |
| 429 | +impl<'a> ToSocketAddr for &'a str { |
| 430 | + fn to_socket_addr(&self) -> IoResult<SocketAddr> { |
| 431 | + // try to parse as a regular SocketAddr first |
| 432 | + match FromStr::from_str(*self) { |
| 433 | + Some(addr) => return Ok(addr), |
| 434 | + None => {} |
| 435 | + } |
| 436 | + |
| 437 | + parse_and_resolve_socket_addr(*self) |
| 438 | + .and_then(|v| v.into_iter().next() |
| 439 | + .ok_or_else(|| IoError { |
| 440 | + kind: io::InvalidInput, |
| 441 | + desc: "no address available", |
| 442 | + detail: None |
| 443 | + }) |
| 444 | + ) |
| 445 | + } |
| 446 | + |
| 447 | + fn to_socket_addr_all(&self) -> IoResult<Vec<SocketAddr>> { |
| 448 | + // try to parse as a regular SocketAddr first |
| 449 | + match FromStr::from_str(*self) { |
| 450 | + Some(addr) => return Ok(vec![addr]), |
| 451 | + None => {} |
| 452 | + } |
| 453 | + |
| 454 | + parse_and_resolve_socket_addr(*self) |
| 455 | + } |
| 456 | +} |
| 457 | + |
351 | 458 |
|
352 | 459 | #[cfg(test)]
|
353 | 460 | mod test {
|
@@ -457,4 +564,48 @@ mod test {
|
457 | 564 | assert_eq!(Ipv6Addr(8, 9, 10, 11, 12, 13, 14, 15).to_string(),
|
458 | 565 | "8:9:a:b:c:d:e:f".to_string());
|
459 | 566 | }
|
| 567 | + |
| 568 | + #[test] |
| 569 | + fn to_socket_addr_socketaddr() { |
| 570 | + let a = SocketAddr { ip: Ipv4Addr(77, 88, 21, 11), port: 12345 }; |
| 571 | + assert_eq!(Ok(a), a.to_socket_addr()); |
| 572 | + assert_eq!(Ok(vec![a]), a.to_socket_addr_all()); |
| 573 | + } |
| 574 | + |
| 575 | + #[test] |
| 576 | + fn to_socket_addr_ipaddr_u16() { |
| 577 | + let a = Ipv4Addr(77, 88, 21, 11); |
| 578 | + let p = 12345u16; |
| 579 | + let e = SocketAddr { ip: a, port: p }; |
| 580 | + assert_eq!(Ok(e), (a, p).to_socket_addr()); |
| 581 | + assert_eq!(Ok(vec![e]), (a, p).to_socket_addr_all()); |
| 582 | + } |
| 583 | + |
| 584 | + #[test] |
| 585 | + fn to_socket_addr_str_u16() { |
| 586 | + let a = SocketAddr { ip: Ipv4Addr(77, 88, 21, 11), port: 24352 }; |
| 587 | + assert_eq!(Ok(a), ("77.88.21.11", 24352u16).to_socket_addr()); |
| 588 | + assert_eq!(Ok(vec![a]), ("77.88.21.11", 24352u16).to_socket_addr_all()); |
| 589 | + |
| 590 | + let a = SocketAddr { ip: Ipv6Addr(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), port: 53 }; |
| 591 | + assert_eq!(Ok(a), ("2a02:6b8:0:1::1", 53).to_socket_addr()); |
| 592 | + assert_eq!(Ok(vec![a]), ("2a02:6b8:0:1::1", 53).to_socket_addr_all()); |
| 593 | + |
| 594 | + let a = SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 23924 }; |
| 595 | + assert!(("localhost", 23924u16).to_socket_addr_all().unwrap().contains(&a)); |
| 596 | + } |
| 597 | + |
| 598 | + #[test] |
| 599 | + fn to_socket_addr_str() { |
| 600 | + let a = SocketAddr { ip: Ipv4Addr(77, 88, 21, 11), port: 24352 }; |
| 601 | + assert_eq!(Ok(a), "77.88.21.11:24352".to_socket_addr()); |
| 602 | + assert_eq!(Ok(vec![a]), "77.88.21.11:24352".to_socket_addr_all()); |
| 603 | + |
| 604 | + let a = SocketAddr { ip: Ipv6Addr(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), port: 53 }; |
| 605 | + assert_eq!(Ok(a), "[2a02:6b8:0:1::1]:53".to_socket_addr()); |
| 606 | + assert_eq!(Ok(vec![a]), "[2a02:6b8:0:1::1]:53".to_socket_addr_all()); |
| 607 | + |
| 608 | + let a = SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 23924 }; |
| 609 | + assert!("localhost:23924".to_socket_addr_all().unwrap().contains(&a)); |
| 610 | + } |
460 | 611 | }
|
0 commit comments