1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283(*
* 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"tcp.wire"~doc:"Mirage TCP Wire module"moduleLog=(valLogs.src_logsrc:Logs.LOG)moduleMake(Ip:Tcpip.Ip.S)=structtypeerror=Tcpip.Ip.errorletpp_error=Tcpip.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);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