123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126(*
* Copyright (C) 2015 David Scott <dave.scott@unikernel.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*)openProtocol_9popenLwtopenAstringmoduleMake(Log:S.LOG)(Filesystem:Filesystem.S)=structmoduleS=Protocol_9p.Server.Make(Log)(Flow_lwt_unix)(Filesystem)typeip=stringtypeport=intletfinallyfg=Lwt.catch(fun()->f()>>=funresult->g()>>=fun_ignored->Lwt.returnresult)(fune->g()>>=fun_ignored->Lwt.faile)typet={shutdown_requested_t:unitLwt.t;shutdown_requested_u:unitLwt.u;shutdown_done_t:unitLwt.t;shutdown_done_u:unitLwt.u;mutablefd:Lwt_unix.file_descroption;fs:Filesystem.t;}letof_fdfsfd=letshutdown_requested_t,shutdown_requested_u=Lwt.task()inletshutdown_done_t,shutdown_done_u=Lwt.task()inletfd=Somefdin{shutdown_requested_t;shutdown_requested_u;shutdown_done_t;shutdown_done_u;fd;fs}letlistenfsprotoaddress=matchprotowith|"tcp"->beginmatchString.cuts~sep:":"addresswith|[ip;port]->letfd=Lwt_unix.socketLwt_unix.PF_INETLwt_unix.SOCK_STREAM0inLwt_unix.setsockoptfdLwt_unix.SO_REUSEADDRtrue;letsockaddr=Lwt_unix.ADDR_INET(Unix.inet_addr_of_stringip,int_of_stringport)inLwt_unix.bindfdsockaddr>>=fun()->Lwt_unix.listenfd5;Lwt.return(Result.Ok(of_fdfsfd))|_->Lwt.return(Error.error_msg"Unable to understand protocol %s and address %s"protoaddress)end|"unix"->Lwt.catch(fun()->Lwt_unix.unlinkaddress)(fun_->Lwt.return())>>=fun()->letfd=Lwt_unix.socketLwt_unix.PF_UNIXLwt_unix.SOCK_STREAM0inletsockaddr=Lwt_unix.ADDR_UNIX(address)inLwt_unix.bindfdsockaddr>>=fun()->Lwt_unix.listenfd5;Lwt.return(Result.Ok(of_fdfsfd))|_->Lwt.return(Error.error_msg"Unknown protocol %s"proto)letshutdownt=Lwt.wakeup_latert.shutdown_requested_u();t.shutdown_done_tletaccept_forevertf=matcht.fdwith|None->Lwt.return(Error.error_msg"9P server already shutdown")|Somefd->letrecloop_forever()=Lwt_unix.acceptfd>>=fun(client,_client_addr)->Log.debug(funf->f"accepted connection");Lwt.async(fun()->Lwt.catch(fun()->finally(fun()->fclient)(fun()->Lwt_unix.closeclient))(fune->Log.err(funf->f"server loop caught %s: no further requests will be processed"(Printexc.to_stringe));Lwt.return()));loop_forever()infinally(fun()->Lwt.pick[loop_forever();t.shutdown_requested_t])(fun()->t.fd<-None;Lwt_unix.closefd)>>=fun()->Lwt.wakeup_latert.shutdown_done_u();return(Result.Ok())letserve_forevert=accept_forevert(funfd->letflow=Flow_lwt_unix.connectfdinS.connectt.fsflow()>>=function|Result.Error(`Msgx)->fail(Failurex)|Result.Okt->Log.debug(funf->f"Successfully negotiated a connection.");S.after_disconnectt)end