interprocess 1.0.0

Interprocess communication toolkit
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
//! Local sockets, an IPC primitive featuring a server and multiple clients connecting to that server using a filesystem path inside a special namespace, each having a private connection to that server.
//!
//! Local sockets are not a real IPC method implemented by the OS — they were introduced because of the difference between named pipes on Windows and Unix: named pipes on Windows are almost the same as Unix domain sockets on Linux while Unix named pipes (which are referred to as FIFO files in this crate to avoid confusion) are like unnamed pipes but identifiable with a filesystem path: there's no distinction between writers and the first reader takes all. **Simply put, local sockets use named pipes on Windows and Unix domain sockets on Unix.**
//!
//! ## Platform-specific namespaces
//! There's one more problem regarding platform differences: since only Linux supports putting Ud-sockets in a separate namespace which is isolated from the filesystem, the `LocalSocketName`/`LocalSocketNameBuf` types are used to identify local sockets rather than `OsStr`/`OsString`: on Unix platforms other than Linux, which includes macOS, all flavors of BSD and possibly other Unix-like systems, the only way to name a Ud-socket is to use a filesystem path. As such, those platforms don't have the namespaced socket creation method available. Complicatng matters further, Windows does not support named pipes in the normal filesystem, meaning that namespaced local sockets are the only functional method on Windows. As a way to solve this issue, `LocalSocketName`/`LocalSocketNameBuf` only provide creation in a platform-specific way, meaning that crate users are required to use conditional compilation to decide on the name for the socket names.

use std::{
    io::{self, IoSlice, IoSliceMut, prelude::*},
    fmt::{self, Formatter, Debug},
    iter::FusedIterator,
    borrow::Cow,
    ffi::{OsStr, OsString, CStr, CString},
    path::{Path, PathBuf},
    str,
};

impmod!{local_socket,
    name_type_support_query as name_type_support_query_impl,
    NAME_TYPE_ALWAYS_SUPPORTED as NAME_TYPE_ALWAYS_SUPPORTED_REAL,
    to_local_socket_name_osstr,
    to_local_socket_name_osstring,
    LocalSocketListener as LocalSocketListenerImpl,
    LocalSocketStream as LocalSocketStreamImpl,
}

/// A local socket server, listening for connections.
///
/// # Example
/// ```no_run
/// use interprocess::local_socket::{LocalSocketListener, LocalSocketStream};
/// use std::io::{self, prelude::*, BufReader};
///
/// fn handle_error(conn: io::Result<LocalSocketStream>) -> Option<LocalSocketStream> {
///     match conn {
///         Ok(val) => Some(val),
///         Err(error) => {
///             eprintln!("Incoming connection failed: {}", error);
///             None
///         }
///     }
/// }
///
/// let listener = LocalSocketListener::bind("/tmp/example.sock")?;
/// for mut conn in listener.incoming().filter_map(handle_error) {
///     conn.write_all(b"Hello from server!\n")?;
///     let mut conn = BufReader::new(conn);
///     let mut buffer = String::new();
///     conn.read_line(&mut buffer);
///     println!("Client answered: {}", buffer);
/// }
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
pub struct LocalSocketListener {
    inner: LocalSocketListenerImpl,
}
impl LocalSocketListener {
    /// Creates a socket server with the specified local socket name.
    #[inline(always)]
    pub fn bind<'a>(name: impl ToLocalSocketName<'a>) -> io::Result<Self> {
        Ok(Self {inner: LocalSocketListenerImpl::bind(name)?})
    }
    /// Listens for incoming connections to the socket, blocking until a client is connected.
    ///
    /// See [`incoming`] for a convenient way to create a main loop for a server.
    ///
    /// [`incoming`]: #method.incoming " "
    #[inline(always)]
    pub fn accept(&self) -> io::Result<LocalSocketStream> {
        Ok(LocalSocketStream {inner: self.inner.accept()?})
    }
    /// Creates an infinite iterator which calls `accept()` with each iteration. Used together with `for` loops to conveniently create a main loop for a socket server.
    ///
    /// # Example
    /// See the struct-level documentation for a full example which already uses this method.
    #[inline(always)]
    pub fn incoming(&self) -> Incoming<'_> {
        Incoming::from(self)
    }
}
impl Debug for LocalSocketListener {
    #[inline(always)]
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        Debug::fmt(&self.inner, f)
    }
}

