You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

188 lines
6.3 KiB

  1. /*
  2. * meli - melib library
  3. *
  4. * Copyright 2020 Manos Pitsidianakis
  5. *
  6. * This file is part of meli.
  7. *
  8. * meli is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * meli is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with meli. If not, see <http://www.gnu.org/licenses/>.
  20. */
  21. #[cfg(feature = "deflate_compression")]
  22. use flate2::{read::DeflateDecoder, write::DeflateEncoder, Compression};
  23. #[derive(Debug)]
  24. pub enum Connection {
  25. Tcp(std::net::TcpStream),
  26. Fd(std::os::unix::io::RawFd),
  27. #[cfg(feature = "imap_backend")]
  28. Tls(native_tls::TlsStream<Self>),
  29. #[cfg(feature = "deflate_compression")]
  30. Deflate {
  31. inner: DeflateEncoder<DeflateDecoder<Box<Self>>>,
  32. },
  33. }
  34. use Connection::*;
  35. impl Connection {
  36. pub const IO_BUF_SIZE: usize = 64 * 1024;
  37. #[cfg(feature = "deflate_compression")]
  38. pub fn deflate(self) -> Self {
  39. Connection::Deflate {
  40. inner: DeflateEncoder::new(
  41. DeflateDecoder::new_with_buf(Box::new(self), vec![0; Self::IO_BUF_SIZE]),
  42. Compression::default(),
  43. ),
  44. }
  45. }
  46. pub fn set_nonblocking(&self, nonblocking: bool) -> std::io::Result<()> {
  47. match self {
  48. Tcp(ref t) => t.set_nonblocking(nonblocking),
  49. #[cfg(feature = "imap_backend")]
  50. Tls(ref t) => t.get_ref().set_nonblocking(nonblocking),
  51. Fd(fd) => {
  52. //FIXME TODO Review
  53. nix::fcntl::fcntl(
  54. *fd,
  55. nix::fcntl::FcntlArg::F_SETFL(if nonblocking {
  56. nix::fcntl::OFlag::O_NONBLOCK
  57. } else {
  58. !nix::fcntl::OFlag::O_NONBLOCK
  59. }),
  60. )
  61. .map_err(|err| {
  62. std::io::Error::from_raw_os_error(err.as_errno().map(|n| n as i32).unwrap_or(0))
  63. })?;
  64. Ok(())
  65. }
  66. #[cfg(feature = "deflate_compression")]
  67. Deflate { ref inner, .. } => inner.get_ref().get_ref().set_nonblocking(nonblocking),
  68. }
  69. }
  70. pub fn set_read_timeout(&self, dur: Option<std::time::Duration>) -> std::io::Result<()> {
  71. match self {
  72. Tcp(ref t) => t.set_read_timeout(dur),
  73. #[cfg(feature = "imap_backend")]
  74. Tls(ref t) => t.get_ref().set_read_timeout(dur),
  75. Fd(_) => Ok(()),
  76. #[cfg(feature = "deflate_compression")]
  77. Deflate { ref inner, .. } => inner.get_ref().get_ref().set_read_timeout(dur),
  78. }
  79. }
  80. pub fn set_write_timeout(&self, dur: Option<std::time::Duration>) -> std::io::Result<()> {
  81. match self {
  82. Tcp(ref t) => t.set_write_timeout(dur),
  83. #[cfg(feature = "imap_backend")]
  84. Tls(ref t) => t.get_ref().set_write_timeout(dur),
  85. Fd(_) => Ok(()),
  86. #[cfg(feature = "deflate_compression")]
  87. Deflate { ref inner, .. } => inner.get_ref().get_ref().set_write_timeout(dur),
  88. }
  89. }
  90. }
  91. impl Drop for Connection {
  92. fn drop(&mut self) {
  93. if let Fd(fd) = self {
  94. let _ = nix::unistd::close(*fd);
  95. }
  96. }
  97. }
  98. impl std::io::Read for Connection {
  99. fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
  100. match self {
  101. Tcp(ref mut t) => t.read(buf),
  102. #[cfg(feature = "imap_backend")]
  103. Tls(ref mut t) => t.read(buf),
  104. Fd(f) => {
  105. use std::os::unix::io::{FromRawFd, IntoRawFd};
  106. let mut f = unsafe { std::fs::File::from_raw_fd(*f) };
  107. let ret = f.read(buf);
  108. let _ = f.into_raw_fd();
  109. ret
  110. }
  111. #[cfg(feature = "deflate_compression")]
  112. Deflate { ref mut inner, .. } => inner.read(buf),
  113. }
  114. }
  115. }
  116. impl std::io::Write for Connection {
  117. fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
  118. match self {
  119. Tcp(ref mut t) => t.write(buf),
  120. #[cfg(feature = "imap_backend")]
  121. Tls(ref mut t) => t.write(buf),
  122. Fd(f) => {
  123. use std::os::unix::io::{FromRawFd, IntoRawFd};
  124. let mut f = unsafe { std::fs::File::from_raw_fd(*f) };
  125. let ret = f.write(buf);
  126. let _ = f.into_raw_fd();
  127. ret
  128. }
  129. #[cfg(feature = "deflate_compression")]
  130. Deflate { ref mut inner, .. } => inner.write(buf),
  131. }
  132. }
  133. fn flush(&mut self) -> std::io::Result<()> {
  134. match self {
  135. Tcp(ref mut t) => t.flush(),
  136. #[cfg(feature = "imap_backend")]
  137. Tls(ref mut t) => t.flush(),
  138. Fd(f) => {
  139. use std::os::unix::io::{FromRawFd, IntoRawFd};
  140. let mut f = unsafe { std::fs::File::from_raw_fd(*f) };
  141. let ret = f.flush();
  142. let _ = f.into_raw_fd();
  143. ret
  144. }
  145. #[cfg(feature = "deflate_compression")]
  146. Deflate { ref mut inner, .. } => inner.flush(),
  147. }
  148. }
  149. }
  150. impl std::os::unix::io::AsRawFd for Connection {
  151. fn as_raw_fd(&self) -> std::os::unix::io::RawFd {
  152. match self {
  153. Tcp(ref t) => t.as_raw_fd(),
  154. #[cfg(feature = "imap_backend")]
  155. Tls(ref t) => t.get_ref().as_raw_fd(),
  156. Fd(f) => *f,
  157. #[cfg(feature = "deflate_compression")]
  158. Deflate { ref inner, .. } => inner.get_ref().get_ref().as_raw_fd(),
  159. }
  160. }
  161. }
  162. pub fn lookup_ipv4(host: &str, port: u16) -> crate::Result<std::net::SocketAddr> {
  163. use std::net::ToSocketAddrs;
  164. let addrs = (host, port).to_socket_addrs()?;
  165. for addr in addrs {
  166. if let std::net::SocketAddr::V4(_) = addr {
  167. return Ok(addr);
  168. }
  169. }
  170. Err(
  171. crate::error::MeliError::new(format!("Could not lookup address {}:{}", host, port))
  172. .set_kind(crate::error::ErrorKind::Network),
  173. )
  174. }