aboutsummaryrefslogtreecommitdiffstats
path: root/network_cmds/ecnprobe/session.c
diff options
context:
space:
mode:
Diffstat (limited to 'network_cmds/ecnprobe/session.c')
-rw-r--r--network_cmds/ecnprobe/session.c785
1 files changed, 785 insertions, 0 deletions
diff --git a/network_cmds/ecnprobe/session.c b/network_cmds/ecnprobe/session.c
new file mode 100644
index 0000000..5ca97d8
--- /dev/null
+++ b/network_cmds/ecnprobe/session.c
@@ -0,0 +1,785 @@
+/*
+ Copyright (c) 2000
+ International Computer Science Institute
+ All rights reserved.
+
+ This file may contain software code originally developed for the
+ Sting project. The Sting software carries the following copyright:
+
+ Copyright (c) 1998, 1999
+ Stefan Savage and the University of Washington.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. All advertising materials mentioning features or use of this software
+ must display the following acknowledgment:
+ This product includes software developed by ACIRI, the AT&T
+ Center for Internet Research at ICSI (the International Computer
+ Science Institute). This product may also include software developed
+ by Stefan Savage at the University of Washington.
+ 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
+ may not be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY ICSI AND CONTRIBUTORS ``AS IS'' AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL ICSI OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+*/
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "base.h"
+#include "inet.h"
+#include "session.h"
+#include "capture.h"
+#include "support.h"
+#include "ecn.h"
+#include <errno.h>
+
+struct TcpSession session;
+
+int EstablishSession(uint32 sourceAddress,
+ uint16 sourcePort,
+ uint32 targetAddress,
+ uint16 targetPort,
+ int ip_optlen, // AM: add support for IP options
+ char *ip_opt, // AM: add support for IP options
+ int mss,
+ int optlen,
+ char *opt,
+ int maxwin,
+ int maxpkts,
+ uint8 iptos,
+ uint8 tcp_flags) // AM: Add a tcp_flags parameter
+{
+
+ int rawSocket;
+
+ struct IPPacket *p = NULL;
+ struct IPPacket *synPacket;
+ char *read_packet;
+ struct pcap_pkthdr pi;
+ int synAckReceived = 0;
+ int numRetransmits = 0;
+ double timeoutTime;
+ double ts1 = 0, ts2;
+ int flag = 1;
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("In EstablishSession...\n");
+ }
+
+ arc4random_stir();
+
+ session.src = sourceAddress;
+ session.sport = sourcePort;
+ session.dst = targetAddress;
+ session.dport = targetPort;
+ session.rcv_wnd = maxwin * mss;
+ session.snd_nxt = arc4random(); /* random initial sequence number */
+ session.iss = session.snd_nxt;
+ session.rcv_nxt = 0;
+ session.irs = 0;
+ session.mss = mss ;
+ session.maxseqseen = 0 ;
+ session.epochTime = GetTime();
+ session.maxpkts = maxpkts;
+ session.num_unwanted_drops = 0;
+ session.num_reordered = 0;
+ session.num_rtos = 0;
+ session.num_dup_acks = 0;
+ session.num_pkts_0_dup_acks = 0;
+ session.num_pkts_1_dup_acks = 0;
+ session.num_pkts_2_dup_acks = 0;
+ session.num_pkts_3_dup_acks = 0;
+ session.num_pkts_4_or_more_dup_acks = 0;
+ session.num_dupack_ret = 0;
+ session.num_reord_ret = 0;
+ session.num_reordered = 0;
+ session.num_dup_transmissions = 0;
+ session.ignore_result = 0;
+ session.curr_ttl = 0;
+
+ if ((session.mtu < 1) || (session.mtu > 1460)) {
+ session.mtu = 1500;
+ }
+
+ if (session.verbose) {
+ printf("session.MTU = %d\n", session.mtu);
+ }
+
+ if ((session.dataRcvd = (uint8 *)calloc(sizeof(uint8), mss * session.maxpkts)) == NULL) {
+ perror("ERROR: no memmory to store data:\n");
+ printf("RETURN CODE: %d\n", ERR_MEM_ALLOC);
+ Quit(ERR_MEM_ALLOC);
+ }
+
+ /* Now open a raw socket for sending our "fake" TCP segments */
+ if ((rawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
+ perror("ERROR: couldn't open socket:");
+ printf("RETURN CODE: %d\n", ERR_SOCKET_OPEN);
+ Quit(ERR_SOCKET_OPEN);
+ }
+
+ if (setsockopt(rawSocket, IPPROTO_IP, IP_HDRINCL, (char *)&flag,sizeof(flag)) < 0) {
+ perror("ERROR: couldn't set raw socket options:");
+ printf("RETURN CODE: %d\n", ERR_SOCKOPT);
+ Quit(ERR_SOCKOPT);
+ }
+
+ session.socket = rawSocket;
+
+ /* Allocate SYN packet */
+ synPacket = AllocateIPPacket(ip_optlen, optlen, 0, "EstablishSession (SYN)");
+
+ /* Copy IP options at the end of IpHeader structure - New */
+ if (ip_optlen > 0) {
+ memcpy((char *)synPacket->ip + sizeof(struct IpHeader), ip_opt, ip_optlen);
+ }
+
+ /* Copy TCP options at the end of TcpHeader structure - New */
+ if (optlen > 0) {
+ memcpy((char *)synPacket->tcp + sizeof(struct TcpHeader), opt, optlen);
+ }
+
+ /* Send SYN Pkt */
+ SendSessionPacket(synPacket,
+ sizeof(struct IpHeader) + ip_optlen + sizeof(struct TcpHeader) + optlen,
+ TCPFLAGS_SYN | tcp_flags,
+ ip_optlen, /* IP opt len */
+ optlen, /* TCP opt len */
+ iptos);
+
+ timeoutTime = GetTime() + SYNTIMEOUT;
+
+ /*
+ * Wait for SYN/ACK and retransmit SYN if appropriate
+ * not great, but it gets the job done
+ */
+
+ while(!synAckReceived && numRetransmits < MAXSYNRETRANSMITS) {
+
+ while(GetTime() < timeoutTime) {
+
+ /* Have we captured any packets? */
+
+ if ((read_packet = (char *)CaptureGetPacket(&pi)) != NULL) {
+
+ p = (struct IPPacket *)FindHeaderBoundaries(read_packet);
+
+ /* Received a packet from us to them */
+ if (INSESSION(p, session.src, session.sport, session.dst, session.dport)) {
+
+ /* Is it a SYN? */
+ if (p->tcp->tcp_flags & TCPFLAGS_SYN) {
+
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("xmit\n");
+ PrintTcpPacket(p);
+ }
+
+ StorePacket(p);
+
+ ts1 = pi.ts.tv_sec + (double)pi.ts.tv_usec/1000000.0;
+ session.totSeenSent ++ ;
+
+ }
+
+ free(p);
+ continue;
+
+
+ }
+
+ if (INSESSION(p, session.dst, session.dport, session.src, session.sport)) {
+
+ /* Is it a SYN/ACK? */
+ if (p->tcp->tcp_flags & (TCPFLAGS_SYN | TCPFLAGS_ACK)) {
+
+ timeoutTime = GetTime(); /* force exit */
+ synAckReceived++;
+ ts2 = pi.ts.tv_sec + (double)pi.ts.tv_usec/1000000.0;
+ session.rtt = ts2 - ts1 ;
+
+ if (numRetransmits > 0) {
+ session.rtt_unreliable = 1;
+ printf("##### Unreliable\n"); /* ACK for which SYN? */
+ }
+
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("rcvd:\n");
+ PrintTcpPacket(p);
+ printf("Connection setup took %d ms\n",(int)((ts2 - ts1) * 1000.0));
+ }
+
+ StorePacket(p);
+
+ /* Save ttl for,admittedly poor,indications of reverse route change */
+ session.ttl = p->ip->ip_ttl;
+ session.snd_wnd = ntohl(p->tcp->tcp_win);
+ session.totRcvd++;
+
+ free(p);
+ break ;
+
+ }
+
+ }
+
+ free(p->ip);
+ free(p->tcp);
+ free(p);
+
+ }
+
+ }
+
+ if (!synAckReceived) {
+
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("SYN timeout. Retransmitting\n");
+ }
+
+ SendSessionPacket(synPacket,
+ sizeof(struct IpHeader) + ip_optlen + sizeof(struct TcpHeader) + optlen,
+ TCPFLAGS_SYN | tcp_flags,
+ ip_optlen, /* IP opt len */
+ optlen, /* TCP opt len */
+ iptos);
+
+ timeoutTime = GetTime() + SYNTIMEOUT;
+ numRetransmits++;
+ }
+ }
+
+ if (numRetransmits >= MAXSYNRETRANSMITS) {
+ printf("ERROR: Could not establish contact after %d retries\nRETURN CODE: %d\n",
+ numRetransmits, NO_CONNECTION);
+ Quit(NO_CONNECTION);
+ }
+
+ /* Update session variables */
+ session.irs = ntohl(p->tcp->tcp_seq);
+ session.dataRcvd[0] = 1 ;
+ session.rcv_nxt = session.irs + 1; /* SYN/ACK takes up a byte of seq space */
+ session.snd_nxt = session.iss + 1; /* SYN takes up a byte of seq space */
+ session.snd_una = session.iss + 1;
+ session.maxseqseen = ntohl(p->tcp->tcp_seq);
+
+ session.initSession = 1;
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("src = %s:%d (%u)\n", InetAddress(session.src), session.sport, session.iss);
+ printf("dst = %s:%d (%u)\n", InetAddress(session.dst), session.dport, session.irs);
+ }
+
+ free(synPacket->ip);
+ free(synPacket->tcp);
+ free(synPacket);
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("Out of EstablishSession...\n");
+ }
+
+ session.start_time = GetTime();
+
+ return 1;
+
+}
+
+int PrepareRequest(char *data, char *filename)
+{
+
+ char h1[] = "GET ";
+ char h2[] = " HTTP/1.1";
+ char h3[] = "Host: ";
+ char h4[] = "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11; DigExt; TBIT)";
+ char h5[] = "Accept: */*";
+
+ /* New */
+ char h7[] = "Pragma: no-cache";
+ char h8[] = "Cache-control: no-chache";
+ char deffile[] = DEFAULT_FILENAME;
+
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("In PrepareRequest...\n");
+ }
+
+ if (filename == NULL) {
+ filename = deffile;
+ }
+
+
+ if (strlen(session.targetName) > 0) {
+
+ sprintf(data,
+
+ "%s/%s %s\r\n%s\r\n%s\r\n%s\r\n%s\r\n%s%s\r\n\r\n",
+ h1,
+ filename,
+ h2,
+ h4,
+ h7,
+ h8,
+ h5,
+ h3,
+ session.targetName);
+ }else {
+
+ sprintf(data,
+ "%s%s%s\r\n%s\r\n\r\n",
+ h1,
+ filename,
+ h2,
+ h4);
+ }
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("Out PrepareRequest...\n");
+ }
+
+ return ((int)strlen(data));
+
+}
+
+
+void SendRequest(char *filename, void (*ackData)(struct IPPacket *p))
+{
+
+ struct IPPacket *p, *datapkt;
+ struct pcap_pkthdr pi;
+ char *read_packet;
+ int i;
+ int sendflag = 1;
+ double startTime = 0;
+ char *dataptr;
+ char data[MAXREQUESTLEN];
+ int datalen;
+ int ipsz;
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("In SendRequest...\n");
+ }
+
+ datalen = PrepareRequest(data, filename);
+
+ ipsz = sizeof(struct IpHeader) + sizeof(struct TcpHeader) + datalen + 1;
+
+ /* Allocate space for IP data packet */
+ datapkt = AllocateIPPacket(0, 0, datalen + 1, "SendRequest (Data)");
+
+ dataptr = (char *)datapkt->tcp + sizeof(struct TcpHeader);
+ memcpy((void *)dataptr, (void *)data, datalen);
+
+ /* Send the data packet. Try to "achieve" reliability by sending the
+ * packet upto 5 times, wating for 2 seconds between packets (BAD
+ * busy-wait loop)
+ */
+
+ i = 0 ;
+ while(1) {
+
+ if (sendflag == 1) {
+
+ SendSessionPacket(datapkt,
+ ipsz,
+ TCPFLAGS_PSH | TCPFLAGS_ACK,
+ 0, /* ip opt len */
+ 0, /* tcp opt len */
+ 0); /* tos */
+
+ startTime = GetTime();
+ sendflag = 0 ;
+ i++;
+
+ }
+
+ /* Check if we have received any packets */
+ if ((read_packet = (char *)CaptureGetPacket(&pi)) != NULL) {
+
+ p = (struct IPPacket *)FindHeaderBoundaries(read_packet);
+
+ /*
+ * packet that we sent?
+ */
+
+ if (INSESSION(p,session.src,session.sport,session.dst,session.dport) &&
+ (p->tcp->tcp_flags == (TCPFLAGS_PSH | TCPFLAGS_ACK)) &&
+ (ntohl(p->tcp->tcp_seq) == session.snd_nxt) &&
+ (ntohl(p->tcp->tcp_ack) <= session.rcv_nxt)) {
+
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("xmit %d\n", i);
+ PrintTcpPacket(p);
+ }
+
+ StorePacket(p);
+
+ free(p);
+
+ //session.snd_nxt += datalen + 1;
+ session.totSeenSent++;
+ continue;
+
+ }
+ /*
+ * packet from them?
+ */
+
+ if (INSESSION(p,session.dst,session.dport,session.src,session.sport) &&
+ (p->tcp->tcp_flags & TCPFLAGS_ACK) &&
+ (ntohl(p->tcp->tcp_seq) == session.rcv_nxt) &&
+ (ntohl(p->tcp->tcp_ack) >= session.snd_una)) {
+
+
+ session.snd_una = ntohl(p->tcp->tcp_ack);
+
+ if (p->ip->ip_ttl != session.ttl) {
+ printf("#### WARNING: route may have changed (ttl was %d, is %d).\n",
+ session.ttl, p->ip->ip_ttl);
+ session.ttl = p->ip->ip_ttl;
+ }
+
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("rcvd %d\n", i);
+ PrintTcpPacket(p);
+ }
+
+ StorePacket(p);
+ session.totRcvd ++;
+ session.snd_nxt += datalen + 1;
+
+ /* if the packet also contains data, receive it and send an ack if needed */
+ (*ackData)(p);
+
+ free(p);
+ break;
+
+ }
+
+ free(p);
+
+ }
+
+ if ((GetTime() - startTime >= REXMITDELAY) &&
+ (sendflag == 0) && (i < MAXDATARETRANSMITS)) {
+ sendflag = 1 ;
+ }
+
+ if (i >= MAXDATARETRANSMITS) {
+ printf ("ERROR: sent request 5 times without response\nRETURN CODE: %d\n",
+ SEND_REQUEST_FAILED);
+ Quit(SEND_REQUEST_FAILED);
+ }
+
+ }
+
+ free(datapkt->ip);
+ free(datapkt->tcp);
+ free(datapkt);
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("Out of SendRequest...\n");
+ }
+}
+
+void SendSessionPacket(struct IPPacket *p,
+ uint16 ip_len, uint8 tcp_flags, uint16 ip_optlen, uint16 optlen,
+ uint8 iptos)
+{
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("In SendSessionPacket...\n");
+ }
+ WriteIPPacket(p,
+ session.src, session.dst, session.sport, session.dport,
+ session.snd_nxt, session.rcv_nxt, tcp_flags,
+ session.rcv_wnd, 0,
+ (ip_len - sizeof(struct IpHeader) - ip_optlen - sizeof(struct TcpHeader) - optlen),
+ ip_optlen, optlen, iptos, 0);
+
+
+ /* Store packet here rather than in rcvData() because otherwise some
+ * ACKs may not be accounted for upon receiving reordered packets */
+
+ StorePacket(p);
+
+ SendPkt(p,
+ ip_len, /* Total IP datagram size */
+ ip_optlen, /* ip options len */
+ optlen); /* tcp options len */
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("Out of SendSessionPacket...\n");
+ }
+
+}
+
+
+void SendICMPReply(struct IPPacket *p)
+{
+
+ struct ICMPUnreachableErrorPacket *icmp_pkt;
+ int icmpsz;
+
+ struct IpHeader *ip = p->ip;
+ struct TcpHeader *tcp = p->tcp;
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("In SendICMPReply...\n");
+ }
+
+ icmpsz = sizeof(struct ICMPUnreachableErrorPacket);
+ if ((icmp_pkt = (struct ICMPUnreachableErrorPacket *)calloc(icmpsz + 1, 1)) == NULL) {
+ perror("ERROR: no space for ICMP packet:");
+ Quit(ERR_MEM_ALLOC) ;
+ }
+
+ /* Fill IP Header of ICMP packet */
+ bzero((char *)icmp_pkt, sizeof(struct ICMPUnreachableErrorPacket));
+ icmp_pkt->ip.ip_src = ip->ip_dst;
+ icmp_pkt->ip.ip_dst = ip->ip_src;
+ icmp_pkt->ip.ip_p = IPPROTOCOL_ICMP;
+ icmp_pkt->ip.ip_xsum =
+ htons((uint16)(sizeof(struct IcmpHeader) + sizeof(struct IpHeader) + sizeof(struct IpHeader) + 8)); /* pseudo hdr */
+ icmp_pkt->ip.ip_ttl = 60;
+ icmp_pkt->ip.ip_tos = 0x00;
+ icmp_pkt->ip.ip_vhl = 0x45;
+#ifdef __FreeBSD__
+ icmp_pkt->ip.ip_off = IP_DF;
+ icmp_pkt->ip.ip_len = (uint16)(sizeof(struct ICMPUnreachableErrorPacket));
+#else /* __FreeBSD__ */
+ icmp_pkt->ip.ip_off = htons(IP_DF);
+ icmp_pkt->ip.ip_len = htons((uint16)((sizeof (struct ICMPUnreachableErrorPacket) + 8 + 1)));
+#endif /* __FreeBSD__ */
+
+ /* Fill ICMP header */
+ icmp_pkt->icmp.icmp_type = 0x3;
+ icmp_pkt->icmp.icmp_code = 0x4;
+ icmp_pkt->icmp.icmp_xsum = 0;
+ icmp_pkt->icmp.icmp_unused = 0;
+ icmp_pkt->icmp.icmp_mtu = htons(session.mtu);
+
+ /* Fill in ip header of offending packet */
+ icmp_pkt->off_ip.ip_src = ip->ip_src;
+ icmp_pkt->off_ip.ip_dst = ip->ip_dst;
+ icmp_pkt->off_ip.ip_p = ip->ip_p;
+ icmp_pkt->off_ip.ip_xsum = ip->ip_xsum;
+ icmp_pkt->off_ip.ip_ttl = ip->ip_ttl;
+ icmp_pkt->off_ip.ip_tos = ip->ip_tos;
+ icmp_pkt->off_ip.ip_vhl = ip->ip_vhl;
+ icmp_pkt->off_ip.ip_p = ip->ip_p;
+#ifdef __FreeBSD__
+ icmp_pkt->off_ip.ip_off = ntohs(ip->ip_off);
+ icmp_pkt->off_ip.ip_len = ntohs(ip->ip_len);
+#else /* __FreeBSD__ */
+ icmp_pkt->off_ip.ip_off = ip->ip_off;
+ icmp_pkt->off_ip.ip_len = ip->ip_len;
+#endif /* __FreeBSD__ */
+
+ icmp_pkt->tcp_sport = tcp->tcp_sport;
+ icmp_pkt->tcp_dport = tcp->tcp_dport;
+ icmp_pkt->tcp_seqno = (uint32)tcp->tcp_seq;
+
+ icmp_pkt->icmp.icmp_xsum = InetChecksum((uint16 *)(&(icmp_pkt->icmp)), NULL,
+ (uint16)(sizeof(struct IcmpHeader) + sizeof(struct IpHeader) + 8), 0);
+
+ if (session.verbose) {
+ printf("++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
+ printf("TCP Packet: %lu\n", sizeof(struct IPPacket));
+ PrintTcpPacket(p);
+ printf("ICMP Packet: %lu\n", sizeof(struct ICMPUnreachableErrorPacket));
+ PrintICMPUnreachableErrorPacket(icmp_pkt);
+ printf("++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
+ }
+
+ SendICMPPkt(icmp_pkt, sizeof(struct ICMPUnreachableErrorPacket));
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("Out of SendICMPReply...\n");
+ }
+
+}
+
+void SendPkt(struct IPPacket *p, uint16 ip_len, int ip_optlen,
+ int tcp_optlen) {
+ int nbytes, datalen;
+ struct sockaddr_in sockAddr;
+ char *assembled_pkt;
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("In SendPkt...\n");
+ }
+ /* Assemble contiguos packet to be sent */
+ if ((assembled_pkt = (char *)calloc(1, ip_len)) == NULL) {
+ printf("SendPkt: Cannot allocate memory for assembled packet\n");
+ Quit(ERR_MEM_ALLOC);
+ }
+ /* Copy IP Header and options, if any */
+ memcpy((char *)assembled_pkt, (char *)(p->ip),
+ sizeof(struct IpHeader) + ip_optlen);
+
+ /* Copy TCP Header and options, if any */
+ memcpy((char *)(assembled_pkt + sizeof(struct IpHeader) + ip_optlen),
+ (char *)(p->tcp),
+ sizeof(struct TcpHeader) + tcp_optlen);
+
+ /* Copy data bytes, if any */
+ datalen = ip_len - ((sizeof(struct IpHeader) + ip_optlen + sizeof(struct TcpHeader) + tcp_optlen));
+
+ if (datalen > 0) {
+ memcpy((char *)assembled_pkt + sizeof(struct IpHeader) + ip_optlen + sizeof(struct TcpHeader) + tcp_optlen,
+ (char *)p->tcp + sizeof(struct TcpHeader) + tcp_optlen, datalen);
+ }
+
+
+ sockAddr.sin_family = AF_INET;
+ sockAddr.sin_addr.s_addr = session.dst;
+
+ if ((nbytes = (int)sendto(session.socket,
+ (char *)assembled_pkt,
+ ip_len,
+ 0,
+ (struct sockaddr *)&sockAddr,
+ sizeof(sockAddr))) < ip_len) {
+ printf("#### WARNING: only sent %d of %d bytes\n", nbytes, ip_len);
+ perror("here");
+
+ }
+
+ session.totSent++;
+
+ free(assembled_pkt);
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("Out SendPkt...\n");
+ }
+
+}
+
+
+
+void SendICMPPkt(struct ICMPUnreachableErrorPacket *p, uint16 len) {
+
+ ssize_t nbytes;
+ struct sockaddr_in sockAddr;
+
+ sockAddr.sin_family = AF_INET;
+ sockAddr.sin_addr.s_addr = session.dst;
+
+ nbytes = sendto(session.socket, (char *)p, len, 0,
+ (struct sockaddr *)&sockAddr,
+ sizeof(sockAddr));
+
+ if (nbytes < len) {
+ printf("#### WARNING: only sent %zd of %d (errno: %d) bytes\n",
+ nbytes, len, errno);
+ perror("here");
+ }
+
+ session.totSent++ ;
+
+}
+
+void rcvData (void (*ackData)(struct IPPacket *p))
+{
+
+ struct pcap_pkthdr pi;
+ struct IPPacket *p;
+ char *read_packet;
+ double startTime = GetTime () ;
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("In rcvData...\n");
+ }
+
+ while (1) {
+
+ if ((GetTime() - startTime) > (MAXDATARETRANSMITS * REXMITDELAY)) {
+ printf ("ERROR: no Data received for %f seconds\nRETURN CODE: %d\n",
+ (MAXDATARETRANSMITS*REXMITDELAY), NO_DATA_RCVD);
+ Quit(NO_DATA_RCVD) ;
+ }
+
+ if ((read_packet = (char *)CaptureGetPacket(&pi)) != NULL) {
+
+ p = (struct IPPacket *)FindHeaderBoundaries(read_packet);
+
+ /*
+ * Packet that we sent?
+ */
+
+ if (INSESSION(p,session.src,session.sport,session.dst,session.dport) &&
+ ((p->tcp->tcp_flags & TCPFLAGS_ACK) || (p->tcp->tcp_flags & TCPFLAGS_FIN)) &&
+ (ntohl(p->tcp->tcp_seq) == session.snd_nxt) &&
+ (ntohl(p->tcp->tcp_ack) <= session.rcv_nxt)) {
+
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("xmit:\n");
+ PrintTcpPacket(p);
+ }
+
+ session.totSeenSent++ ;
+
+ free(p);
+ continue;
+
+ }
+
+ /*
+ * Data that we were expecting?
+ */
+
+ if (INSESSION(p,session.dst,session.dport,session.src,session.sport) &&
+ (p->tcp->tcp_flags & TCPFLAGS_ACK) &&
+ (ntohl(p->tcp->tcp_ack) >= session.snd_una)) {
+
+ if (p->ip->ip_ttl != session.ttl) {
+ printf("#### WARNING: route may have changed (ttl was %d, is %d).\n",
+ session.ttl, p->ip->ip_ttl);
+ session.ttl = p->ip->ip_ttl;
+ }
+
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("rcvd: \n");
+ PrintTcpPacket(p);
+ }
+
+ session.totRcvd++ ;
+ startTime = GetTime () ;
+ StorePacket(p);
+
+ /* if the packet also contains data, receive it, and send an ack if needed */
+ ECNAckData(p);
+
+ free(p);
+ continue ;
+
+ } else {
+
+ free(p);
+
+ }
+ }
+ }
+}
+
+