package mnet
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>
An implementation of TCP (Transmission Control Protocol) in OCaml for Miou & Solo5
Install
dune-project
Dependency
Authors
Maintainers
Sources
mnet-0.0.1.tbz
sha256=c3151b243150c7b7412bf27b08107bed0e132f0a271d5f5b34bc0fdffed8ec3e
sha512=4a70d77ed42519a547f7b13e76ccfa05192514ca84e9dc9dcb97a5d141a8cc4551a669017a48290d70f01790a83fbeba53950a2d5f975e8e51e7daf3017d6b5e
doc/src/mnet.fragments/fragment.ml.html
Source file fragment.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 110 111 112 113 114 115 116let src = Logs.Src.create "mnet.fragment" module Log = (val Logs.src_log src : Logs.LOG) type t = Unsized : Ropes.unknown Ropes.t -> t | Sized : Diet.t * bytes -> t (* A payload can be: - an entire packet (Unfragmented) - the start of a fragment whose end is unknown (Unsized) - a packet that has not yet been fully received (but which size is known) (Sized) In the case of a fragment whose size is unknown, a Rope is used so that insertion at random locations is not costly. This Rope is in a state where we do not know the final size ([Ropes.unknown]). We can therefore add fragments one after the other "ad infinitum". However, we cannot add a fragment on top of another existing one. If this is the case, the addition raises the [Overlap] exception. Then, if we know the last fragment, we know the final size of our packet. We can therefore [Ropes.fixed] our ropes. This consists of creating a final buffer in which we will copy all our fragments (a reassembly, in short). However, this does not mean that we have received the whole of our package; there may be holes. It is therefore always necessary to check that the addition of new fragments to this buffer does not overlap other already existing fragments. For this reason, we associate with this buffer a Discrete Interval Encoding Tree that contains all the intervals already "filled" in our buffer. A [Sized] value is then created. Thanks to the DIET, we can verify that the addition of all these intervals forms a continuous final interval of our packet in its entirety. All we have to do is make a [Diet.diff] between our current DIET and the one that contains this final interval. If the result is empty, it means that our current DIET contains all the intervals necessary to complete our buffer. Our packet is complete! Finally, there is the special case of an unfragmented packet. This corresponds to our "happy path" where the bigstring used physically corresponds to the one used (and filled) by Solo5. That is to say that from Solo5 up to here, this unfragmented packet **is not** a copy. *) let singleton ~off ?(limit = false) ~len slice : t = match (off, limit) with | _, false -> let str = Slice_bstr.to_string slice in let empty = Ropes.(Unknown Limitless) in let ropes = Ropes.insert ~off str empty in Log.debug (fun m -> m "+%d byte(s) %@ %d" (String.length str) off); Unsized ropes | 0, true -> invalid_arg "Unfragmented packet" | _, true -> let str = Slice_bstr.sub_string ~off:0 ~len slice in let empty = Ropes.(Unknown Limitless) in let ropes = Ropes.insert ~off str empty in let max = off + String.length str in Log.debug (fun m -> m "+%d byte(s) %@ %d (max: %d)" (String.length str) off max); let ropes = Ropes.fixed ~max ropes in let diet, buf = Ropes.to_bytes ropes in Sized (diet, buf) let weight = function | Unsized ropes -> Ropes.weight ropes | Sized (_, buf) -> Bytes.length buf exception Out_of_bounds exception Overlap exception Too_big let () = Printexc.register_printer @@ function | Out_of_bounds -> Some "Fragment out of bounds" | Overlap -> Some "Fragment overlap" | Too_big -> Some "Too big" | _ -> None let insert t ~off ?(limit = false) str = match (t, limit) with | Sized (diet, buf), false -> let len = String.length str in if off < 0 || off > Bytes.length buf - len then raise_notrace Out_of_bounds; begin try let diet = Diet.add ~off ~len diet in Bytes.unsafe_blit_string str 0 buf off len; Sized (diet, buf) with _ -> raise_notrace Overlap end | Unsized ropes, false -> Log.debug (fun m -> m "+%d byte(s) %@ %d" (String.length str) off); let ropes = Ropes.insert ~off str ropes in (* NOTE(dinosaure): actually, we can increase the ropes without limit. This is also the case with [mirage-tcpip], which has no mechanism to limit the [payload]. Not sure if you should put a limit or not. *) Unsized ropes | Sized _, true -> failwith "Multiple MF:0 fragments" | Unsized ropes, true -> let max = off + String.length str in Log.debug (fun m -> m "+%d byte(s) %@ %d (max: %d)" (String.length str) off max); let ropes = Ropes.insert ~off str ropes in let ropes = Ropes.fixed ~max ropes in let diet, buf = Ropes.to_bytes ropes in Sized (diet, buf) let is_complete : t -> bool = function | Unsized _ -> false | Sized (diet, buf) -> let buf = Diet.add ~off:0 ~len:(Bytes.length buf) Diet.empty in Diet.(is_empty (diff diet buf)) let reassemble_exn = function | Unsized _ -> invalid_arg "Fragment.reassemble_exn" | Sized (_, buf) -> Bytes.unsafe_to_string buf
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>