123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288moduletypeS=sigtypestacktypeipaddrmoduleTCP:sigincludeMirage_flow.Svaldst:flow->ipaddr*intendmoduleTLS:moduletypeofTls_mirage.Make(TCP)valtcp_protocol:(stack*ipaddr*int,TCP.flow)Mimic.protocolvaltcp_edn:(stack*ipaddr*int)Mimic.valuevaltls_edn:([`host]Domain_name.toption*Tls.Config.client*stack*ipaddr*int)Mimic.valuevaltls_protocol:([`host]Domain_name.toption*Tls.Config.client*stack*ipaddr*int,TLS.flow)Mimic.protocoltypettypedst=ipaddr*intvalinit:port:int->stack->tLwt.tvalaccept:t->(TCP.flow,[>`Closed])resultLwt.tvalclose:t->unitLwt.tvalhttp_service:?config:Httpaf.Config.t->error_handler:(dst->Httpaf.Server_connection.error_handler)->(TCP.flow->dst->Httpaf.Server_connection.request_handler)->tPaf.servicevalhttps_service:tls:Tls.Config.server->?config:Httpaf.Config.t->error_handler:(dst->Httpaf.Server_connection.error_handler)->(TLS.flow->dst->Httpaf.Server_connection.request_handler)->tPaf.servicevalalpn_service:tls:Tls.Config.server->?config:Httpaf.Config.t*H2.Config.t->error_handler:(dst->?request:Alpn.request->Alpn.server_error->(Alpn.headers->Alpn.body)->unit)->(dst->Alpn.reqd->unit)->tPaf.servicevalserve:?stop:Lwt_switch.t->'tPaf.service->'t->[`InitializedofunitLwt.t]endmoduleMake(Time:Mirage_time.S)(Stack:Tcpip.Tcp.S):Swithtypestack=Stack.tandtypeTCP.flow=Stack.flowandtypeipaddr=Stack.ipaddr=structopenLwt.Infixtypeipaddr=Stack.ipaddrtypedst=ipaddr*intmoduleTCP=structletsrc=Logs.Src.create"paf-tcp"moduleLog=(valLogs.src_logsrc:Logs.LOG)includeStacktypeendpoint=Stack.t*Stack.ipaddr*inttypenonrecwrite_error=[`Writeofwrite_error|`Connectoferror|`Closed]letpp_write_errorppf=function|`Writeerr|(`Closedaserr)->pp_write_errorppferr|`Connecterr->pp_errorppferrletwriteflowcs=writeflowcs>>=function|Ok_asv->Lwt.returnv|Errorerr->Lwt.return_error(`Writeerr)letwritevflowcss=writevflowcss>>=function|Ok_asv->Lwt.returnv|Errorerr->Lwt.return_error(`Writeerr)letconnect(stack,ipaddr,port)=create_connectionstack(ipaddr,port)>>=function|Ok_asv->Lwt.returnv|Errorerr->Lwt.return_error(`Connecterr)endmoduleTLS=structletsrc=Logs.Src.create"paf-tls"moduleLog=(valLogs.src_logsrc:Logs.LOG)includeTls_mirage.Make(TCP)typeendpoint=[`host]Domain_name.toption*Tls.Config.client*Stack.t*Stack.ipaddr*intletconnect(host,cfg,stack,ipaddr,port)=Stack.create_connectionstack(ipaddr,port)>>=function|Errorerr->Lwt.return_error(`Readerr)|Okflow->client_of_flowcfg?hostflowendletsrc=Logs.Src.create"paf-layer"moduleLog=(valLogs.src_logsrc:Logs.LOG)typestack=Stack.tlettcp_edn,tcp_protocol=Mimic.register~name:"tcp"(moduleTCP)lettls_edn,tls_protocol=Mimic.register~priority:10~name:"tls"(moduleTLS)typet={stack:Stack.t;queue:Stack.flowQueue.t;condition:unitLwt_condition.t;mutex:Lwt_mutex.t;mutableclosed:bool;}letinit~portstack=letqueue=Queue.create()inletcondition=Lwt_condition.create()inletmutex=Lwt_mutex.create()inletlistenerflow=Lwt_mutex.lockmutex>>=fun()->Queue.pushflowqueue;Lwt_condition.signalcondition();Lwt_mutex.unlockmutex;Lwt.return()inStack.listen~portstacklistener;Lwt.return{stack;queue;condition;mutex;closed=false}letrecaccept({queue;condition;mutex;_}ast)=Lwt_mutex.lockmutex>>=fun()->letrecawait()=ifQueue.is_emptyqueue&¬t.closedthenLwt_condition.waitcondition~mutex>>=awaitelseLwt.return_unitinawait()>>=fun()->matchQueue.popqueuewith|flow->Lwt_mutex.unlockmutex;Lwt.return_okflow|exceptionQueue.Empty->ift.closedthen(Lwt_mutex.unlockmutex;Lwt.return_error`Closed)else(Lwt_mutex.unlockmutex;acceptt)letclose({condition;_}ast)=t.closed<-true;(* Stack.disconnect stack >>= fun () -> *)Lwt_condition.signalcondition();Lwt.return_unitlethttp_service?config~error_handlerrequest_handler=letmoduleR=(valMimic.reprtcp_protocol)inletconnectionflow=letdst=Stack.dstflowinleterror_handler=error_handlerdstinletrequest_handler=request_handlerflowdstinletconn=Httpaf.Server_connection.create?config~error_handlerrequest_handlerinLwt.return_ok(R.Tflow,Paf.Runtime((moduleHttpaf.Server_connection),conn))inPaf.serviceconnectionLwt.return_okacceptcloselethttps_service~tls?config~error_handlerrequest_handler=letmoduleR=(valMimic.reprtls_protocol)inlethandshakeflow=letdst=Stack.dstflowinTLS.server_of_flowtlsflow>>=function|Okflow->Lwt.return_ok(dst,flow)|Error`Closed->(* XXX(dinosaure): be care! [`Closed] at this stage does not mean
* that the bound socket is closed but the socket with the peer is
* closed. *)Lwt.return_error(`Write`Closed)|Errorerr->Stack.closeflow>>=fun()->Lwt.return_errorerrinletconnection(dst,flow)=leterror_handler=error_handlerdstinletrequest_handler=request_handlerflowdstinletconn=Httpaf.Server_connection.create?config~error_handlerrequest_handlerinLwt.return_ok(R.Tflow,Paf.Runtime((moduleHttpaf.Server_connection),conn))inPaf.serviceconnectionhandshakeacceptcloseletalpn=letmoduleR=(valMimic.reprtls_protocol)inletalpn_of_tls_connection(_edn,flow)=matchTLS.epochflowwith|Ok{Tls.Core.alpn_protocol;_}->alpn_protocol|Error_->Noneinletpeer_of_tls_connection(edn,_flow)=ednin(* XXX(dinosaure): [TLS]/[ocaml-tls] should let us to project the underlying
* [flow] and apply [TCP.dst] on it. *)letinjection(_edn,flow)=R.Tflowin{Alpn.alpn=alpn_of_tls_connection;Alpn.peer=peer_of_tls_connection;Alpn.injection;}letalpn_service~tls?config:(_=(Httpaf.Config.default,H2.Config.default))~error_handlerrequest_handler=lethandshakeflow=letdst=Stack.dstflowinTLS.server_of_flowtlsflow>>=function|Okflow->Lwt.return_ok(dst,flow)|Error`Closed->(* XXX(dinosaure): be care! [`Closed] at this stage does not mean
* that the bound socket is closed but the socket with the peer is
* closed. *)Lwt.return_error(`Write`Closed)|Errorerr->Stack.closeflow>>=fun()->Lwt.return_error(err:>[TLS.write_error|`Msgofstring])inAlpn.servicealpn~error_handler~request_handlerhandshakeacceptcloseletserve?stopservicet=Paf.serve~sleep:Time.sleep_ns?stopservicetendtypetransmission=[`Clear|`TLSofstringoption]letpaf_transmission:transmissionMimic.value=Mimic.make~name:"paf-transmission"openLwt.Infixletreckind_of_flow:Mimic.ednlist->transmissionoption=function|Mimic.Edn(k,v)::r->(matchMimic.equalkpaf_transmissionwith|SomeMimic.Refl->Somev|None->kind_of_flowr)|[]->Nonelet(>>?)=Lwt_result.bindletrun~sleep~ctx~error_handler~response_handlerrequest=Mimic.unfoldctx>>?funress->Mimic.connectress>>=funres->match(res,kind_of_flowress)with|(Error_aserr),_->Lwt.returnerr|Okflow,(Some`Clear|None)->letalpn=matchrequestwith`V1_->"http/1.1"|`V2_->"h2c"inAlpn.run~sleep~alpn~error_handler~response_handlerflowrequestflow|Okflow,Some(`TLSalpn)->Alpn.run~sleep?alpn~error_handler~response_handlerflowrequestflowmoduleTCPV4V6(Stack:Tcpip.Stack.V4V6):sigincludeTcpip.Tcp.Swithtypet=Stack.TCP.tandtypeipaddr=Ipaddr.tandtypeflow=Stack.TCP.flowvalconnect:Stack.t->tLwt.tend=structincludeStack.TCPletconnectstackv4v6=Lwt.return(Stack.tcpstackv4v6)end