123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230(*----------------------------------------------------------------------------
* Copyright (c) 2017 Inhabited Type LLC.
* Copyright (c) 2019 Antonio N. Monteiro.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the author nor the names of his contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*---------------------------------------------------------------------------*)openH2openLwt.InfixmoduleBuffer:sigtypetvalcreate:int->tvalget:t->f:(Bigstringaf.t->off:int->len:int->int)->intvalput:t->f:(Bigstringaf.t->off:int->len:int->[`Eof|`Okofint]Lwt.t)->[`Eof|`Okofint]Lwt.tend=structtypet={buffer:Bigstringaf.t;mutableoff:int;mutablelen:int}letcreatesize=letbuffer=Bigstringaf.createsizein{buffer;off=0;len=0}letcompresst=ift.len=0then(t.off<-0;t.len<-0)elseift.off>0then(Bigstringaf.blitt.buffer~src_off:t.offt.buffer~dst_off:0~len:t.len;t.off<-0)letgett~f=letn=ft.buffer~off:t.off~len:t.lenint.off<-t.off+n;t.len<-t.len-n;ift.len=0thent.off<-0;nletputt~f=compresst;(* XXX: dinosaure wants a comment here. *)assert(t.off=0);ft.buffer~off:(t.off+t.len)~len:(Bigstringaf.lengtht.buffer-t.len)(* - t.off *)>|=function|`Eof->`Eof|`Oknasret->t.len<-t.len+n;retendmoduleConfig=H2.ConfigincludeH2_lwt_intfmoduleServer(Io:IO)=structletcreate_connection_handler?(config=Config.default)~request_handler~error_handlerclient_addrsocket=letconnection=Server_connection.create~config~error_handler:(error_handlerclient_addr)(request_handlerclient_addr)inletreport_exn=Io.report_exnconnectionsocketinletread_buffer=Buffer.createconfig.Config.read_buffer_sizeinletread_loop_exited,notify_read_loop_exited=Lwt.wait()inletread_loop()=letrecread_loop_step()=matchServer_connection.next_read_operationconnectionwith|`Read->Buffer.put~f:(Io.readsocket)read_buffer>>=(function|`Eof->Buffer.getread_buffer~f:(funbigstring~off~len->Server_connection.read_eofconnectionbigstring~off~len)|>ignore;read_loop_step()|`Ok_->Buffer.getread_buffer~f:(funbigstring~off~len->Server_connection.readconnectionbigstring~off~len)|>ignore;read_loop_step())|`Close->Lwt.wakeup_laternotify_read_loop_exited();Io.shutdown_receivesocket;Lwt.return_unitinLwt.async(fun()->Lwt.catchread_loop_stepreport_exn)inletwritev=Io.writevsocketinletwrite_loop_exited,notify_write_loop_exited=Lwt.wait()inletrecwrite_loop()=letrecwrite_loop_step()=matchServer_connection.next_write_operationconnectionwith|`Writeio_vectors->writevio_vectors>>=funresult->Server_connection.report_write_resultconnectionresult;write_loop_step()|`Yield->Server_connection.yield_writerconnectionwrite_loop;Lwt.return_unit|`Close_->Lwt.wakeup_laternotify_write_loop_exited();Io.shutdown_sendsocket;Lwt.return_unitinLwt.async(fun()->Lwt.catchwrite_loop_stepreport_exn)inread_loop();write_loop();Lwt.join[read_loop_exited;write_loop_exited]>>=fun()->Io.closesocketendmoduleClient(Io:IO)=structmoduleClient_connection=H2.Client_connectiontypet=Client_connection.tletcreate_connection?(config=Config.default)?push_handler~error_handlersocket=letconnection=Client_connection.create~config?push_handler~error_handlerinletread_buffer=Buffer.createconfig.Config.read_buffer_sizeinletread_loop_exited,notify_read_loop_exited=Lwt.wait()inletread_loop()=letrecread_loop_step()=matchClient_connection.next_read_operationconnectionwith|`Read->Buffer.put~f:(Io.readsocket)read_buffer>>=(function|`Eof->Buffer.getread_buffer~f:(funbigstring~off~len->Client_connection.read_eofconnectionbigstring~off~len)|>ignore;read_loop_step()|`Ok_->Buffer.getread_buffer~f:(funbigstring~off~len->Client_connection.readconnectionbigstring~off~len)|>ignore;read_loop_step())|`Close->Lwt.wakeup_laternotify_read_loop_exited();Io.shutdown_receivesocket;Lwt.return_unitinLwt.async(fun()->Lwt.catchread_loop_step(funexn->Client_connection.report_exnconnectionexn;Lwt.return_unit))inletwritev=Io.writevsocketinletwrite_loop_exited,notify_write_loop_exited=Lwt.wait()inletrecwrite_loop()=letrecwrite_loop_step()=matchClient_connection.next_write_operationconnectionwith|`Writeio_vectors->writevio_vectors>>=funresult->Client_connection.report_write_resultconnectionresult;write_loop_step()|`Yield->Client_connection.yield_writerconnectionwrite_loop;Lwt.return_unit|`Close_->Lwt.wakeup_laternotify_write_loop_exited();Lwt.return_unitinLwt.async(fun()->Lwt.catchwrite_loop_step(funexn->Client_connection.report_exnconnectionexn;Lwt.return_unit))inread_loop();write_loop();Lwt.async(fun()->Lwt.join[read_loop_exited;write_loop_exited]>>=fun()->Io.closesocket);Lwt.returnconnectionletrequest=Client_connection.requestletping=Client_connection.pingletshutdown=Client_connection.shutdownletis_closed=Client_connection.is_closedend