/// An infinite iterator over incoming client connections of a [`LocalSocketListener`].
///
/// This iterator is created by the [`incoming`] method on [`LocalSocketListener`] — see its documentation for more.
///
/// [`LocalSocketListener`]: struct.LocalSocketListener.html " "
/// [`incoming`]: struct.LocalSocketListener.html#method.incoming " "
#[derive(Debug)]
pub struct Incoming<'a> {
    listener: &'a LocalSocketListener,
}
impl<'a> From<&'a LocalSocketListener> for Incoming<'a> {
    #[inline(always)]
    fn from(listener: &'a LocalSocketListener) -> Self {
        Self {listener}
    }
}
impl Iterator for Incoming<'_> {
    type Item = io::Result<LocalSocketStream>;
    #[inline(always)]
    fn next(&mut self) -> Option<Self::Item> {
        Some(self.listener.accept())
    }
    #[inline(always)]
    fn size_hint(&self) -> (usize, Option<usize>) {
        (usize::MAX, None)
    }
}
impl FusedIterator for Incoming<'_> {}

/// A local socket byte stream, obtained eiter from [`LocalSocketListener`] or by connecting to an existing local socket.
///
/// # Example
/// ```no_run
/// use interprocess::local_socket::LocalSocketStream;
/// use std::io::{prelude::*, BufReader};
///
/// // Replace the path as necessary on Windows.
/// let mut conn = LocalSocketStream::connect("/tmp/example.sock")?;
/// conn.write_all(b"Hello from client!\n")?;
/// let mut conn = BufReader::new(conn);
/// let mut buffer = String::new();
/// conn.read_line(&mut buffer)?;
/// println!("Server answered: {}", buffer);
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
///
/// [`LocalSocketListener`]: struct.LocalSocketListener.html " "
pub struct LocalSocketStream {
    inner: LocalSocketStreamImpl,
}
impl LocalSocketStream {
    /// Connects to a remote local socket server.
    #[inline(always)]
    pub fn connect<'a>(name: impl ToLocalSocketName<'a>) -> io::Result<Self> {
        Ok(Self {inner: LocalSocketStreamImpl::connect(name)?})
    }
}
impl Read for LocalSocketStream {
    #[inline(always)]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.inner.read(buf)
    }
    #[inline(always)]
    fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
        self.inner.read_vectored(bufs)
    }
}
impl Write for LocalSocketStream {
    #[inline(always)]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.inner.write(buf)
    }
    #[inline(always)]
    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
        self.inner.write_vectored(bufs)
    }
    #[inline(always)]
    fn flush(&mut self) -> io::Result<()> {
        self.inner.flush()
    }
}
impl Debug for LocalSocketStream {
    #[inline(always)]
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        Debug::fmt(&self.inner, f)
    }
}
impl_handle_manip!(LocalSocketStream);

