123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245[%%import"config.h"]open!Coreopen!IobufmoduleFile_descr=Unix.File_descrmoduleSyscall_result=Unix.Syscall_resulttypeok_or_eof=|Ok|Eof[@@derivingcompare,sexp_of]letinputtch=matchBigstring_unix.inputch(Expert.buft)~pos:(Expert.lot)~len:(lengtht)with|n->unsafe_advancetn;Ok|exceptionBigstring_unix.IOError(n,End_of_file)->unsafe_advancetn;Eof;;letreadtfd=matchBigstring_unix.readfd(Expert.buft)~pos:(Expert.lot)~len:(lengtht)with|n->unsafe_advancetn;Ok|exceptionBigstring_unix.IOError(n,End_of_file)->unsafe_advancetn;Eof;;letread_assume_fd_is_nonblockingtfd=letnread=Bigstring_unix.read_assume_fd_is_nonblockingfd(Expert.buft)~pos:(Expert.lot)~len:(lengtht)inifSyscall_result.Int.is_oknreadthenunsafe_advancet(Syscall_result.Int.ok_exnnread);Syscall_result.ignore_ok_valuenread;;letpread_assume_fd_is_nonblockingtfd~offset=letnread=Bigstring_unix.pread_assume_fd_is_nonblockingfd~offset(Expert.buft)~pos:(Expert.lot)~len:(lengtht)inunsafe_advancetnread;;letrecvfrom_assume_fd_is_nonblockingtfd=letnread,sockaddr=Bigstring_unix.recvfrom_assume_fd_is_nonblockingfd(Expert.buft)~pos:(Expert.lot)~len:(lengtht)inunsafe_advancetnread;sockaddr;;[%%ifdefJSC_RECVMMSG](* Allocate and pre-populate the [struct mmsghdr]s and associated [struct iovec]s. Reusing
this context reduces the cost of calls to [recvmmsg] considerably if the iobuf array is
large. *)moduleRecvmmsg_context=structtypectxexternalunsafe_ctx:([>write],seek)tarray->ctx="iobuf_recvmmsg_ctx"letctxts=ifArray.for_allts~f:(funt->lengtht=capacityt)thenunsafe_ctxtselseraise_s[%sexp"Recvmmsg_context.create: all buffers must be reset",(ts:(_,_)t_with_shallow_sexparray)];;(* we retain a reference to the underlying bigstrings, in the event that callers
mistakenly use set_bounds_and_buffer. Since we've cached the underlying memory
referenced by the bigstring, we want to prevent it from being garbage collected and
released. *)typenonrect={iobufs:(read_write,seek)tarray;bstrs:Bigstring.tarray;ctx:ctx}letcreateiobufs={iobufs;bstrs=Array.mapiobufs~f:Expert.buf;ctx=ctxiobufs};;endexternalunsafe_recvmmsg_assume_fd_is_nonblocking:File_descr.t->(read_write,seek)tarray->Recvmmsg_context.ctx->Unix.Syscall_result.Int.t="iobuf_recvmmsg_assume_fd_is_nonblocking_stub"[@@noalloc]letrecvmmsg_assume_fd_is_nonblockingfd{Recvmmsg_context.iobufs;ctx;_}=unsafe_recvmmsg_assume_fd_is_nonblockingfdiobufsctx;;letrecvmmsg_assume_fd_is_nonblocking=(* We link with [--wrap recvmmsg]. If we have compiled on a machine with recvmmsg
(e.g., CentOS 6) but then run on a machine without (e.g., CentOS 5), our wrapped
[recvmmsg] always returns -1 and sets errno to ENOSYS. *)matchUnix.Syscall_result.Int.to_result(letfd=File_descr.of_int(-1)inrecvmmsg_assume_fd_is_nonblockingfd(Recvmmsg_context.create[||]))with|ErrorENOSYS->Or_error.unimplemented"Iobuf.recvmmsg_assume_fd_is_nonblocking"|_->Okrecvmmsg_assume_fd_is_nonblocking;;[%%else](* not JSC_RECVMMSG *)moduleRecvmmsg_context=structtypet=unitletcreate=ignoreendletrecvmmsg_assume_fd_is_nonblocking=Or_error.unimplemented"Iobuf.recvmmsg_assume_fd_is_nonblocking";;[%%endif](* JSC_RECVMMSG *)letunsafe_senttresult=ifSyscall_result.Int.is_okresultthen(unsafe_advancet(Syscall_result.Int.ok_exnresult);Syscall_result.unit)elseSyscall_result.Int.reinterpret_error_exnresult;;(* Don't use [Or_error.map]. The natural usage results in a partially applied function,
which is slower to call. *)letsend_nonblocking_no_sigpipe()=matchBigstring_unix.send_nonblocking_no_sigpipewith|Error_ase->e|Oksend->Ok(funtfd->unsafe_sentt(sendfd(Expert.buft)~pos:(Expert.lot)~len:(lengtht)));;letsendto_nonblocking_no_sigpipe()=matchBigstring_unix.sendto_nonblocking_no_sigpipewith|Error_ase->e|Oksendto->Ok(funtfdaddr->unsafe_sentt(sendtofd(Expert.buft)~pos:(Expert.lot)~len:(lengtht)addr));;letoutputtch=letnwritten=Bigstring_unix.outputch(Expert.buft)~pos:(Expert.lot)~len:(lengtht)inunsafe_advancetnwritten;;letwritetfd=letnwritten=Bigstring_unix.writefd(Expert.buft)~pos:(Expert.lot)~len:(lengtht)inunsafe_advancetnwritten;;letwrite_assume_fd_is_nonblockingtfd=(* This is safe because of the invariant of [t] that the window is within the buffer
(unless the user has violated the invariant with an unsafe operation). *)letnwritten=Bigstring_unix.unsafe_write_assume_fd_is_nonblockingfd(Expert.buft)~pos:(Expert.lot)~len:(lengtht)inunsafe_advancetnwritten;;letpwrite_assume_fd_is_nonblockingtfd~offset=letnwritten=Bigstring_unix.pwrite_assume_fd_is_nonblockingfd~offset(Expert.buft)~pos:(Expert.lot)~len:(lengtht)inunsafe_advancetnwritten;;moduleExpert=structexternalunsafe_pokef_float:(read_write,_)t->c_format:string->max_length:int->(float[@unboxed])->int="iobuf_unsafe_pokef_double_bytecode""iobuf_unsafe_pokef_double"[@@noalloc]letfillf_floatt~c_formatvalue=letlimit=lengthtinletresult=unsafe_pokef_floatt~c_format~max_length:(lengtht)valueinifresult>=limitthen`Truncatedelseifresult<0then`Format_errorelse(unsafe_advancetresult;`Ok);;letto_iovec_shared?pos?lent=letpos,len=Ordered_collection_common.get_pos_len_exn()?pos?len~total_length:(lengtht)inUnix.IOVec.of_bigstring(Expert.buft)~pos:(Expert.lot+pos)~len;;end