123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101(*
* Copyright (c) 2010-2014 Anil Madhavapeddy <anil@recoil.org>
*
* 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.
*)openLwt.Infixletsrc=Logs.Src.create"udp"~doc:"Mirage UDP"moduleLog=(valLogs.src_logsrc:Logs.LOG)moduleMake(Ip:Tcpip.Ip.S)=structtypeipaddr=Ip.ipaddrtypecallback=src:ipaddr->dst:ipaddr->src_port:int->Cstruct.t->unitLwt.ttypeerror=[`IpofIp.error]letpp_errorppf(`Ipe)=Ip.pp_errorppfetypet={ip:Ip.t;listeners:(int,callback)Hashtbl.t;}letpp_ip=Ip.pp_ipaddrletlistent~portcallback=ifport<0||port>65535thenraise(Invalid_argument(Printf.sprintf"invalid port number (%d)"port))elseHashtbl.replacet.listenersportcallbackletunlistent~port=Hashtbl.removet.listenersport(* TODO: ought we to check to make sure the destination is relevant
here? Currently we process all incoming packets without making
sure they're either unicast for us or otherwise interesting. *)letinputt~src~dstbuf=matchUdp_packet.Unmarshal.of_cstructbufwith|Errors->Log.debug(funf->f"Discarding received UDP message: error parsing: %s"s);Lwt.return_unit|Ok({Udp_packet.src_port;dst_port},payload)->matchHashtbl.find_optt.listenersdst_portwith|None->Lwt.return_unit|Somefn->fn~src~dst~src_portpayloadletwritev?src?src_port?ttl~dst~dst_porttbufs=letsrc_port=matchsrc_portwith|None->Randomconv.int~bound:65535(funx->Mirage_crypto_rng.generatex)|Somep->pinletfill_hdrbuf=letpayload_size=Cstruct.lenvbufsinletph=Ip.pseudoheadert.ip?srcdst`UDP(payload_size+Udp_wire.sizeof_udp)inletudp_header=Udp_packet.({src_port;dst_port;})inmatchUdp_packet.Marshal.into_cstructudp_headerbuf~pseudoheader:ph~payload:(Cstruct.concatbufs)with|Ok()->8|Errormsg->Logs.err(funm->m"error while assembling udp header: %s, ignoring"msg);8inIp.writet.ip?srcdst?ttl`UDP~size:8fill_hdrbufs>|=function|Ok()->Ok()|Errore->Log.err(funf->f"IP module couldn't send UDP packet to %a: %a"pp_ipdstIp.pp_errore);(* we're supposed to make our best effort, and we did *)Ok()letwrite?src?src_port?ttl~dst~dst_porttbuf=writev?src?src_port?ttl~dst~dst_portt[buf]letconnectip=Log.info(funf->f"UDP layer connected on %a"Fmt.(list~sep:(any", ")Ip.pp_prefix)(Ip.configured_ipsip));lett={ip;listeners=Hashtbl.create7}inLwt.returntletdisconnectt=Log.info(funf->f"UDP layer disconnected on %a"Fmt.(list~sep:(any", ")Ip.pp_prefix)(Ip.configured_ipst.ip));Lwt.return_unitend