đŸ Archived View for heyplzlookat.me âș articles âș mehari-serveur.gmi captured on 2024-08-18 at 17:25:29. Gemini links have been rewritten to link to archived content
âŹ ïž Previous capture (2024-03-21)
-=-=-=-=-=-=-
â ïž TW : Article trĂšs moche avec de nombreuses profanitĂ©s, malgrĂ© tout publiĂ©
Le principal problĂšme est la stack TCP/IP puisquâon ne peut pas utiliser la librairie Unix (prĂ©sente dans la librairie standard) sinon ce nâest pas compatible Mirage.
On peut donc aller la chercher dans le type de module `Tcpip.Stack.V4V6` (celui que Tim a choisi dans `server_impl`)
on y trouve :
val listen_tcp : ?keepalive:Tcp.Keepalive.t -> t -> port:int -> ( TCP.flow -> unit Lwt.t ) -> unit
Mais elle est dépréciée je ne sais pas pourquoi.
Donc on cherche mieux et on tombe sur ça :
val listen : t -> port:int -> ?keepalive:Tcp.Keepalive.t -> ( flow -> unit Lwt.t ) -> unit
Ok super elle nâest pas dĂ©prĂ©ciĂ©e mais maintenant il faut une valeur de type `t` !!
OĂč trouver ça ???
Il nây a aucune fonction pour crĂ©er un `t`âŠ
âŠSauf que si, dĂ©trompez-vous.
Il y a `tcpip.stack-direct` et `tcpip.stack-socket` qui sont deux implĂ©mentations du truc de ce que jâai compris (lisez le readme sinon, je sais pas).
Tim a séparé en deux Mehari :
Jâai choisi la premiĂšre implĂ©mentation de `tcpip` qui venait de base (`socket`) mais elle sâest finalement avĂ©rĂ©e ĂȘtre un bon choix puisquâon lâutilise uniquement dans `mehari.unix` et que `direct` est un bordel que je nâai pas envie dâaborder.
Si on regarde dans le module `V4V6` on y trouve :
val connect : Udpv4v6_socket.t -> Tcpv4v6_socket.t -> t Lwt.t
(Tcpip) Tcpip_stack_socket.V4V6
Ce nâest pas ce quâil nous faut (pas besoin dâ`Udpv4v6_socket.t`) et il nous faut trouver comment crĂ©er un `Tcpv4v6_socket.t` de toute façon.
On regarde Ă©galement du cĂŽtĂ© de `TCP` (mĂȘme type de module) et ici se trouve notre bonheur :
val listen : t -> port:int -> ?keepalive:Tcp.Keepalive.t -> ( flow -> unit Lwt.t ) -> unit
(Tcpip) Tcpip_stack_socket.V4V6.TCP
Mais elle nâest pas incluse dans le type de module, jâai donc Ă©tĂ© renvoyĂ© Ă la triste rĂ©alitĂ© quâon ne peut pas lâutiliser en dehors de `mehari.unix`.
Comment faire donc ?
AprĂšs un soir Ă se lamenter devant Tim que je nâarrive Ă rien il a donc posĂ© la question Ă Dinosaure (illustre membre de la communautĂ© Mirage OS) sur le Discord OCaml (on a essayĂ© de faire notre meilleur anglais possible pour lâimpressioner) :
Le condor du plateau â 17/11/2022 18:56
hi, I use mirage Tcpip to listen on a socket so I am using Tcpip.Stack.V4V6.TCP.listen
https://mirage.github.io/mirage-tcpip/tcpip/Tcpip/Stack/module-type-V4V6/index.html#val-listen
For this usage, I have to pass a value of type Tcpip.Stack.V4V6.TCP.t and a callback of type TLS.FLOW.flow -> unit Lwt.t but I donât understand how can I get a value of type Tcpip.Stack.V4V6.t.
I must specify that I work on a library and not on a unikernel
from what I understand I can obtain a stack value at the construction of the unikernel like here
but I still donât know how to get it in another context than unikernel
dinosaure â 18/11/2022 11:50
you can have an example here: https://github.com/roburio/http-mirage-client/blob/d2de9c59824a621959a4dbaceca24bedb26ca374/test/test.ml#L116 đ
Super !
Mais on a toujours le mĂȘme problĂšme, on peut pas lâutiliser dans `mehari`.
Condor va donc gentiment lui répondre :
Le condor du plateau â 18/11/2022 12:36
thank you for your reply, however the connect function seems to be hidden by the signature that I apply here to the Stack module:
module Make (Stack : Tcpip.Stack.V4V6) = struct
âŠ
end
include Lib.Make (Tcpip_stack_socket.V4V6)
if it was not clear, I use the this module type because I try to make a mirage library compatible while having a default implementation đ
(Notez lâutilisation de lâemote de faquin) (pas Dinosaure je parle de Tim)
On en reparle donc en message privĂ© avant que Dinosaure ne rĂ©ponde et lĂ on se rend compte de notre bĂȘtise : si tous les unikernels Mirage passaient leur stack via `main $ stack` et pas directement dans la fonction câest quâil y avait une raisonâŠ
Le condor du plateau â 18/11/2022 12:46
so I just have to make an entry point and then adapt it in the default implementation of the library
I was doing it wrong, thank you đ„č
(Lire : « éjacule-moi dessus »)
dinosaure â 18/11/2022 12:56
the reason behind is: the connect function (for any device) depends on the implementation (and should not be exposed by the interface)
then, the mirage tool knows how to âconnectâ a device and compose implementations, values which come from the connect and your unikernel đ
I just would like to notice that Hannes wrote an article about Albatross, our tool to deploy unikernels easily:
https://hannes.nqsb.io/Posts/Albatross
Merci Dinosaure pour cette explication.
Donc on va suivre son exemple et override les fonctions `run` et `run_lwt` dans `mehari.unix`.
Je mets par dĂ©faut `Ipaddr.V4.Prefix.loopback` pour lâadresse IPv4 et lĂ encore des problĂšmes surviennent :
Fatal error: exception Unix.Unix_error(Unix.EADDRNOTAVAIL, "bind", "")
Ătrange Ă©tant donnĂ© quâon utilise lâadresse loopback.
Je me retrouve plongĂ© dans la mĂȘme situation : plusieurs soirs de tristesse et dâimpuissance.
Mais cette fois jâeu la prĂ©sence dâesprit de vĂ©rifier si câĂ©tait la bonne adresse :
127.0.0.0/8
« Tiens tiens tiens »
Il manque un 1Â !
Jâessaie donc de remplacer par `127.0.0.1/8` (avec `Ipaddr.V4.Prefix.of_string_exn` parce que flemme de propager le `result`).
Là oui ça marche youpi !
Sauf quâil y a _encore_ un problĂšme, notre fonction `serve` qui est la main loop du seveur nâest pas exĂ©cutĂ©e.
Donc pareil je demande à Tim de poser la question sur le Discord :
Le condor du plateau â 22/11/2022 22:46
Hi, I keep hacking with Tcpip and I have a new problem.
The callback doesnât seem to run in the following snippet:
let callback _ = Lwt_io.printl "Executed"
Stack.TCP.listen stack serve;
âŠ
Iâm using this function :
https://mirage.github.io/mirage-tcpip/tcpip/Tcpip/Stack/module-type-V4V6/TCP/index.html#val-listen
Vous remarquerez que lâon sâest trompĂ© de nom de fonction et il manque un `in` donc on aura droit Ă un message dâĂ©tonnement de la part de « anmonteiro » (autre illustre membre de la communautĂ© (rĂ©alisation dâun serveur HTTP en OCaml !)).
Ătant de vĂ©ritables singes, on ne corrigera lâerreur que trop tard aprĂšs humiliation.
« mseri » (illustre membre de la communauté OCaml également) nous aura proposé une piste un peu plus tÎt :
mseri â 22/11/2022 23:44
Have you tried to flush before listening?
Le condor du plateau â 22/11/2022 23:48
how can I do that?
Pas de réponse à ce jour.
Câest lĂ que Dinosaure vint Ă notre rescousse et proposa deux pistes :
dinosaure â 23/11/2022 15:35
itâs probably related to this issue (which is fixed):
https://github.com/mirage/mirage-tcpip/issues/438
I would like to say that you should to listen âŠÂ ; Lwt.return_unit instead of listen ⊠|> Lwt.return first
if it does not solve your issue, I will probably try to go deeper and reproduce your case đ
Pour la premiĂšre option, avec un peu dâespoir notre version de `tcpip` nâĂ©tait peut-ĂȘtre tout simplement que trop peu rĂ©cente, mais aprĂšs vĂ©rification cette issue date dâil y a presque 2 ans.
Pour la deuxiÚme option :
Le condor du plateau â 23/11/2022 15:44
I just tried this fix but it doesnât solve the issue đ
dinosaure â 23/11/2022 15:56
hmmhmm
ok, I will try to reproduce
Quoi !? Dinosaure va cloner (ou _a_ cloné !) notre code (que dis-je, notre torchon) sur sa machine personnelle et le compiler.
Malgré les difficultés, on y a vu une petite victoire.
AprĂšs une semaine dâattente impatiente, Dinosaure est sorti de sa longue rĂ©flexion pour rĂ©pondre Ă Tim :
dinosaure â 2022/11/29 13:54
I finally found why your `listen` does not work. With `mirage-tcpip`, you must allocate a `Stack.t` (not only a `Stack.TCP.t`) and call the `Stack.listen` then. `Stack.TCP.listen` just adds internally a notification to `listen` but it does not really `listen()`
I made a little example for you here:
Bien Ă©videmment, son petit exemple est parfait.
On remplace tout comme il faut, et lĂ encore un problĂšme : le client envoie un « hello » mais le serveur, au lieu dâenvoyer le sien, envoie un paquet FIN et la connexion se termine lĂ -dessus.
Câest relativement problĂ©matique, mais comme Ă notre habitude :
Le condor du plateau â 2022/11/30 22:42
Hi, I want to upgrade the TCP flow to a TLS flow with `TLS.server_of_flow`
https://docs.mirage.io/tls-mirage/Tls_mirage/Make/index.html#val-server_of_flow
but when running the server, while the client successfully send a client hello the server shutdowns the connection with FIN
dinosaure â 2022/12/01 16:13
Can you show where you use `server_of_flow`?
Le condor du plateau â 2022/12/01 16:15
https://github.com/Psi-Prod/Mehari/blob/wip-merge/mehari/server_impl.ml#L43
just here
Pas de rĂ©ponse jusquâĂ aujourdâhui.
Alors que cela fait environ une semaine dâattente, Tim dĂ©cide dâouvrir une issue chez mirage/mirage-tcp-ip (qui nâest pas le bon repo mdr) avec un titre Ă peine anglais :
https://github.com/mirage/mirage-tcpip/issues/500
hannesm rĂ©pond alors que `server_of_flow` est sensĂ© fonctionner (comme sur tout les autres repo) mais ne comprends pas `match%lwt` (ou nâa pas compris pourquoi on lâa mis lĂ , au choix). Tim sâempresse de lui rĂ©pondre pour au final ne rien recevoir encore 2 semaines aprĂšs. DurâŠ
Le 6 dĂ©cembre, la release candidate dâOCaml 5 sort !
Avec elle on peut utiliser la librairie Eio que Tim va utiliser pour écrire une nouvelle implémentation, puisque `mehari.mirage` est toujours en panne.
Mehari change donc de forme et devient :
Avant dâarriver Ă la vraie solution, en cherchant un peu une des causes « habituelles » (mĂȘme sâil faut chercher pour se taper un tel truc) est que le serveur ne trouve pas dâalgorithme quâil supporte dans la liste fournie par le « client hello » et FIN directement. Seulement ça nâarrive uniquement (jâimagine) quand on utilise un client SSL ou TLSv1 donc bon.
Le 21 décembre, vers 4h et demi du matin, je comprends enfin comment activer le mode de débug avec `ocaml-tls` !
Grande nouvelle puisquâĂ la premiĂšre connection :
2022-12-21 04:29:36 +01:00: WRN [tcpv4v6-socket] error The default generator is not yet initialized.
To initialize the RNG with a default generator, and set up entropy collection and periodic reseeding as a background task, do the following:
If you are using MirageOS, use the random device in config.ml: `let main = Mirage.foreign "Unikernel.Main" (random @-> job)`, and `let () = register "my_unikernel" [main $ default_random]`.
If you are using Lwt, execute `Mirage_crypto_rng_lwt.initialize ()` at startup.
If you are using Async, execute `Mirage_crypto_eng_async.initialize (module Mirage_crypto_rng.Fortuna)` at startup.
If you are using Eio, execute in one of the fibers `Mirage_crypto_rng_eio.run (module Fortuna) env` (`env` from `Eio_main.run`).
Otherwise, there is no periodic reseeding. For an initial seed from getrandom(), execute `Mirage_crypto_rng_unix.initialize ()`. You can use `Mirage_crypto_rng.accumulate` and `Mirage_crypto_rng.reseed` to reseed the RNG manually.
On a juste Ă ajouter
Mirage_crypto_rng_lwt.initialize ()
chez `mehari_unix` et le tour est joué, tout fonctionne correctement (ou presque).
Solution qui marche mais trĂšs dĂ©cevante, sachant lâattente que ça a gĂ©nĂ©rĂ©.
FIN de OCaml
Pas encore de commentaires