package tcpip
OCaml TCP/IP networking stack, used in MirageOS
Install
Dune Dependency
Authors
Maintainers
Sources
tcpip-9.0.1.tbz
sha256=fac07ce986811cf5e3d71373d92b631cc30fbef548d6da21b0917212dcf90b03
sha512=01de13f560d58b1524c39619e4e4cb6ebbf069155eb43d0f264aa12b00e0cc8c39792719e3ca46585dd596b692b8e1e3f8c132f005ed9e2d77747c0c158bf4d9
doc/src/tcpip.icmpv4-socket/icmpv4_socket.ml.html
Source file icmpv4_socket.ml
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
open Lwt.Infix type ipaddr = Ipaddr.V4.t type t = { mutable listening_sockets : Lwt_unix.file_descr list } type error = [ `Ip of string ] let pp_error ppf (`Ip s) = Fmt.string ppf s let is_win32 = Sys.os_type = "Win32" let ipproto_icmp = 1 (* according to BSD /etc/protocols *) let port = 0 (* port isn't meaningful in this context *) let safe_close fd = Lwt.catch (fun () -> Lwt_unix.close fd) (function | Unix.Unix_error (Unix.EBADF, _, _) -> Lwt.return_unit | e -> Lwt.fail e) let connect () = Lwt.return { listening_sockets = [] } let disconnect t = Lwt_list.iter_p safe_close t.listening_sockets let pp_sockaddr fmt sa = let open Lwt_unix in match sa with | ADDR_UNIX s -> Format.fprintf fmt "%s" s | ADDR_INET (ip, port) -> Format.fprintf fmt "%s, %d" (Unix.string_of_inet_addr ip) port let src = Logs.Src.create "icmpv4_socket" ~doc:"Mirage ICMPv4 (Sockets Edition)" module Log = (val Logs.src_log src : Logs.LOG) let sendto' fd buf flags dst = if is_win32 then begin (* Lwt on Win32 doesn't support Lwt_bytes.sendto *) let bytes = Bytes.make (Cstruct.length buf) '\000' in Cstruct.blit_to_bytes buf 0 bytes 0 (Cstruct.length buf); Lwt_unix.sendto fd bytes 0 (Bytes.length bytes) flags dst end else Lwt_cstruct.sendto fd buf flags dst let recvfrom' fd buf flags = if is_win32 then begin (* Lwt on Win32 doesn't support Lwt_bytes.recvfrom *) let bytes = Bytes.make (Cstruct.length buf) '\000' in Lwt_unix.recvfrom fd bytes 0 (Bytes.length bytes) flags >>= fun (n, sockaddr) -> Cstruct.blit_from_bytes bytes 0 buf 0 n; Lwt.return (n, sockaddr) end else Lwt_cstruct.recvfrom fd buf flags let write _t ?src:_ ~dst ?ttl:_ttl buf = let open Lwt_unix in let flags = [] in let ipproto_icmp = 1 in (* according to BSD /etc/protocols *) let port = 0 in (* port isn't meaningful in this context *) let fd = socket PF_INET SOCK_RAW ipproto_icmp in let in_addr = Unix.inet_addr_of_string (Ipaddr.V4.to_string dst) in let sockaddr = ADDR_INET (in_addr, port) in Lwt.catch (fun () -> sendto' fd buf flags sockaddr >>= fun sent -> if (sent <> (Cstruct.length buf)) then Log.debug (fun f -> f "short write: %d received vs %d expected" sent (Cstruct.length buf)); Lwt_unix.close fd |> Lwt_result.ok ) (fun exn -> Lwt.return @@ Error (`Ip (Printexc.to_string exn))) let input t ~src ~dst:_ buf = (* some default logic -- respond to echo requests with echo replies *) match Icmpv4_packet.Unmarshal.of_cstruct buf with | Error s -> Log.debug (fun f -> f "Error decomposing an ICMP packet: %s" s); Lwt.return_unit | Ok (icmp, payload) -> let open Icmpv4_packet in match icmp.ty, icmp.subheader with | Icmpv4_wire.Echo_request, Id_and_seq (id, seq) -> let response = { ty = Icmpv4_wire.Echo_reply; code = 0x00; subheader = Id_and_seq (id, seq); } in (* TODO: if `listen` were allowed to report problems, * it would be sensible not to discard the value returned here, * but as it is we can only return () *) write t ~dst:src (Marshal.make_cstruct response ~payload) >>= fun _ -> Lwt.return_unit | _, _ -> Lwt.return_unit let listen t addr fn = let fd = Lwt_unix.socket PF_INET SOCK_RAW ipproto_icmp in t.listening_sockets <- fd :: t.listening_sockets; let sa = Lwt_unix.ADDR_INET (Unix.inet_addr_of_string (Ipaddr.V4.to_string addr), port) in Lwt_unix.bind fd sa >>= fun () -> Log.debug (fun f -> f "Bound ICMP file descriptor to %a" pp_sockaddr sa); let rec loop () = let receive_buffer = Cstruct.create 4096 in recvfrom' fd receive_buffer [] >>= fun (len, _sockaddr) -> (* trim the buffer to the amount of data actually received *) let receive_buffer = Cstruct.sub receive_buffer 0 len in (* On macOS the IP length field is set to a very large value (16384) which probably reflects some kernel datastructure size rather than the real on-the-wire size. This confuses our IPv4 parser so we correct the size here. *) let len = Ipv4_wire.get_len receive_buffer in Ipv4_wire.set_len receive_buffer (min len (Cstruct.length receive_buffer)); Lwt.async (fun () -> fn receive_buffer); loop () in loop ()
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>