Skip to main content

strate_net_silo/
vfs.rs

1use alloc::vec::Vec;
2use strate_net::syscalls::call;
3
4use smoltcp::{
5    iface::Route,
6    socket::{tcp, udp},
7    wire::{IpAddress, IpEndpoint, Ipv4Address},
8};
9use strat9_syscall::data::IPC_FILE_FLAG_DIRECTORY;
10use strate_net::IpcMessage;
11
12use crate::{
13    ip::{parse_ip, parse_ip_cidr, parse_ipv4, parse_ipv4_cidr, parse_ipv6, parse_ipv6_cidr},
14    ipc::{
15        message_file_id, open_path, read_request, reply_ok, reply_open, reply_read, reply_write,
16        reply_write_data_len, write_data, HANDLE_FLAG_CONTROL, HANDLE_FLAG_DATAGRAM,
17        HANDLE_FLAG_INFO, HANDLE_FLAG_STREAM,
18    },
19    state::{
20        NetworkStrate, OpenedFile, TcpConnState, TcpListenerState, UdpBoundState, UdpConnState,
21    },
22};
23
24impl NetworkStrate {
25    fn insert_open_handle(&mut self, sender: u64, path: &str) -> u64 {
26        let fid = self.new_fid(sender);
27        self.open_handles.insert(fid, OpenedFile::new(path));
28        fid
29    }
30
31    fn reply_open_path(&mut self, sender: u64, path: &str, flags: u32) -> IpcMessage {
32        let fid = self.insert_open_handle(sender, path);
33        reply_open(sender, fid, u64::MAX, flags)
34    }
35
36    fn open_tcp_listener_handle(
37        &mut self,
38        sender: u64,
39        path: &str,
40        port: u16,
41        auto_relisten: bool,
42    ) -> IpcMessage {
43        let rx_buf = tcp::SocketBuffer::new(alloc::vec![0u8; 16384]);
44        let tx_buf = tcp::SocketBuffer::new(alloc::vec![0u8; 16384]);
45        let mut socket = tcp::Socket::new(rx_buf, tx_buf);
46        if socket.listen(port).is_err() {
47            return IpcMessage::error_reply(sender, -98);
48        }
49        let socket = self.sockets.add(socket);
50        let fid = self.insert_open_handle(sender, path);
51        self.tcp_listeners.insert(
52            fid,
53            TcpListenerState {
54                socket,
55                port,
56                auto_relisten,
57            },
58        );
59        reply_open(sender, fid, u64::MAX, HANDLE_FLAG_STREAM)
60    }
61
62    fn open_tcp_connection_handle(
63        &mut self,
64        sender: u64,
65        path: &str,
66        remote_ip: IpAddress,
67        remote_port: u16,
68        local_port: u16,
69    ) -> IpcMessage {
70        let rx_buf = tcp::SocketBuffer::new(alloc::vec![0u8; 16384]);
71        let tx_buf = tcp::SocketBuffer::new(alloc::vec![0u8; 16384]);
72        let socket = tcp::Socket::new(rx_buf, tx_buf);
73        let handle = self.sockets.add(socket);
74        if self
75            .sockets
76            .get_mut::<tcp::Socket>(handle)
77            .connect(
78                self.interface.context(),
79                (remote_ip, remote_port),
80                local_port,
81            )
82            .is_err()
83        {
84            self.sockets.remove(handle);
85            return IpcMessage::error_reply(sender, -111);
86        }
87
88        let fid = self.insert_open_handle(sender, path);
89        self.tcp_connections.insert(
90            fid,
91            TcpConnState {
92                socket: handle,
93                local_port,
94                remote: IpEndpoint::new(remote_ip, remote_port),
95            },
96        );
97        reply_open(sender, fid, u64::MAX, HANDLE_FLAG_STREAM)
98    }
99
100    fn open_udp_connection_handle(
101        &mut self,
102        sender: u64,
103        path: &str,
104        remote: IpEndpoint,
105    ) -> IpcMessage {
106        let Some(local_port) = self.alloc_udp_ephemeral_port() else {
107            return IpcMessage::error_reply(sender, -28);
108        };
109        let Ok(socket) = self.create_udp_socket(local_port) else {
110            return IpcMessage::error_reply(sender, -98);
111        };
112
113        let fid = self.insert_open_handle(sender, path);
114        self.udp_connections.insert(
115            fid,
116            UdpConnState {
117                socket,
118                local_port,
119                remote,
120            },
121        );
122        reply_open(sender, fid, u64::MAX, HANDLE_FLAG_DATAGRAM)
123    }
124
125    pub(crate) fn handle_open(&mut self, msg: &IpcMessage) -> IpcMessage {
126        let path = match open_path(msg) {
127            Ok(path) => path,
128            Err(err) => return IpcMessage::error_reply(msg.sender, err),
129        };
130
131        match path {
132            "" => {
133                let fid = self.insert_open_handle(msg.sender, "");
134                reply_open(msg.sender, fid, u64::MAX, IPC_FILE_FLAG_DIRECTORY)
135            }
136            "ip" | "address" | "prefix" | "netmask" | "broadcast" | "gateway" | "route"
137            | "routes" | "dns" | "resolve" | "ping" | "tcp" | "tcp/listeners"
138            | "tcp/connections" | "tcp/stats" | "udp" | "dhcp" | "ip6" | "ip6/address"
139            | "ip6/gateway" => self.reply_open_path(msg.sender, path, HANDLE_FLAG_INFO),
140            path if path.starts_with("resolve/") => {
141                if path.len() <= 8 {
142                    return IpcMessage::error_reply(msg.sender, -22);
143                }
144                self.reply_open_path(msg.sender, path, HANDLE_FLAG_INFO)
145            }
146            path if path.starts_with("ping/") => {
147                if parse_ipv4(&path[5..]).is_none() {
148                    return IpcMessage::error_reply(msg.sender, -22);
149                }
150                self.reply_open_path(msg.sender, path, HANDLE_FLAG_CONTROL)
151            }
152            path if path.starts_with("ping6/") => {
153                if parse_ipv6(&path[6..]).is_none() {
154                    return IpcMessage::error_reply(msg.sender, -22);
155                }
156                self.reply_open_path(msg.sender, path, HANDLE_FLAG_CONTROL)
157            }
158            path if path.starts_with("tcp/connect/") => {
159                let rest = &path[12..];
160                let parts: Vec<&str> = rest.split('/').collect();
161                if parts.len() < 2 || parts.len() > 3 {
162                    return IpcMessage::error_reply(msg.sender, -22);
163                }
164                let Some(remote_ip) = parse_ip(parts[0]) else {
165                    return IpcMessage::error_reply(msg.sender, -22);
166                };
167                let Some(remote_port) = parts[1].parse::<u16>().ok() else {
168                    return IpcMessage::error_reply(msg.sender, -22);
169                };
170                if remote_port == 0 {
171                    return IpcMessage::error_reply(msg.sender, -22);
172                }
173                let local_port = if parts.len() == 3 {
174                    let Some(local_port) = parts[2].parse::<u16>().ok() else {
175                        return IpcMessage::error_reply(msg.sender, -22);
176                    };
177                    if local_port == 0 {
178                        return IpcMessage::error_reply(msg.sender, -22);
179                    }
180                    local_port
181                } else {
182                    49152 + (self.next_fid as u16 % 16384)
183                };
184                self.open_tcp_connection_handle(
185                    msg.sender,
186                    path,
187                    remote_ip,
188                    remote_port,
189                    local_port,
190                )
191            }
192            path if path.starts_with("tcp/listen-once/") => {
193                let Some(port) = path[16..].parse::<u16>().ok() else {
194                    return IpcMessage::error_reply(msg.sender, -22);
195                };
196                if port == 0 {
197                    return IpcMessage::error_reply(msg.sender, -22);
198                }
199                self.open_tcp_listener_handle(msg.sender, path, port, false)
200            }
201            path if path.starts_with("tcp/listen/") => {
202                let Some(port) = path[11..].parse::<u16>().ok() else {
203                    return IpcMessage::error_reply(msg.sender, -22);
204                };
205                if port == 0 {
206                    return IpcMessage::error_reply(msg.sender, -22);
207                }
208                self.open_tcp_listener_handle(msg.sender, path, port, true)
209            }
210            path if path.starts_with("udp/bind/") => {
211                let Some(port) = path[9..].parse::<u16>().ok() else {
212                    return IpcMessage::error_reply(msg.sender, -22);
213                };
214                if port == 0 || self.udp_port_in_use(port) {
215                    return IpcMessage::error_reply(msg.sender, -98);
216                }
217                let Ok(socket) = self.create_udp_socket(port) else {
218                    return IpcMessage::error_reply(msg.sender, -98);
219                };
220                let fid = self.insert_open_handle(msg.sender, path);
221                self.udp_bound.insert(
222                    fid,
223                    UdpBoundState {
224                        socket,
225                        local_port: port,
226                        last_peer: None,
227                    },
228                );
229                reply_open(msg.sender, fid, u64::MAX, HANDLE_FLAG_DATAGRAM)
230            }
231            path if path.starts_with("udp/connect/") => {
232                let rest = &path[12..];
233                let parts: Vec<&str> = rest.splitn(2, '/').collect();
234                if parts.len() != 2 {
235                    return IpcMessage::error_reply(msg.sender, -22);
236                }
237                let Some(remote_ip) = parse_ip(parts[0]) else {
238                    return IpcMessage::error_reply(msg.sender, -22);
239                };
240                let Some(remote_port) = parts[1].parse::<u16>().ok() else {
241                    return IpcMessage::error_reply(msg.sender, -22);
242                };
243                if remote_port == 0 {
244                    return IpcMessage::error_reply(msg.sender, -22);
245                }
246                self.open_udp_connection_handle(
247                    msg.sender,
248                    path,
249                    IpEndpoint::new(remote_ip, remote_port),
250                )
251            }
252            path if path.starts_with("udp/send/") => {
253                let rest = &path[9..];
254                let parts: Vec<&str> = rest.splitn(2, '/').collect();
255                if parts.len() != 2 {
256                    return IpcMessage::error_reply(msg.sender, -22);
257                }
258                let Some(remote_ip) = parse_ip(parts[0]) else {
259                    return IpcMessage::error_reply(msg.sender, -22);
260                };
261                let Some(remote_port) = parts[1].parse::<u16>().ok() else {
262                    return IpcMessage::error_reply(msg.sender, -22);
263                };
264                if remote_port == 0 {
265                    return IpcMessage::error_reply(msg.sender, -22);
266                }
267                self.open_udp_connection_handle(
268                    msg.sender,
269                    path,
270                    IpEndpoint::new(remote_ip, remote_port),
271                )
272            }
273            path if path.starts_with("route/add/")
274                || path.starts_with("route/del/")
275                || path.starts_with("route/default/set/")
276                || path == "route/default/clear" =>
277            {
278                self.reply_open_path(msg.sender, path, HANDLE_FLAG_CONTROL)
279            }
280            path if path.starts_with("ip/set/")
281                || path.starts_with("ip6/set/")
282                || path.starts_with("dns/set/")
283                || path == "dhcp/enable"
284                || path == "dhcp/disable" =>
285            {
286                self.reply_open_path(msg.sender, path, HANDLE_FLAG_CONTROL)
287            }
288            _ => IpcMessage::error_reply(msg.sender, -2),
289        }
290    }
291
292    pub(crate) fn handle_read(&mut self, msg: &IpcMessage) -> IpcMessage {
293        let (file_id, offset, requested) = read_request(msg);
294
295        // Ownership check: fids are sequential and guessable.
296        if !self.is_owner(file_id, msg.sender) {
297            return IpcMessage::error_reply(msg.sender, -9); // EBADF
298        }
299
300        if let Some(listener) = self.tcp_listeners.get(&file_id).copied() {
301            return self.handle_tcp_read(msg.sender, listener, requested);
302        }
303        if let Some(conn) = self.tcp_connections.get(&file_id).copied() {
304            return self.handle_tcp_conn_read(msg.sender, conn, requested);
305        }
306        if self.udp_bound.contains_key(&file_id) {
307            return self.handle_udp_bound_read(msg.sender, file_id, requested);
308        }
309        if let Some(conn) = self.udp_connections.get(&file_id).copied() {
310            return self.handle_udp_conn_read(msg.sender, file_id, conn, requested);
311        }
312
313        let path = match self.open_handles.get(&file_id) {
314            Some(handle) => handle.path.clone(),
315            None => return IpcMessage::error_reply(msg.sender, -9),
316        };
317
318        let is_ping_path = path.starts_with("ping/") || path.starts_with("ping6/");
319
320        let needs_refresh = offset == 0
321            || self
322                .open_handles
323                .get(&file_id)
324                .and_then(|handle| handle.cached_content.as_ref())
325                .is_none()
326            // Ping paths return dynamic content : one reply per read.
327            // Never serve stale cached data.
328            || is_ping_path;
329
330        if needs_refresh {
331            match self.generate_content(file_id, &path) {
332                Ok(content) => {
333                    if let Some(handle) = self.open_handles.get_mut(&file_id) {
334                        handle.cached_content = Some(content);
335                    }
336                }
337                Err(err) => return IpcMessage::error_reply(msg.sender, err),
338            }
339        }
340
341        let cached = match self
342            .open_handles
343            .get(&file_id)
344            .and_then(|handle| handle.cached_content.as_ref())
345        {
346            Some(content) => content,
347            None => return IpcMessage::error_reply(msg.sender, -9),
348        };
349
350        // Ping endpoints behave like a dequeue, not a seekable file. Reads must
351        // ignore the shared file offset because the preceding write advances it.
352        let start = if is_ping_path {
353            0
354        } else {
355            (offset as usize).min(cached.len())
356        };
357        reply_read(msg.sender, &cached[start..])
358    }
359
360    pub(crate) fn handle_write(&mut self, msg: &IpcMessage) -> IpcMessage {
361        let file_id = message_file_id(msg);
362
363        // Ownership check: fids are sequential and guessable.
364        if !self.is_owner(file_id, msg.sender) {
365            return IpcMessage::error_reply(msg.sender, -9); // EBADF
366        }
367
368        if let Some(listener) = self.tcp_listeners.get(&file_id).copied() {
369            return self.handle_tcp_write(msg.sender, listener, msg);
370        }
371        if let Some(conn) = self.tcp_connections.get(&file_id).copied() {
372            return self.handle_tcp_conn_write(msg.sender, conn, msg);
373        }
374        if self.udp_bound.contains_key(&file_id) {
375            return self.handle_udp_bound_write(msg.sender, file_id, msg);
376        }
377        if let Some(conn) = self.udp_connections.get(&file_id).copied() {
378            return self.handle_udp_conn_write(msg.sender, conn, msg);
379        }
380
381        let path = match self.open_handles.get(&file_id) {
382            Some(handle) => handle.path.clone(),
383            None => return IpcMessage::error_reply(msg.sender, -9),
384        };
385
386        if path.starts_with("ping/") {
387            let Some(target) = parse_ipv4(&path[5..]) else {
388                return IpcMessage::error_reply(msg.sender, -22);
389            };
390            let data_len = u16::from_le_bytes([msg.payload[16], msg.payload[17]]) as usize;
391            let data = write_data(msg);
392            let seq = data
393                .get(0..2)
394                .map(|bytes| u16::from_le_bytes([bytes[0], bytes[1]]))
395                .unwrap_or(0);
396            let _ = call::debug_log(b"[ping] write ping/ target=");
397            let _ = call::debug_log(&target.octets());
398            let _ = call::debug_log(b" seq=");
399            let _ = call::debug_log(&[(seq >> 8) as u8, seq as u8]);
400            let _ = call::debug_log(b"\n");
401            if self.send_ping(target, seq, file_id) {
402                return reply_write(msg.sender, data_len);
403            }
404            let _ = call::debug_log(b"[ping] write: send_ping failed\n");
405            return IpcMessage::error_reply(msg.sender, -11);
406        }
407
408        if path.starts_with("ping6/") {
409            let Some(target) = parse_ipv6(&path[6..]) else {
410                return IpcMessage::error_reply(msg.sender, -22);
411            };
412            let data_len = u16::from_le_bytes([msg.payload[16], msg.payload[17]]) as usize;
413            let data = write_data(msg);
414            let seq = data
415                .get(0..2)
416                .map(|bytes| u16::from_le_bytes([bytes[0], bytes[1]]))
417                .unwrap_or(0);
418            let _ = call::debug_log(b"[ping] write ping6/ target=");
419            let _ = call::debug_log(&target.octets());
420            let _ = call::debug_log(b" seq=");
421            let _ = call::debug_log(&[(seq >> 8) as u8, seq as u8]);
422            let _ = call::debug_log(b"\n");
423            if self.send_ping6(target, seq, file_id) {
424                return reply_write(msg.sender, data_len);
425            }
426            let _ = call::debug_log(b"[ping] write: send_ping6 failed\n");
427            return IpcMessage::error_reply(msg.sender, -11);
428        }
429
430        if let Some(cidr) = path.strip_prefix("ip/set/").and_then(parse_ipv4_cidr) {
431            self.dhcp_enabled = false;
432            self.dns_from_dhcp = false;
433            let gateway = self.ip_config.as_ref().and_then(|cfg| cfg.gateway);
434            self.apply_ipv4_config(cidr, gateway);
435            return reply_write_data_len(msg.sender, msg);
436        } else if path.starts_with("ip/set/") {
437            return IpcMessage::error_reply(msg.sender, -22);
438        }
439
440        if let Some(cidr) = path.strip_prefix("ip6/set/").and_then(parse_ipv6_cidr) {
441            let gateway = self.ipv6_config.as_ref().and_then(|cfg| cfg.gateway);
442            self.apply_ipv6_config(cidr, gateway);
443            return reply_write_data_len(msg.sender, msg);
444        } else if path.starts_with("ip6/set/") {
445            return IpcMessage::error_reply(msg.sender, -22);
446        }
447
448        if let Some(rest) = path.strip_prefix("dns/set/") {
449            let mut parts = rest.split('/');
450            let Some(idx_s) = parts.next() else {
451                return IpcMessage::error_reply(msg.sender, -22);
452            };
453            let Some(ip_s) = parts.next() else {
454                return IpcMessage::error_reply(msg.sender, -22);
455            };
456            if parts.next().is_some() {
457                return IpcMessage::error_reply(msg.sender, -22);
458            }
459            let Some(idx) = idx_s.parse::<usize>().ok() else {
460                return IpcMessage::error_reply(msg.sender, -22);
461            };
462            if idx >= 3 {
463                return IpcMessage::error_reply(msg.sender, -22);
464            }
465            let Some(ip) = parse_ip(ip_s) else {
466                return IpcMessage::error_reply(msg.sender, -22);
467            };
468            self.dhcp_enabled = false;
469            self.dns_from_dhcp = false;
470            self.dns_servers[idx] = if matches!(ip, IpAddress::Ipv4(addr) if addr == Ipv4Address::new(0, 0, 0, 0))
471            {
472                None
473            } else {
474                Some(ip)
475            };
476            if let Some(ref mut cfg) = self.ip_config {
477                cfg.dns[idx] = match self.dns_servers[idx] {
478                    Some(IpAddress::Ipv4(addr)) => Some(addr),
479                    _ => None,
480                };
481            }
482            self.refresh_dns_servers();
483            return reply_write_data_len(msg.sender, msg);
484        }
485
486        if path == "dhcp/enable" {
487            self.enable_dhcp();
488            return reply_write_data_len(msg.sender, msg);
489        }
490
491        if path == "dhcp/disable" {
492            self.dhcp_enabled = false;
493            return reply_write_data_len(msg.sender, msg);
494        }
495
496        if let Some(rest) = path.strip_prefix("route/add/") {
497            let mut parts = rest.split('/');
498            let Some(cidr_s) = parts.next() else {
499                return IpcMessage::error_reply(msg.sender, -22);
500            };
501            let Some(gw_s) = parts.next() else {
502                return IpcMessage::error_reply(msg.sender, -22);
503            };
504            if parts.next().is_some() {
505                return IpcMessage::error_reply(msg.sender, -22);
506            }
507            let Some(cidr) = parse_ip_cidr(cidr_s) else {
508                return IpcMessage::error_reply(msg.sender, -22);
509            };
510            let Some(gw) = parse_ip(gw_s) else {
511                return IpcMessage::error_reply(msg.sender, -22);
512            };
513            let mut full = false;
514            self.interface.routes_mut().update(|table| {
515                if let Some((idx, _)) = table
516                    .iter()
517                    .enumerate()
518                    .find(|(_, route)| route.cidr == cidr)
519                {
520                    let _ = table.remove(idx);
521                }
522                match (cidr, gw) {
523                    (smoltcp::wire::IpCidr::Ipv4(_), IpAddress::Ipv4(_))
524                    | (smoltcp::wire::IpCidr::Ipv6(_), IpAddress::Ipv6(_)) => {
525                        if table
526                            .push(Route {
527                                cidr,
528                                via_router: gw,
529                                preferred_until: None,
530                                expires_at: None,
531                            })
532                            .is_err()
533                        {
534                            full = true;
535                        }
536                    }
537                    _ => {
538                        full = true;
539                    }
540                }
541            });
542            if full {
543                return IpcMessage::error_reply(msg.sender, -28);
544            }
545            return reply_write_data_len(msg.sender, msg);
546        }
547
548        if let Some(rest) = path.strip_prefix("route/del/") {
549            let Some(cidr) = parse_ip_cidr(rest) else {
550                return IpcMessage::error_reply(msg.sender, -22);
551            };
552            let mut removed = false;
553            self.interface.routes_mut().update(|table| {
554                if let Some((idx, _)) = table
555                    .iter()
556                    .enumerate()
557                    .find(|(_, route)| route.cidr == cidr)
558                {
559                    let _ = table.remove(idx);
560                    removed = true;
561                }
562            });
563            if !removed {
564                return IpcMessage::error_reply(msg.sender, -2);
565            }
566            return reply_write_data_len(msg.sender, msg);
567        }
568
569        if let Some(gw_s) = path.strip_prefix("route/default/set/") {
570            let Some(gw) = parse_ip(gw_s) else {
571                return IpcMessage::error_reply(msg.sender, -22);
572            };
573            match gw {
574                IpAddress::Ipv4(gw4) => {
575                    let _ = self.interface.routes_mut().remove_default_ipv4_route();
576                    if self
577                        .interface
578                        .routes_mut()
579                        .add_default_ipv4_route(gw4)
580                        .is_err()
581                    {
582                        return IpcMessage::error_reply(msg.sender, -28);
583                    }
584                    if let Some(ref mut cfg) = self.ip_config {
585                        cfg.gateway = Some(gw4);
586                    }
587                }
588                IpAddress::Ipv6(gw6) => {
589                    let _ = self.interface.routes_mut().remove_default_ipv6_route();
590                    if self
591                        .interface
592                        .routes_mut()
593                        .add_default_ipv6_route(gw6)
594                        .is_err()
595                    {
596                        return IpcMessage::error_reply(msg.sender, -28);
597                    }
598                    if let Some(ref mut cfg) = self.ipv6_config {
599                        cfg.gateway = Some(gw6);
600                    }
601                }
602            }
603            self.refresh_dns_servers();
604            return reply_write_data_len(msg.sender, msg);
605        }
606
607        if path == "route/default/clear" {
608            let _ = self.interface.routes_mut().remove_default_ipv4_route();
609            let _ = self.interface.routes_mut().remove_default_ipv6_route();
610            if let Some(ref mut cfg) = self.ip_config {
611                cfg.gateway = None;
612            }
613            if let Some(ref mut cfg) = self.ipv6_config {
614                cfg.gateway = None;
615            }
616            self.refresh_dns_servers();
617            return reply_write_data_len(msg.sender, msg);
618        }
619
620        IpcMessage::error_reply(msg.sender, -1)
621    }
622
623    pub(crate) fn handle_close(&mut self, msg: &IpcMessage) -> IpcMessage {
624        let file_id = message_file_id(msg);
625
626        // Only the owner may close; also prevents destroying another
627        // process's sockets by guessing its fid.
628        if !self.is_owner(file_id, msg.sender) {
629            return IpcMessage::error_reply(msg.sender, -9); // EBADF
630        }
631        self.forget_handle(file_id);
632        self.open_handles.remove(&file_id);
633        if let Some(listener) = self.tcp_listeners.remove(&file_id) {
634            let _ = self.sockets.remove(listener.socket);
635        }
636        if let Some(conn) = self.tcp_connections.remove(&file_id) {
637            let socket = self.sockets.get_mut::<tcp::Socket>(conn.socket);
638            socket.close();
639            self.lingering_sockets.push(conn.socket);
640        }
641        if let Some(state) = self.udp_bound.remove(&file_id) {
642            let socket = self.sockets.get_mut::<udp::Socket>(state.socket);
643            socket.close();
644            self.sockets.remove(state.socket);
645        }
646        if let Some(conn) = self.udp_connections.remove(&file_id) {
647            let socket = self.sockets.get_mut::<udp::Socket>(conn.socket);
648            socket.close();
649            self.sockets.remove(conn.socket);
650        }
651        reply_ok(msg.sender)
652    }
653}