/// A name for a local socket.
///
/// Due to vast differences between platforms in terms of how local sockets are named, there needs to be a way to store and process those in a unified way while also retaining platform-specific pecularities. `LocalSocketName` aims to bridge the gap between portability and platform-specific correctness.
///
/// # Creation
/// A separate trait is used to create names from basic strings: [`ToLocalSocketName`]. Aside from being conveniently implemented on every single string type in the standard library, it also provides some special processing. Please read its documentation if you haven't already — the rest of this page assumes you did.
///
/// # Validity
/// As mentioned in the [module-level documentation], not all platforms support all types of local socket names. A name pointing to a filesystem location is only supported on Unix-like systems, and names pointing to an abstract namespace reserved specifically for local sockets are only available on Linux and Windows. Due to the diversity of those differences, `LocalSocketName` does not provide any forced validation by itself — the [`is_supported`] and [`is_always_supported`] checks are not enforced to succeed. Instead, they are intended as helpers for the process of user input validation, if any local socket names are ever read from environment variables, configuration files or other methods of user input.
///
/// If an invalid local socket name is used to create a local socket or connect to it, the creation/connection method will fail.
///
/// [`to_local_socket_name`]: trait.ToLocalSocketName.html " "
/// [module-level documentation]: index.html " "
/// [`is_supported`]: #method.is_supported " "
/// [`is_always_supported`]: #method.is_always_supported " "
pub struct LocalSocketName<'a> {
    inner: Cow<'a, OsStr>,
    namespaced: bool,
}
impl<'a> LocalSocketName<'a> {
    /// Returns `true` if the type of the name is supported by the OS, `false` otherwise.
    ///
    /// The check is performed at runtime. For a conservative compile-time check, see [`is_always_supported`].
    ///
    /// [`is_always_supported`]: #method.is_always_supported " "
    #[inline]
    pub fn is_supported(&self) -> bool {
           (NameTypeSupport::query().namespace_supported() && self.is_namespaced())
        || (NameTypeSupport::query().paths_supported() && !self.is_path())
    }
    /// Returns `true` if the type of the name is supported by the OS, `false` otherwise.
    ///
    /// The check is performed at compile-time. For a check which might return a more permissive result on certain platforms by checking for support at runtime, see [`is_supported`].
    ///
    /// [`is_supported`]: #method.is_supported " "
    #[inline]
    pub fn is_always_supported(&self) -> bool {
           (NameTypeSupport::ALWAYS_AVAILABLE.namespace_supported() && self.is_namespaced())
        || (NameTypeSupport::ALWAYS_AVAILABLE.paths_supported() && self.is_path())
    }
    /// Returns `true` if the value is a namespaced name, `false` otherwise.
    #[inline(always)]
    pub const fn is_namespaced(&self) -> bool {
        self.namespaced
    }
    /// Returns `true` if the value is a filesystem path, `false` otherwise.
    #[inline(always)]
    pub const fn is_path(&self) -> bool {
        !self.namespaced
    }
    /// Returns the name as an `OsStr`. The returned value does not retain the type of the name (whether it was a filesystem path or a namespaced name).
    ///
    /// If you need the value as an owned `OsString` instead, see [`into_inner`].
    ///
    /// [`into_inner`]: #method.into_inner " "
    #[inline(always)]
    pub fn inner(&'a self) -> &'a OsStr {
        &self.inner
    }
    /// Returns the name as an `OsString`. The returned value does not retain the type of the name (whether it was a filesystem path or a namespaced name).
    ///
    /// If you need the value as a borrowed `OsStr` instead, see [`inner`].
    ///
    /// [`inner`]: #method.inner " "
    #[inline(always)]
    pub fn into_inner(self) -> OsString {
        self.inner.into_owned()
    }
    /// Returns the name as a *borrowed* `Cow<'_, OsStr>`. The returned value does not retain the type of the name (whether it was a filesystem path or a namespaced name).
    ///
    /// If you need the value as a borrowed `OsStr`, see [`inner`]; if you need the value as an owned `OsString`, see [`into_inner`].  If you need to take ownership of the `Cow`, see `into_inner_cow`.
    ///
    /// [`inner`]: #method.inner " "
    /// [`into_inner`]: #method.into_inner " "
    /// [`into_inner_cow`]: #method.into_inner_cow " "
    #[inline(always)]
    pub const fn inner_cow(&'a self) -> &'a Cow<'a, OsStr> {
        &self.inner
    }
    /// Returns the name as a `Cow<'_, OsStr>`. The returned value does not retain the type of the name (whether it was a filesystem path or a namespaced name).
    ///
    /// If you need the value as a borrowed `OsStr`, see [`inner`]; if you need the value as an owned `OsString`, see [`into_inner`]. If you don't need to take ownership of the `Cow`, see `inner_cow`.
    ///
    /// [`inner`]: #method.inner " "
    /// [`into_inner`]: #method.into_inner " "
    /// [`inner_cow`]: #method.inner_cow " "
    #[inline(always)]
    pub fn into_inner_cow(self) -> Cow<'a, OsStr> {
        self.inner
    }
    #[inline(always)]
    pub(crate) const fn from_raw_parts(inner: Cow<'a, OsStr>, namespaced: bool) -> Self {
        Self {inner, namespaced}
    }
}

/// Represents which kinds of identifiers can be used for a local socket's name on the current platform.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum NameTypeSupport {
    /// Only filesystem paths can be used.
    ///
    /// This is true for all Unix/POSIX and Unix-like systems other than Linux.
    OnlyPaths,
    /// Only names in an dedicated namespace can be used.
    ///
    /// This is true only for Windows.
    OnlyNamespaced,
    /// Both of the above options are available.
    ///
    /// This is true only for Linux.
    Both,
}
impl NameTypeSupport {
    /// The types of local socket names supported on the current platform regardless of the environment and OS version.
    ///
    /// On most platforms, the value is known at compile time, i.e. the support for paths wasn't introduced in a specific version of the OS or isn't known to be supported at all. **Currently, this includes all supported OSes.** If support is added for an OS which added this functionality in a specific version, this constant will be the most restrictive value for that platform, with [`query`] possibly returning the actual value according to the current version of the OS.
    ///
    /// Simply put, you should probably just use this value for consistency across platforms, unless you really need a specific name type to be supported.
    ///
    /// [`query`]: #method.query " "
    pub const ALWAYS_AVAILABLE: Self = NAME_TYPE_ALWAYS_SUPPORTED_REAL;
    /// Returns the types of local socket names supported on the current platform with the current environment.
    ///
    /// On most platforms, the value is known at compile time, i.e. the support for one of the types wasn't introduced in an update to the OS or isn't known to be supported at all. **Currently, this includes all supported OSes.** For compatibility with OSes which might add the functionality in the future starting with a specific version, this function isn't a `const fn` — see [`ALWAYS_AVAILABLE`] if you need a constant expression.
    ///
    /// [`ALWAYS_AVAILABLE`]: #associatedconstant.ALWAYS_AVAILABLE " "
    #[inline(always)]
    pub fn query() -> Self {
        name_type_support_query_impl()
    }

