123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687(*
* Copyright (c) 2012 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"Wire"~doc:"Mirage TCP Wire module"moduleLog=(valLogs.src_logsrc:Logs.LOG)letcount_tcp_to_ip=MProf.Counter.make~name:"tcp-to-ip"moduleMake(Ip:Mirage_protocols.IP)=structtypeerror=Mirage_protocols.Ip.errorletpp_error=Mirage_protocols.Ip.pp_errortypet={dst_port:int;(* Remote TCP port *)dst:Ip.ipaddr;(* Remote IP address *)src_port:int;(* Local TCP port *)src:Ip.ipaddr;(* Local IP address *)}letv~src~src_port~dst~dst_port={dst_port;dst;src_port;src}letsrct=t.srcletdstt=t.dstletsrc_portt=t.src_portletdst_portt=t.dst_portletppppft=Fmt.pfppf"remote %a,%d to local %a, %d"Ip.pp_ipaddrt.dstt.dst_portIp.pp_ipaddrt.srct.src_portletxmit~ip{src_port;dst_port;src;dst}?(rst=false)?(syn=false)?(fin=false)?(psh=false)~rx_ack~seq~window~optionspayload=let(ack,ack_number)=matchrx_ackwith|None->(false,Sequence.zero)|Somen->(true,n)inletheader={sequence=seq;Tcp_packet.ack_number;window;urg=false;ack;psh;rst;syn;fin;options;src_port;dst_port;}in(* Make a TCP/IP header frame *)lettcp_size=Tcp_wire.sizeof_tcp+Options.lenvoptions+Cstruct.lengthpayloadinletfill_bufferbuf=letpseudoheader=Ip.pseudoheaderip~srcdst`TCPtcp_sizeinmatchTcp_packet.Marshal.into_cstructheaderbuf~pseudoheader~payloadwith|Errors->Log.err(funl->l"Error writing TCP packet header: %s"s);0(* TODO: better to avoid this entirely, now we're sending empty IP
frame and drop the payload.. oops *)|Okl->Cstruct.blitpayload0bufl(Cstruct.lengthpayload);MProf.Counter.increasecount_tcp_to_ip(Cstruct.lengthpayload+ifsynthen1else0);tcp_sizeinIp.writeip~fragment:false~srcdst`TCP~size:tcp_sizefill_buffer[]>|=function|Ok()->Ok()(* swallow errors so normal recovery mechanisms can be used *)(* For errors which aren't transient, or are too long-lived for TCP to recover
* from, this will eventually result in a higher-level notification
* that communication over the TCP flow has failed *)|Errore->Log.warn(funl->l"Error sending TCP packet via IP: %a"Ip.pp_errore);Ok()end