    /// Returns `true` if, according to `self`, filesystem-based local sockets are supported; `false` otherwise.
    #[inline(always)]
    pub const fn paths_supported(self) -> bool {
        matches!(self, Self::OnlyPaths | Self::Both)
    }
    /// Returns `true` if, according to `self`, namespaced local socket names are supported; `false` otherwise.
    #[inline(always)]
    pub const fn namespace_supported(self) -> bool {
        matches!(self, Self::OnlyNamespaced | Self::Both)
    }
}
/// Types which can be converted to a local socket name.
///
/// The difference between this trait and [`TryInto`]`<`[`LocalSocketName`]`>` is that the latter does not constrain the error type to be [`io::Error`] and thus is not compatible with many types from the standard library which are widely expected to be convertible to Unix domain socket paths. Additionally, this makes the special syntax for namespaced sockets possible (see below).
///
/// ## `@` syntax for namespaced paths
/// As mentioned in the [`LocalSocketName` documentation][`LocalSocketName`], there are two types of which local socket names can be: filesystem paths and namespaced names. Those are isolated from each other — there's no portable way to represent one using another, though certain OSes might provide ways to do so — Windows does, for example. To be able to represent both in a platform-independent fashion, a special syntax was implemented in implementations of this trait on types from the standard library: "@ syntax".
///
/// The feature, in its core, is extremely simple: if the first character in a string is the @ character, the value of the string is interpreted and stored as a namespaced name (otherwise, it's treated as a filesystem path); the @ character is then removed from the string (by taking a subslice which dosen't include it if a string slice is being used; for owned strings, it's simply removed from the string by shifting the entire string towards the beginning). **[`Path`] and [`PathBuf`] are not affected at all — those have explicit path semantics and therefore cannot logically represent namespaced names.**
///
/// This feature is extremely useful both when using hardcoded literals and accepting user input for the path, but sometimes you might want to prevent this behavior. In such a case, you have the following possible approaches:
/// - If the string is a [`OsStr`]/[`OsString`], it can be cheaply converted to a [`Path`]/[`PathBuf`], which do not support the @ syntax
/// - If the string is a [`str`]/[`String`], it can be cheaply converted to [`OsStr`]/[`OsString`]; then the above method can be applied
/// - If the string is a [`CStr`]/[`CString`], it can be converted to [`str`]/[`String`] using the following code:
/// ```
/// # use std::{
/// #     str::Utf8Error,
/// #     ffi::{CStr, CString},
/// # };
/// fn cstr_to_str(val: &CStr) -> Result<&str, Utf8Error> {
///     std::str::from_utf8(val.to_bytes_with_nul())
/// }
/// fn cstring_to_string(val: CString) -> String {
///     String::from_utf8_lossy(&val.into_bytes_with_nul()).into()
/// }
/// ```
/// Then, the method for [`str`]/[`String`] can be applied.
///
/// None of the above conversions perform memory allocations — the only expensive one is [`CStr`]/[`CString`] which performs a check for valid UTF-8.
///
/// [`LocalSocketName`]: struct.LocalSocketName.html " "
/// [`TryInto`]: https://doc.rust-lang.org/std/convert/trait.TryInto.html " "
/// [`str`]: https://doc.rust-lang.org/std/primitive.str.html " "
/// [`String`]: https://doc.rust-lang.org/std/string/struct.String.html " "
/// [`OsStr`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html " "
/// [`OsString`]: https://doc.rust-lang.org/std/ffi/struct.OsString.html " "
/// [`CStr`]: https://doc.rust-lang.org/std/ffi/struct.CStr.html " "
/// [`CString`]: https://doc.rust-lang.org/std/ffi/struct.CString.html " "
/// [`Path`]: https://doc.rust-lang.org/std/path/struct.Path.html " "
/// [`PathBuf`]: https://doc.rust-lang.org/std/path/struct.PathBuf.html " "
pub trait ToLocalSocketName<'a> {
    /// Performs the conversion to a local socket name.
    fn to_local_socket_name(self) -> io::Result<LocalSocketName<'a>>;
}
// TODO document inpls for symmetry with ud-sockets
impl<'a> ToLocalSocketName<'a> for &'a Path {
    #[inline(always)]
    fn to_local_socket_name(self) -> io::Result<LocalSocketName<'a>> {
        Ok(
            LocalSocketName::from_raw_parts(
                Cow::Borrowed(self.as_os_str()),
                false,
            )
        )
    }
}
impl ToLocalSocketName<'static> for PathBuf {
    #[inline(always)]
    fn to_local_socket_name(self) -> io::Result<LocalSocketName<'static>> {
        Ok(
            LocalSocketName::from_raw_parts(
                Cow::Owned(self.into_os_string()),
                false,
            )
        )
    }
}
impl<'a> ToLocalSocketName<'a> for &'a OsStr {
    #[inline(always)]
    fn to_local_socket_name(self) -> io::Result<LocalSocketName<'a>> {
        Ok(to_local_socket_name_osstr(self))
    }
}
impl ToLocalSocketName<'static> for OsString {
    #[inline(always)]
    fn to_local_socket_name(self) -> io::Result<LocalSocketName<'static>> {
        Ok(to_local_socket_name_osstring(self))
    }
}
impl<'a> ToLocalSocketName<'a> for &'a str {
    fn to_local_socket_name(self) -> io::Result<LocalSocketName<'a>> {
        OsStr::new(self).to_local_socket_name()
    }
}
impl ToLocalSocketName<'static> for String {
    fn to_local_socket_name(self) -> io::Result<LocalSocketName<'static>> {
        // OsString docs misleadingly state that a conversion from String requires reallocating
        // and copying, but, according to the std sources, that is not true on any platforms.
        OsString::from(self).to_local_socket_name()
    }
}
impl<'a> ToLocalSocketName<'a> for &'a CStr {
    #[inline]
    fn to_local_socket_name(self) -> io::Result<LocalSocketName<'a>> {
        str::from_utf8(self.to_bytes_with_nul())
            .map(|x| to_local_socket_name_osstr(OsStr::new(x)))
            .map_err(|error| io::Error::new(io::ErrorKind::InvalidData, error))
    }
}
impl ToLocalSocketName<'static> for CString {
    #[inline]
    fn to_local_socket_name(self) -> io::Result<LocalSocketName<'static>> {
        String::from_utf8(self.into_bytes_with_nul())
            .map(|x| to_local_socket_name_osstring(OsString::from(x)))
            .map_err(|error| io::Error::new(io::ErrorKind::InvalidData, error))
    }
}

#[cfg(test)]
mod test {
    use crate::local_socket::{LocalSocketListener, LocalSocketStream};
    #[test]
    fn basic() {
        use std::{
            io::{self, prelude::*, BufReader},
            sync::{Arc, Barrier},
        };

        // We're using a barrier here to avoid the client attempting to connect
        // before the server creates the socket
        let barrier = Arc::new(Barrier::new(2));
        let server_barrier = Arc::clone(&barrier);
        
        std::thread::spawn(move || {
            fn handle_error(
                connection: io::Result<LocalSocketStream>,
            ) -> Option<LocalSocketStream> {
                match connection {
                    Ok(val) => Some(val),
                    Err(error) => {
                        panic!("Incoming connection failed: {}", error);
                    }
                }
            }

            let listener = LocalSocketListener::bind("/tmp/example.sock").unwrap();
            server_barrier.wait();
            for mut conn in listener.incoming().filter_map(handle_error) {
                println!("Incoming connection!");
                conn.write_all(b"Hello from server!\n").unwrap();
                // Add buffering to the connection to read a line.
                let mut conn = BufReader::new(conn);
                let mut buffer = String::new();
                conn.read_line(&mut buffer).unwrap();
                println!("Client answered: {}", buffer);
            }
        });

        barrier.wait();
        let h2 = std::thread::spawn(move || {
            let mut conn = LocalSocketStream::connect("/tmp/example.sock").unwrap();
            conn.write_all(b"Hello from client!\n").unwrap();
            let mut conn = BufReader::new(conn);
            let mut buffer = String::new();
            conn.read_line(&mut buffer).unwrap();
            println!("Server answered: {}", buffer);
        });
        h2.join().unwrap();
    }
}