技術共有

Raw ソケット (1) TCP スリーウェイ ハンドシェイクの実装

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

ラボ環境:
Windows 物理マシン: 192.168.1.4
WSL Ubuntu 20.04.6 LTS:172.19.32.196
Windows の http サーバー: HFS は、おそらく次のようになります。
ここに画像の説明を挿入します
クライアントは Ubuntu、サーバーは http サーバー (以下、サーバーまたはサーバーと呼びます) で、サーバー IP はパラメータを通じてプログラムに渡されます。

ソースコードは最後にあります。

メイン関数プログラムは次の部分に分かれています。
1.パラメータを取得する 、ネットリンク通信で通信するネットワークカードを選択し(実際にはUbuntuにはネットワークカードが1枚しかありません、ipは172.19.32.196です)、サーバーとクライアントのipとポートを初期化します。ネットリンク通信で通信するためのネットワークカードの選択については、以下のリンクを参照してください。
Netlink 通信 - ルーティング テーブルを読み取り、通信ネットワーク カードの IP を取得します。
コードの一部:

	...
	// netlink通信
	uint32_t src_address = getLocalIPAddress(inet_addr(dst));
	...
	src_addr.sin_family = AF_INET;
	src_addr.sin_port = htons((uint16_t) getpid());  // 将当前进程ID作为源端口
	src_addr.sin_addr = *(struct in_addr *) &src_address;

	dst_addr.sin_family = AF_INET;
	dst_addr.sin_port = htons(HTTP_PORT);
	dst_addr.sin_addr.s_addr = inet_addr(dst);
	...
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

2. 2 つのソケットを作成します、ソケットの送信とソケットの受信、クライアントのバインド(この例の 4 つのタプルは変更されていないため、この手順はオプションです)、ソケット プロトコル属性を設定します。
コードの一部:

	...
	send_sock_fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
	recv_sock_fd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
	bind(recv_sock_fd, (const struct sockaddr *) &src_addr,
			sizeof(struct sockaddr_in)) < 0);
	int one = 1;
	setsockopt(recv_sock_fd, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one));
	...
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

       送信ソケットと受信ソケットを作成します。
AF_INET は TCP/IP – IPv4 プロトコル スイートを表します。
SOCK_RAW は、ソケット タイプが raw ソケットであることを示します。
3 番目のパラメータは、プロトコル パラメータです。これは、開発者が自分で IP データ パケットを構築して解析できることを意味します。これをソケット送信用のプロトコル タイプとして使用するには、発信データ パケットを自分でカプセル化し、チェックサムを計算する必要があります。 、受信したデータ パケットが TCP データ パケットであることを示します。
       クライアントのIPとポートをバインドする: この手順は必要ありません。前述したように、双方の IP アドレスとポートは変更されません。
       ソケットプロトコルのプロパティを設定する:setsockopt は、受信側ソケットのプロパティを設定します。共通のオプションは次のとおりです。
       (1) ソケットレベルのオプション(ソルソケット)
SO_REUSEADDR: ローカル アドレスの再利用を許可します。
SO_RCVBUF: 受信バッファサイズを設定します。
SO_SNDBUF: 送信バッファサイズを設定します。
SO_BROADCAST: ブロードキャスト メッセージの送信を許可します。
SO_KEEPALIVE: キープアライブ メカニズムを有効にし、接続が有効かどうかを確認します。
       (2) IP層オプション(IPPROTO_IP)
IP_TTL: IP データグラムの存続期間 (TTL) を設定します。
IP_HDRINCL: IP ヘッダーを提供するようにアプリケーションに指示します。
       (3) TCP層オプション(IPPROTO_TCP)
TCP_NODELAY: Nagle アルゴリズムを無効にして遅延を軽減します。
TCP_MAXSEG: TCP の最大セグメント サイズを設定します。
この例では、ソケット オプションは IPPROTO_IP の IP 層オプション IP_HDRINCL に設定されており、受信したパケットに IP ヘッダーが含まれていることを示しています。

       

3回の握手を開始します

connect_tcp(send_sock_fd, recv_sock_fd, &dst_addr, &src_addr);
  • 1
//Blocking call
int connect_tcp(int send_fd, int recv_fd, struct sockaddr_in* dst_addr,
		struct sockaddr_in* src_addr)
{
	int ret = 0;

// Initialize the TCP Session State with the given details
	bzero(&tcp_state, sizeof(tcp_state__t));
	tcp_state.max_segment_size = MAX_CLIENT_SEGMENT_SIZE;    // 初始化MSS
	tcp_state.client_window_size = CLIENT_WINDOW_SIZE;       // 初始化拥塞窗口
	tcp_state.client_next_seq_num = STARTING_SEQUENCE;       // 客户端下个包的seq
	tcp_state.session_info.dst_addr = *dst_addr;             // 目的地址
	tcp_state.session_info.src_addr = *src_addr;             // 源地址
	tcp_state.session_info.recv_fd = recv_fd;                // 接收句柄
	tcp_state.session_info.send_fd = send_fd;                // 发送句柄
	tcp_state.syn_retries = 5;                               // 重传次数
	tcp_state.cwindow_size = 1;    // 拥塞窗口值
	initialize_mutex(&tcp_state.tcp_state_lock);
	initialize_mutex(&tcp_state.session_info.send_fd_lock);

	tcp_flags_t flags = {0};
	flags.ack = 1;
	flags.syn = 1;
	if (((ret = send_syn()) < 0) || ((ret = receive_syn_ack_segment(&flags)) < 0)
	                             || ((ret = send_ack_segment(0)) < 0))
	{
		printf("Failed to set up TCP Connection!!");
		ret = -1;
		goto EXIT;
	}
	tcp_state.tcp_current_state = ESTABLISHED;

	EXIT: return ret;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

ハンドシェイクのプロセスは大まかに次のとおりです。
ここに画像の説明を挿入します
以下の 3 つのステップに分かれていることがわかります。
       1. SYN パケットを送信します。対応する関数は次のとおりです。 send_syn();
create_packet() は TCP パケットを作成します。この関数は非常に重要であり、オフセット ポインターを設定することで、IP ヘッダー、TCP ヘッダー、およびデータを見つけることができます。 TCP の SYN フラグを 1 に設定する必要があります。その後、ヘッダーが構築されます (build_packet_headers)。具体的なタスクは、TCP ヘッダーのカプセル化、TCP チェックサムの計算、IP ヘッダーのカプセル化、およびチェックサムの計算です。 TCP 状態遷移図では、クライアントが SYN パケットを送信した後、その状態が CLOSED から SYN_SENT に変化するため、sendto を使用するだけでなく、TCP 状態を次のように設定する必要があります。データを送信するには、再送信タイマーを作成するには、SYN パケットの送信後、タイムアウト内に応答が受信されなかった場合、SYN パケットを再送信する必要があります。したがって、タイムアウト後に、送信されたパケットを送信循環キューのバッファに書き込む必要があります。この記事では、循環キューについては説明しません。
       2. SYN/ACK パケットを受信します。対応する関数は、receive_syn_ack_segment(&flags); です。
データを受信するには、recvfrom 関数を使用します。データを受信した後、IP チェックサムの確認、送信元ポートと宛先ポートおよび IP が正しいかどうかの確認、TCP チェックサムの確認、およびパケットは再送パケットです。次に、データ パケット内の IP ヘッダー、TCP ヘッダー、データのオフセット方向も設定する必要があります。これにより、受信パケットの SYN フラグと ACK フラグが 1 であるかどうか、および RST パケットであるかどうかを判断できます。これらのタスクを完了した後も、サーバーからの次のパケットのシーケンスの設定、クライアントからの次のパケットのシーケンスの設定、サーバーの受信ウィンドウの値の更新、輻輳ウィンドウ値を確認し、受信ウィンドウから開始します。この応答パケットを循環キューから削除し(処理済みのため)、このパケットを受信するために作成されたスペースを解放し、MSS を更新します。
       3. ACK パケットを送信します。対応する関数は send_ack_segment(0) です。
3 番目のステップは非常に簡単で、3 ウェイ ハンドシェイクが成功したことを示す応答を送信します。パラメータ 0 は、FIN フラグが 0、つまりパケットが ACK パケットであることを意味します。 TCP ステータスを ESTABLISHED に設定します。

プログラムを実行し、Wireshark を使用してパケットをキャプチャすると、結果はどうなるでしょうか。
ここに画像の説明を挿入します

ここに画像の説明を挿入します
       SYN パケットを送信して SYN/ACK を受信した後、クライアントが何らかの方法で別の RST パケットを送信し、その後 ACK パケットを送信したことがわかります。プログラムは正常に実行されたように見えますが、実際には 3 ウェイ ハンドシェイクが確立されています。接続に失敗しました。 。
       その理由は何でしょうか?

       このプログラムは、通信にシステム コールではなく生のソケットを使用します。クライアントが SYN/ACK を送信すると、オペレーティング システムはまずパケットを受信し、対応するソケット (システム コールを使用して作成された) がローカルに存在するかどうかを確認します。誰もいない場合、RST パケットが送信され、スリーウェイ ハンドシェイクは接続を確立できません。 。

       では、どうすれば解決できるでしょうか?

このプログラムは主に実験学習を目的としているため、iptables を使用してマシンから送信された RST パケットを破棄することで解決できます。この時点では、サーバーはクライアントから送信された RST パケットを受信せず、接続は正常に確立されます。 !
実装されたシェルスクリプト:

#!/bin/sh

if ! iptables -C OUTPUT -p tcp --tcp-flags RST RST -j DROP; then
    iptables -A OUTPUT -p tcp --tcp-flags RST RST -j DROP
fi

./handshake "$@" 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

まず、iptables -C OUTPUT -p tcp --tcp-flags RST RST -j DROP コマンドが実行されているかどうかを確認します。実行されていない場合は、再度実行します。

結果の表示:
ここに画像の説明を挿入します
成功!

       最後に、このプログラムは 3 ウェイ ハンドシェイクのみを実装し、4 ウェイ ウェーブは実装しません。
       ソースコード
実行.sh

#!/bin/sh

if ! iptables -C OUTPUT -p tcp --tcp-flags RST RST -j DROP; then
    iptables -A OUTPUT -p tcp --tcp-flags RST RST -j DROP
fi

./handshake "$@"

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

メイクファイル

CFLAGS= -g -Werror -lrt -lpthread
CC=gcc

all:
	$(CC) handshake.c routing_table.c tcp_handler.c $(CFLAGS) -o handshake

clean:
	rm -rf handshake 

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

ハンドシェイク.c

#include "routing_table.h"
#include "tcp_handler.h"
#include <ctype.h>
#include <fcntl.h>
#include <unistd.h>

#define WRITE_BUFFER_SIZE 2048
#define RECV_BUFFER_LENGTH 32768
#define REQ_LENGTH 256
#define STRIP_LEADING_NEWLINE_CHAR(ptr) 
	while(*ptr == 'n') 
		ptr++;
#define STRIP_LEADING_WHITESPACES(ptr) 
	while(*ptr == ' ') 
		ptr++;
#define STRIP_TRAILING_CARRIAGE_RETURN(ptr) (ptr[strlen(ptr)-1] = '0')

int main(int argc, char** argv)
{

	int send_sock_fd = -1, recv_sock_fd = -1;
	struct sockaddr_in src_addr, dst_addr;
	char dst[REQ_LENGTH] = {0};

	if (argc != 2)
	{
		printf("Usage: ./rawhttpget ipn");
		exit(1);
	}

	strncpy(dst, argv[1], REQ_LENGTH);

	memset(&src_addr, 0, sizeof(struct sockaddr_in));
	memset(&dst_addr, 0, sizeof(struct sockaddr_in));

    // netlink通信
	uint32_t src_address = getLocalIPAddress(inet_addr(dst));

	src_addr.sin_family = AF_INET;
	src_addr.sin_port = htons((uint16_t) getpid());  // 将当前进程ID作为源端口
	src_addr.sin_addr = *(struct in_addr *) &src_address;

	dst_addr.sin_family = AF_INET;
	dst_addr.sin_port = htons(HTTP_PORT);
	dst_addr.sin_addr.s_addr = inet_addr(dst);

	send_sock_fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); // IPPROTO_RAW:表示开发人员可以自己构造和解析 IP 数据包
	if (send_sock_fd < 0)
	{
		printf("Error: Creation of Raw Socket failed: %s!!n", strerror(errno));
		exit(1);
	}

	recv_sock_fd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);  // IPPROTO_TCP表示接收TCP包

	if (recv_sock_fd < 0)
	{
		printf("Error: Creation of Raw Socket failed: %s!!n", strerror(errno));
		exit(1);
	}

	if (bind(recv_sock_fd, (const struct sockaddr *) &src_addr,
			sizeof(struct sockaddr_in)) < 0)
	{
		printf("Error: Unable to bind the receiving socket: %sn",
				strerror(errno));
		exit(1);
	}

	//IP_HDRINCL to tell the kernel that headers are included in the packet
	int one = 1;
	if (setsockopt(recv_sock_fd, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one)) < 0) // IP_HDRINCL:数据中包含IP头
	{
		perror("Error setting IP_HDRINCL");
		exit(1);
	}

	char psrc_addr[256] = {0}, pdst_addr[256] = {0};
	printf("Src Address: %s Destination Address: %sn",
			inet_ntop(AF_INET, &src_addr.sin_addr.s_addr, psrc_addr, 256),
			inet_ntop(AF_INET, &dst_addr.sin_addr.s_addr, pdst_addr, 256));

	if (connect_tcp(send_sock_fd, recv_sock_fd, &dst_addr, &src_addr) < 0)
	{
		printf("TCP Connection Failedn");
		goto EXIT;
	}
	else
		printf("TCP Connection Successfuln");

	EXIT: close(send_sock_fd);
	close(recv_sock_fd);

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95

ルーティングテーブル.c

#include <stdio.h>
#include <stdlib.h>
#include <bits/sockaddr.h>
#include <asm/types.h>
#include <linux/rtnetlink.h>
#include <sys/socket.h>
#include <errno.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netdb.h>
#include <unistd.h>
#include <string.h>

#define BUFFER_LENGTH 8192
typedef struct rt_request
{
	struct nlmsghdr nl;
	struct rtmsg rt;
	char payload[BUFFER_LENGTH];
} rt_request;

uint32_t fetch_interface_ip(uint32_t if_index)
{
	int family;
	struct ifreq ifreq;
	char host[256] =
	{ 0 }, if_name[256] =
	{ 0 };
	uint32_t src_addr;
	int fd;

	if_indextoname(if_index, if_name);  // 根据索引值获取网络接口名,如eth0
	fd = socket(AF_INET, SOCK_DGRAM, 0);
	if (fd < 0)
	{
		perror("socket()");
		exit(EXIT_FAILURE);
	}

	memset(&ifreq, 0, sizeof ifreq);
	strncpy(ifreq.ifr_name, if_name, IFNAMSIZ);
	if (ioctl(fd, SIOCGIFADDR, &ifreq) != 0)    // 获取接口ip
	{
		/* perror(name); */
		return -1; /* ignore */
	}

	switch (family = ifreq.ifr_addr.sa_family)
	{
	case AF_UNSPEC:
		// return;
		return -1; /* ignore */
	case AF_INET:
	case AF_INET6:
		getnameinfo(&ifreq.ifr_addr, sizeof ifreq.ifr_addr, host, sizeof host,
				0, 0, NI_NUMERICHOST);
		break;
	default:
		sprintf(host, "unknown  (family: %d)", family);
	}
	inet_pton(AF_INET, host, &src_addr);
	close(fd);
	return src_addr;
}

void formRequest(rt_request* req)
{
	bzero(req, sizeof(req));
/*
struct nlmsghdr 为 netlink socket 自己的消息头,
这用于多路复用和多路分解 netlink 定义的所有协议类型以及其它一些控制,
netlink 的内核实现将利用这个消息头来多路复用和多路分解已经其它的一些控制,
因此它也被称为netlink 控制块。因此,应用在发送 netlink 消息时必须提供该消息头。
*/
	req->nl.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
	req->nl.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;  // NLM_F_REQUEST表示消息是一个请求
	req->nl.nlmsg_type = RTM_GETROUTE;  // nlmsg_type消息内容

    // 填充rtmsg结构体,即路由表管理结构体,对于上面的RTM_GETROUTE操作来说,只需要定义下面两个内容
	req->rt.rtm_family = AF_INET;
	req->rt.rtm_table = RT_TABLE_MAIN;

}

void sendRequest(int sock_fd, struct sockaddr_nl *pa, rt_request* req)
{
	struct msghdr msg;    // sendmsg和recvmsg的参数,描述发送消息和接收消息的结构体
	struct iovec iov;     // iovec结构体用于描述一个数据缓冲区
	int rtn;

	bzero(pa, sizeof(pa));
	pa->nl_family = AF_NETLINK;

	bzero(&msg, sizeof(msg));
	msg.msg_name = pa;
	msg.msg_namelen = sizeof(*pa);

	iov.iov_base = (void *) req;
	iov.iov_len = req->nl.nlmsg_len;

	msg.msg_iov = &iov;
	msg.msg_iovlen = 1;

	while (1)
	{
		if ((rtn = sendmsg(sock_fd, &msg, 0)) < 0)
		{
			if (errno == EINTR)
				continue;
			else
			{
				printf("Error: Unable to send NetLink message:%sn",
						strerror(errno));
				exit(1);
			}
		}
		break;
	}

}

int receiveReply(int sock_fd, char* response_buffer)
{
	char* p;
	int nll, rtl, rtn;
	struct nlmsghdr *nlp;
	struct rtmsg *rtp;

	bzero(response_buffer, BUFFER_LENGTH);
	p = response_buffer;
	nll = 0;

	while (1)
	{
		if ((rtn = recv(sock_fd, p, BUFFER_LENGTH - nll, 0)) < 0)
		{
			if (errno == EINTR)
				continue;
			else
			{
				printf("Failed to read from NetLink Socket: %sn",
						strerror(errno));
				exit(1);
			}

		}

		nlp = (struct nlmsghdr*) p;
		if (nlp->nlmsg_type == NLMSG_DONE)
			break;

		p += rtn;
		nll += rtn;
	}
	return nll;
}

uint32_t readReply(char *response, int nll, in_addr_t dst_address)
{
	struct nlmsghdr *nlp = NULL;
	struct rtmsg *rtp = NULL;
	struct rtattr *rtap = NULL;
	int rtl = 0, found_route = 0, default_route = 0;
	uint32_t route_addr, net_mask;
	uint32_t if_index = -1;

	nlp = (struct nlmsghdr*) response;
	for (; NLMSG_OK(nlp, nll); nlp = NLMSG_NEXT(nlp, nll))  // NLMSG_OK:检查nlh地址是否是一条完整的消息
	{                                                       // NLMSG_NEXT:当前消息地址,返回下一个消息地址
		rtp = (struct rtmsg *) NLMSG_DATA(nlp);        // NLMSG_DATA:从nlh首地址向后移动到data起始位置

		if (rtp->rtm_table != RT_TABLE_MAIN)
			continue;

		// RTM_RTA:输入route message指针,返回route第一个属性首地址
		rtap = (struct rtattr *) RTM_RTA(rtp);    // rtattr结构体封装可选路由信息的通用结构,用于表示 Netlink 消息的属性
		rtl = RTM_PAYLOAD(nlp);    // RTM_PAYLOAD:即rtmsg层封装的数据长度,相当于TCP数据包去掉IP报头和TCP报头长度得到TCP数据部分长度
		found_route = 0;
		default_route = 1;

		for (; RTA_OK(rtap, rtl); rtap = RTA_NEXT(rtap, rtl))  // RTA_OK:判断一个属性rta是否正确
		{                                                      // RTA_NEXT:先对attrlen减去rta属性内容的全部长度,然后返回下一个rtattr的首地址
			switch (rtap->rta_type)
			{
			// destination IPv4 address
			case RTA_DST:
				default_route = 0;
				route_addr = *((uint32_t*) RTA_DATA (rtap));
				net_mask = 0xFFFFFFFF;
				net_mask <<= (32 - rtp->rtm_dst_len);
				net_mask = ntohl(net_mask);
				if (route_addr == (dst_address & net_mask))
					found_route = 1;
				else if (route_addr == 0)
					default_route = 1;
				break;

				// unique ID associated with the network
				// interface
			case RTA_OIF:  // Output interface index
				if (found_route || default_route)
					if_index = *((uint32_t*) RTA_DATA (rtap));
				break;

			default:
				break;
			}
		}

		if (found_route)
			break;
	}

	return if_index;

}
// Netlink分层模型及消息格式:https://onestraw.github.io/linux/netlink-message/
uint32_t getLocalIPAddress(in_addr_t dst_address)
{
	int route_sock_fd = -1, res_len = 0;
	struct sockaddr_nl sa, pa;    // sa为消息接收者的 netlink 地址
	uint32_t if_index;

	rt_request req = {0};
	char response_payload[BUFFER_LENGTH] = {0};

	// Open Routing Socket
	if ((route_sock_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1)
	{
		printf("Error: Failed to open routing socket: %sn", strerror(errno));
		exit(1);
	}

	bzero(&sa, sizeof(sa));
	// nl_groups == 0 表示该消息为单播
	sa.nl_family = AF_NETLINK;
	sa.nl_pid = getpid();  // nl_pid表示接收消息者的进程ID

	bind(route_sock_fd, (struct sockaddr*) &sa, sizeof(sa));

	formRequest(&req);    // 构造netlink消息
	sendRequest(route_sock_fd, &pa, &req);    // 发送消息
	res_len = receiveReply(route_sock_fd, response_payload);    // 接收消息
	if_index = readReply(response_payload, res_len, dst_address);  // 从接收的消息中获取if(network interface)

	close(route_sock_fd);
	return fetch_interface_ip(if_index);    // 从if_index获取接口ip
}


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251

ルーティングテーブル.h

#include <sys/types.h>
#include <netinet/in.h>

#ifndef ROUTING_TABLE_H
#define ROUTING_TABLE_H

uint32_t getLocalIPAddress(in_addr_t dst_address);

#endif

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

tcp_handler.c

#include "tcp_handler.h"

#define STARTING_SEQUENCE 1
#define TCP_WORD_LENGTH_WITH_NO_OPTIONS 5
#define HAS_TCP_OPTIONS(ptr) (ptr->doff > TCP_WORD_LENGTH_WITH_NO_OPTIONS)
#define TCP_OPTION_OFFSET(ptr) ((char*)ptr + (TCP_WORD_LENGTH_WITH_NO_OPTIONS * WORD_LENGTH))
#define TCP_OPTION_LENGTH(ptr) ((ptr->doff - TCP_WORD_LENGTH_WITH_NO_OPTIONS) * WORD_LENGTH)
#define END_OF_TCP_OPTION_CHECK(ptr) ((*ptr) == 0)
#define TCP_OPTIONS_LEN(ptr) ((ptr->doff - TCP_WORD_LENGTH_WITH_NO_OPTIONS) * WORD_LENGTH )
#define IS_NO_OPERATION(ptr) ((*ptr) == 1)
#define IS_MSS(ptr) ((*ptr) == 2)
#define OPTION_LENGTH(ptr) (*(ptr+1))
#define min(a,b) 
   ({ __typeof__ (a) _a = (a); 
       __typeof__ (b) _b = (b); 
     _a < _b ? _a : _b; })
#define TCP_OPTION_DATA_OFFSET 2

#define IS_DUPLICATE_TCP_SEGMENT(tcph) (ntohl(tcph->seq) < tcp_state.server_next_seq_num)
#define IS_DUPLICATE_ACK(tcph) (tcph->ack && (tcph->ack_seq == tcp_state.last_acked_seq_num) )
#define WRAP_ROUND_BUFFER_SIZE(index) 
		({ __typeof__ (index) _index = (index); 
		 ( _index + 1) > MAX_BUFFER_SIZE ? 0 : (_index + 1); })

tcp_state__t tcp_state;

/*
 Generic checksum calculation function
 */
static unsigned short csum(uint16_t *ptr, unsigned int nbytes)
{
	uint32_t sum;
	uint16_t answer;

	sum = 0;
	while (nbytes > 1)
	{
		sum += *ptr++;
		nbytes -= 2;    // 以16位的字为单位计算和
	}
	if (nbytes == 1)   // 如果总长度为奇数个字节,则在最后增添一个位都为0的字节
	{
		sum += *(unsigned char*) ptr;
	}
	// 将32bit数据压缩成16bit数据,即将高16bit与低16bit相加,将进位加到低16位上,最后取反
	sum = (sum >> 16) + (sum & 0xffff);
	sum = sum + (sum >> 16);
	answer = (short) ~sum;

	return (answer);
}

static void calculate_tcp_checksum(struct tcphdr* tcph,
		uint16_t tcp_payload_len, uint32_t src_addr, uint32_t dst_addr)
{
	pseudo_header psh;
	char* pseudogram;
	uint16_t tcphdr_len = (tcph->doff * WORD_LENGTH);  // tcph->doff:以32位字为单位表示TCP头长

	// pseudoheader
	bzero(&psh, sizeof(pseudo_header));
	psh.source_address = src_addr;
	psh.dest_address = dst_addr;
	psh.protocol = IPPROTO_TCP;
	psh.tcp_length = htons(tcphdr_len + tcp_payload_len);

	int psize = sizeof(pseudo_header) + tcphdr_len + tcp_payload_len;
	pseudogram = malloc(psize);

	// TCP伪首部、TCP头、TCP数据
	bzero(pseudogram, psize);
	memcpy(pseudogram, &psh, sizeof(pseudo_header));
	memcpy(pseudogram + sizeof(pseudo_header), tcph,
			tcphdr_len + tcp_payload_len);

	// 计算校验和
	tcph->check = csum((uint16_t*) pseudogram, (unsigned int) psize);
	free(pseudogram);
}

static int validate_ip_checksum(struct iphdr* iph)
{
	int ret = -1;
	uint16_t received_checksum = iph->check;
	iph->check = 0;

	if (received_checksum
			== csum((uint16_t*) iph, (unsigned int) (iph->ihl * WORD_LENGTH)))
		ret = 1;

	return ret;
}

static int validate_tcp_checksum(struct tcphdr* tcph,
		uint16_t tcp_payload_length)
{
	int ret = -1;
	uint16_t received_checksum = tcph->check;
	tcph->check = 0;
	calculate_tcp_checksum(tcph, tcp_payload_length,
			*(uint32_t *) &tcp_state.session_info.dst_addr.sin_addr.s_addr,
			*(uint32_t *) &tcp_state.session_info.src_addr.sin_addr.s_addr);
	if (received_checksum == tcph->check)
		ret = 1;

	if (ret < 0) {
		printf("received_checksum:%d, tcph->check:%dn", received_checksum, tcph->check);
	char psrc_addr[256] = {0}, pdst_addr[256] = {0};
	printf("Src Address: %s Destination Address: %sn",
			inet_ntop(AF_INET, &tcp_state.session_info.src_addr.sin_addr.s_addr, psrc_addr, 256),
			inet_ntop(AF_INET, &tcp_state.session_info.dst_addr.sin_addr.s_addr, pdst_addr, 256));
	}
	return ret;
}

static packet_t* create_packet()
{
	packet_t* packet = malloc(sizeof(packet_t));

	// send tcp syn
	bzero(packet, sizeof(packet_t));
	packet->offset[IP_OFFSET] = packet->payload;
	packet->offset[TCP_OFFSET] = packet->payload + sizeof(struct iphdr);
	packet->offset[DATA_OFFSET] = packet->payload + sizeof(struct tcphdr)
			+ sizeof(struct iphdr);
	packet->retransmit_timer_id = NULL;
	return packet;
}

static void adjust_layer_offset(packet_t* packet)
{
	struct tcphdr *tcph;
	struct iphdr *iph;

	iph = (struct iphdr *) packet->payload;
	tcph = (struct tcphdr *) (packet->payload + (iph->ihl * WORD_LENGTH));
	packet->offset[TCP_OFFSET] = (char*) tcph;
	packet->offset[DATA_OFFSET] = (char*) (packet->offset[TCP_OFFSET]
			+ (tcph->doff * WORD_LENGTH));
}

static void destroy_packet(packet_t* packet)
{
	if (packet->retransmit_timer_id != NULL)
		timer_delete(packet->retransmit_timer_id);

	free(packet);
}

static void remove_acked_entries(uint32_t next_expected_seq)
{
	pthread_mutex_lock(&tcp_state.sender_info.tcp_retx_lock);
	while ((tcp_state.sender_info.retx_buffer[tcp_state.sender_info.retx_buffer_head].packet_seq
			< next_expected_seq)
			&& !(tcp_state.sender_info.retx_buffer_head
					== tcp_state.sender_info.retx_buffer_tail))
	{
		destroy_packet(
				tcp_state.sender_info.retx_buffer[tcp_state.sender_info.retx_buffer_head].packet);
		tcp_state.sender_info.retx_buffer[tcp_state.sender_info.retx_buffer_head].packet = NULL;
		tcp_state.sender_info.retx_buffer_head =
		WRAP_ROUND_BUFFER_SIZE(tcp_state.sender_info.retx_buffer_head);
	}
	pthread_mutex_unlock(&tcp_state.sender_info.tcp_retx_lock);
}

static void reset_packet_retransmission_timer(timer_t* timer_id,
		uint16_t timeInSecs)
{
	struct itimerspec timer_value = {0};
	timer_value.it_interval.tv_sec = timeInSecs;
	timer_value.it_value.tv_sec = timeInSecs;

	if (timer_settime(*timer_id, 0, &timer_value, NULL) < 0)
	{
		printf("Failed to set time!!");
		timer_delete(*timer_id);
		*timer_id = NULL;
	}
}

static void build_ip_header(struct iphdr* iph, uint16_t ip_payload_len)
{
	iph->daddr = *(uint32_t*) &tcp_state.session_info.dst_addr.sin_addr.s_addr;
	iph->saddr = *(uint32_t*) &tcp_state.session_info.src_addr.sin_addr.s_addr;
	iph->ihl = 5;
	iph->protocol = IPPROTO_TCP;
	iph->ttl = 255;
	iph->version = 4;
	iph->tot_len = sizeof(struct iphdr) + ip_payload_len;
	iph->check = csum((unsigned short*) iph, sizeof(struct iphdr));
}

static void build_tcp_header(struct tcphdr* tcph, tcp_flags_t* flags,
		uint16_t payload_len)
{
	tcph->dest = *(uint16_t*) &tcp_state.session_info.dst_addr.sin_port;
	tcph->source = *(uint16_t*) &tcp_state.session_info.src_addr.sin_port;
	tcph->window = htons(tcp_state.client_window_size);
	tcph->seq = htonl(tcp_state.client_next_seq_num);
	tcp_state.client_next_seq_num +=
			(flags->syn || flags->fin) ? 1 : payload_len;
	tcph->doff = (flags->syn) ? 6 : 5;
	tcph->syn = flags->syn;
	tcph->ack = flags->ack;
	tcph->fin = flags->fin;
	tcph->psh = flags->psh;
	tcph->ack_seq = htonl(tcp_state.server_next_seq_num);

	if (flags->syn)
	{
		char* tcp_options = ((char *) tcph) + sizeof(struct tcphdr);
		tcp_options_t mss = {0};
		mss.option_type = 2;
		mss.option_len = 4;
		mss.option_value = htons(1460);
		memcpy(tcp_options++, &mss.option_type, sizeof(char));
		memcpy(tcp_options++, &mss.option_len, sizeof(char));
		memcpy(tcp_options, &mss.option_value, sizeof(uint16_t));
	}
}

static void build_packet_headers(packet_t* packet, int payload_len,
		tcp_flags_t* flags)
{
	struct tcphdr* tcph = (struct tcphdr*) packet->offset[TCP_OFFSET];
	struct iphdr* iph = (struct iphdr*) packet->offset[IP_OFFSET];

	build_tcp_header(tcph, flags, payload_len);
	calculate_tcp_checksum(tcph, payload_len,
			*(uint32_t *) &tcp_state.session_info.src_addr.sin_addr.s_addr,
			*(uint32_t *) &tcp_state.session_info.dst_addr.sin_addr.s_addr);
	build_ip_header(iph, ((tcph->doff * WORD_LENGTH) + payload_len));
}

static int send_packet(void *buffer, int total_packet_len)
{
	int ret = -1;

	pthread_mutex_lock(&tcp_state.session_info.send_fd_lock);
	while (total_packet_len > 0)
	{
		//Send the packet
		if ((ret = sendto(tcp_state.session_info.send_fd, buffer,
				total_packet_len, 0,
				(struct sockaddr *) &tcp_state.session_info.dst_addr,
				sizeof(struct sockaddr_in))) < 0)
		{
			if (errno == EINTR)
			{
				printf("Sendto() Interrupted!!");
				continue;
			}
			else
			{
				perror("sendto failed");
				goto EXIT;
			}
		}
		if (ret == total_packet_len)
			break;

		total_packet_len -= ret;
		buffer += ret;
	}

	EXIT: pthread_mutex_unlock(&tcp_state.session_info.send_fd_lock);
	return ret;
}

static void handle_packet_retransmission()
{
	packet_t* packet = NULL;
	pthread_mutex_lock(&tcp_state.sender_info.tcp_retx_lock);
	int index = tcp_state.sender_info.retx_buffer_head;
	while (index != tcp_state.sender_info.retx_buffer_tail)
	{
		packet = tcp_state.sender_info.retx_buffer[index].packet;
		// 重启重传定时器
		reset_packet_retransmission_timer(&packet->retransmit_timer_id, 0);
		if (send_packet(packet->payload, packet->payload_len) < 0)
			printf("Failed to retransmit packet!!");
		reset_packet_retransmission_timer(&packet->retransmit_timer_id, 60);
		index++;
	}
	pthread_mutex_unlock(&tcp_state.sender_info.tcp_retx_lock);
}

static int send_ack_segment(uint8_t fin)
{
	int ret = -1;
	packet_t* packet = create_packet();
	tcp_flags_t flags =
	{ 0 };

	flags.ack = 1;
	flags.fin = fin;
	build_packet_headers(packet, 0, &flags);

	if ((ret = send_packet(&packet->payload,
			((struct iphdr*) packet->offset[IP_OFFSET])->tot_len)) < 0)
	{
		printf("Send error!! Exiting.. ");
	}

	EXIT: destroy_packet(packet);
	return ret;
}

static int receive_packet(packet_t *packet)
{
	int ret = -1;
	while (1)
	{
		if ((ret = recvfrom(tcp_state.session_info.recv_fd, &packet->payload,
				sizeof(packet->payload), 0,
				NULL, NULL)) < 0)
		{
			if (errno == EINTR)
				continue;
			else
			{
				perror("recv failed");
				return ret;
			}

		}
		//Data received successfully
		struct iphdr *iph = (struct iphdr *) &packet->payload;
		// printf("packet->payload:%sn", packet->payload);
		if (validate_ip_checksum(iph) < 0)
		{
			printf("IP Checksum validation failed!! Packet dropped!!n");
			continue;
		}

		uint16_t iphdr_len = iph->ihl * WORD_LENGTH;
		struct tcphdr *tcph = (struct tcphdr *) ((char*) iph + iphdr_len);
		uint16_t tcphdr_len = tcph->doff * WORD_LENGTH;

		if (iph->saddr != tcp_state.session_info.dst_addr.sin_addr.s_addr
				&& tcph->dest != tcp_state.session_info.src_port
				&& tcph->source != tcp_state.session_info.dst_port)
			continue;

		if (validate_tcp_checksum(tcph,
				(ntohs(iph->tot_len) - iphdr_len - tcphdr_len)) < 0)
		{
			printf("TCP Checksum validation failed!! Packet dropped!!n");
			continue;
		}

		if ( IS_DUPLICATE_ACK(tcph))
		{
			handle_packet_retransmission();
			continue;
		}
		else if ( IS_DUPLICATE_TCP_SEGMENT(tcph))
		{
			send_ack_segment(0);
			continue;
		}

		adjust_layer_offset(packet);
		packet->payload_len = (ntohs(iph->tot_len) - iphdr_len - tcphdr_len);
		// printf("packet->payload_len:%dn", packet->payload_len);
		break;
	}
	return ret;
}

static void process_ack(struct tcphdr *tcph, uint16_t payload_len)
{
	tcp_state.server_next_seq_num = (ntohl(tcph->seq) + payload_len);  // 当前收到的包的序号是seq,长度是payload_len,那么下一个数据包的seq就是ntohl(tcph->seq) + payload_len
	tcp_state.last_acked_seq_num = (ntohl(tcph->ack_seq));  // 下一个发包的seq

	pthread_mutex_lock(&tcp_state.tcp_state_lock);
	tcp_state.server_window_size = ntohs(tcph->window);    // 更新对端接收窗口值
	tcp_state.cwindow_size =
			(++tcp_state.cwindow_size > MAX_CONGESTION_WINDOW_SIZE) ?
					MAX_CONGESTION_WINDOW_SIZE : tcp_state.cwindow_size;
	pthread_cond_signal(&tcp_state.send_window_low_thresh);
	pthread_mutex_unlock(&tcp_state.tcp_state_lock);

	remove_acked_entries(ntohl(tcph->ack_seq));    // 删除已经收到回应的数据包
	// 更新tcp_state.max_segment_size
	if (HAS_TCP_OPTIONS(tcph))
	{
		char* tcp_options_offset = (char*) TCP_OPTION_OFFSET(tcph);
		uint16_t total_options_len = TCP_OPTIONS_LEN(tcph);

		while (!END_OF_TCP_OPTION_CHECK(tcp_options_offset)
				&& total_options_len > 0)
		{
			if ( IS_NO_OPERATION(tcp_options_offset))
			{
				tcp_options_offset++;
				total_options_len--;
			}
			else if ( IS_MSS(tcp_options_offset))
			{
				tcp_state.max_segment_size =
						min(tcp_state.max_segment_size,
								*((uint16_t*)(tcp_options_offset+TCP_OPTION_DATA_OFFSET)));
				tcp_options_offset += OPTION_LENGTH(tcp_options_offset);
				total_options_len -= OPTION_LENGTH(tcp_options_offset);
			}
			else
			{
				tcp_options_offset += OPTION_LENGTH(tcp_options_offset);
				total_options_len -= OPTION_LENGTH(tcp_options_offset);
			}
		}
	}
}

static void retransmission_timer_handler(union sigval value)
{
	int buffer_index = value.sival_int;
	packet_t* packet = NULL;

	pthread_mutex_lock(&tcp_state.tcp_state_lock);
	tcp_state.cwindow_size = 1;
	pthread_mutex_unlock(&tcp_state.tcp_state_lock);

	pthread_mutex_lock(&tcp_state.sender_info.tcp_retx_lock);

	if (tcp_state.sender_info.retx_buffer[buffer_index].packet == NULL
			|| buffer_index < tcp_state.sender_info.retx_buffer_head)
		goto EXIT;

	packet = tcp_state.sender_info.retx_buffer[buffer_index].packet;
	if (send_packet(&packet->payload,
			((struct iphdr*) packet->offset[IP_OFFSET])->tot_len) < 0)
	{
		printf("Failed to retransmit packet!!n");
	}

	EXIT: pthread_mutex_unlock(&tcp_state.sender_info.tcp_retx_lock);
}

void create_retransmission_timer(timer_t* timer, int send_buffer_index)
{
	union sigval val;
	struct sigevent sev;
	struct itimerspec timer_value = {0};

	memset(&val, 0, sizeof(val));
	memset(&sev, 0, sizeof(sev));
	val.sival_int = send_buffer_index;

	// SIGEV_THREAD:当定时器到期,内核会(在此进程内)以sigev_notification_attributes为线程属性创建一个线程,
	// 并且让它执行sigev_notify_function,传入sigev_value作为为一个参数。
	sev.sigev_notify = SIGEV_THREAD;
	sev.sigev_value = val;
	sev.sigev_notify_function = retransmission_timer_handler;    // 定时器到期,重传数据包(即超时重传)

	// 创建定时器
	// CLOCK_MONOTONIC:从系统启动这一刻起开始计时,不受系统时间被用户改变的影响
	if (timer_create(CLOCK_MONOTONIC, &sev, timer) < 0)
	{
		printf("Failed to create the retransmission timer!!");
		*timer = NULL;
		goto EXIT;
	}

	timer_value.it_interval.tv_sec = 60;  // it_interval:定时时间 60s
	timer_value.it_value.tv_sec = 60;     // it_value:单次启动时间 60s

	// 设置定时器
	if (timer_settime(*timer, 0, &timer_value, NULL) < 0)
	{
		printf("Failed to set time!!");
		timer_delete(*timer);
		*timer = NULL;
	}

	EXIT: return;
}

static int send_tcp_segment(packet_t* packet)
{
	int ret = 0;

	if ((ret = send_packet(&packet->payload,
			((struct iphdr*) packet->offset[IP_OFFSET])->tot_len)) < 0)
	{
		printf("Send error!! Exiting.. ");
		goto EXIT;
	}
	// 创建重传定时器,超时重传数据包 NULL 0
	create_retransmission_timer(&packet->retransmit_timer_id,
			tcp_state.sender_info.retx_buffer_tail);

	pthread_mutex_lock(&tcp_state.sender_info.tcp_retx_lock);

	// 数据包写入发送循环队列
	tcp_state.sender_info.retx_buffer[tcp_state.sender_info.retx_buffer_tail].packet_seq =
			((struct tcphdr*) &packet->offset[TCP_OFFSET])->seq;
	tcp_state.sender_info.retx_buffer[tcp_state.sender_info.retx_buffer_tail].packet =
			packet;
	// 发送尾指针加一,指向下一个空队列空间
	tcp_state.sender_info.retx_buffer_tail =
	WRAP_ROUND_BUFFER_SIZE(tcp_state.sender_info.retx_buffer_tail);

	pthread_mutex_unlock(&tcp_state.sender_info.tcp_retx_lock);

	EXIT: return ret;
}

static int send_syn()
{
	int ret = -1;
	packet_t* packet = create_packet();
	tcp_flags_t flags = {0};

	flags.syn = 1;
	build_packet_headers(packet, 0, &flags);
	tcp_state.tcp_current_state = SYN_SENT;

	return send_tcp_segment(packet);
}

static int receive_syn_ack_segment(tcp_flags_t* flags)
{
	int ret = -1;
	packet_t* packet = create_packet();
	struct tcphdr *tcph;

	while (1)
	{
		if ((ret = receive_packet(packet)) < 0)
		{
			printf("Receive error!! Exiting.. ");
			goto EXIT;
		}

		tcph = (struct tcphdr *) packet->offset[TCP_OFFSET];

		if (tcph->ack == flags->ack && tcph->syn == flags->syn)
			break;

		if (tcph->rst || !tcp_state.syn_retries)
		{
			ret = -1;
			goto EXIT;
		}
	}

	process_ack(tcph, 1);

	EXIT: destroy_packet(packet);
	return ret;
}

static int initialize_mutex(pthread_mutex_t* mutex)
{
	int ret = -1;
	pthread_mutexattr_t mutex_attr;

	if ((ret = pthread_mutexattr_init(&mutex_attr)) != 0)
	{
		printf("Failed to initialize mutex attributen");
		ret = -1;
		goto EXIT;
	}

	if ((ret = pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_RECURSIVE))
			!= 0)
	{
		printf("Failed to set mutex attributen");
		ret = -1;
		goto EXIT;
	}

	if ((ret = pthread_mutex_init(mutex, &mutex_attr)) != 0)
	{
		printf("Failed to initialize mutex!!n");
		ret = -1;
	}

	EXIT: return ret;
}

static void get_wait_time(struct timespec* timeToWait, uint16_t timeInSeconds)
{
	struct timeval now;
	int rt;

	gettimeofday(&now, NULL);

	timeToWait->tv_sec = now.tv_sec + timeInSeconds;
	timeToWait->tv_nsec = 0;
}

//Blocking call
int connect_tcp(int send_fd, int recv_fd, struct sockaddr_in* dst_addr,
		struct sockaddr_in* src_addr)
{
	int ret = 0;

// Initialize the TCP Session State with the given details
	bzero(&tcp_state, sizeof(tcp_state__t));
	tcp_state.max_segment_size = MAX_CLIENT_SEGMENT_SIZE;    // 初始化MSS
	tcp_state.client_window_size = CLIENT_WINDOW_SIZE;       // 初始化拥塞窗口
	tcp_state.client_next_seq_num = STARTING_SEQUENCE;       // 客户端下个包的seq
	tcp_state.session_info.dst_addr = *dst_addr;             // 目的地址
	tcp_state.session_info.src_addr = *src_addr;             // 源地址
	tcp_state.session_info.recv_fd = recv_fd;                // 接收句柄
	tcp_state.session_info.send_fd = send_fd;                // 发送句柄
	tcp_state.syn_retries = 5;                               // 重传次数
	tcp_state.cwindow_size = 1;    // 拥塞窗口值
	initialize_mutex(&tcp_state.tcp_state_lock);
	initialize_mutex(&tcp_state.session_info.send_fd_lock);

	tcp_flags_t flags = {0};
	flags.ack = 1;
	flags.syn = 1;
	if (((ret = send_syn()) < 0) || ((ret = receive_syn_ack_segment(&flags)) < 0)
	                             || ((ret = send_ack_segment(0)) < 0))
	{
		printf("Failed to set up TCP Connection!!");
		ret = -1;
		goto EXIT;
	}
	tcp_state.tcp_current_state = ESTABLISHED;

	EXIT: return ret;
}

static int send_fin()
{
	int ret = -1;
	packet_t* packet = create_packet();
	tcp_flags_t flags = {0};

	flags.fin = 1;
	flags.ack = 1;
	build_packet_headers(packet, 0, &flags);

	return send_tcp_segment(packet);
}

int close_tcp()
{
	int ret = -1;
	pthread_mutex_lock(&tcp_state.tcp_state_lock);
	if (!((tcp_state.tcp_current_state & ESTABLISHED)
			|| (tcp_state.tcp_current_state & CLOSE_WAIT)))
	{
		pthread_mutex_unlock(&tcp_state.tcp_state_lock);
		goto EXIT;
	}
	pthread_mutex_unlock(&tcp_state.tcp_state_lock);

	if ((ret = send_fin()) < 0)
		goto EXIT;

	struct timespec timeToWait;
	get_wait_time(&timeToWait, 10);

	pthread_mutex_lock(&tcp_state.tcp_state_lock);

	if (tcp_state.tcp_current_state & ESTABLISHED)
		tcp_state.tcp_current_state = FIN_WAIT_1;
	else
		tcp_state.tcp_current_state = LAST_ACK;

	tcp_state.tcp_write_end_closed = 1;
	pthread_cond_timedwait(&tcp_state.tcp_session_closed_notify,
			&tcp_state.tcp_state_lock, &timeToWait);

	pthread_mutex_unlock(&tcp_state.tcp_state_lock);

	EXIT: return ret;
}

static void release_and_update_recv_buffer(packet_t* packet)
{
	pthread_mutex_lock(&tcp_state.recv_info.tcp_recv_lock);

	tcp_state.recv_info.recv_buffer[tcp_state.recv_info.recv_buffer_head].packet =
	NULL;
	tcp_state.recv_info.recv_buffer_head =
	WRAP_ROUND_BUFFER_SIZE(tcp_state.recv_info.recv_buffer_head);
	destroy_packet(packet);
	pthread_cond_signal(&tcp_state.recv_info.recv_buffer_full);

	pthread_mutex_unlock(&tcp_state.recv_info.tcp_recv_lock);

}

int receive_data(char* buffer, int buffer_len)
{
	int total_bytes_read = 0, ret = -1;
	packet_t* packet = NULL;
	struct timespec timeToWait;

	while (buffer_len > 0)
	{
		get_wait_time(&timeToWait, 5);

		pthread_mutex_lock(&tcp_state.recv_info.tcp_recv_lock);
		if (tcp_state.recv_info.recv_buffer_head
				== tcp_state.recv_info.recv_buffer_tail)
		{
			if (total_bytes_read > 0)
			{
				pthread_mutex_unlock(&tcp_state.recv_info.tcp_recv_lock);
				break;
			}
			else
			{
				if ((ret = pthread_cond_timedwait(
						&tcp_state.recv_info.recv_buffer_empty,
						&tcp_state.recv_info.tcp_recv_lock, &timeToWait)) != 0)
				{
					pthread_mutex_unlock(&tcp_state.recv_info.tcp_recv_lock);
					if (ret == ETIMEDOUT)
					{
						pthread_mutex_lock(&tcp_state.tcp_state_lock);
						if (tcp_state.tcp_read_end_closed)
						{
							printf("TCP Server Closed!!n");
							total_bytes_read = -1;
							pthread_mutex_unlock(&tcp_state.tcp_state_lock);
							break;
						}
						pthread_mutex_unlock(&tcp_state.tcp_state_lock);
						continue;
					}
					else
						break;
				}
			}
		}

		packet =
				tcp_state.recv_info.recv_buffer[tcp_state.recv_info.recv_buffer_head].packet;
		pthread_mutex_unlock(&tcp_state.recv_info.tcp_recv_lock);

		int copied_bytes = 0;
		if (packet->payload_len > buffer_len)
		{
			printf("CHUNKED TRANSFER: %d:%dn", packet->payload_len,
					buffer_len);
			memcpy((buffer + total_bytes_read), packet->offset[DATA_OFFSET],
					buffer_len);
			packet->offset[DATA_OFFSET] += buffer_len;
			packet->payload_len -= buffer_len;
			total_bytes_read += buffer_len;
			copied_bytes = buffer_len;
			buffer_len = 0;
		}
		else
		{
			memcpy((buffer + total_bytes_read), packet->offset[DATA_OFFSET],
					packet->payload_len);
			buffer_len -= packet->payload_len;
			total_bytes_read += packet->payload_len;
			copied_bytes = packet->payload_len;
			release_and_update_recv_buffer(packet);
		}

		pthread_mutex_lock(&tcp_state.tcp_state_lock);
		tcp_state.client_window_size += copied_bytes;
		tcp_state.client_window_size =
				(tcp_state.client_window_size > CLIENT_WINDOW_SIZE) ?
						CLIENT_WINDOW_SIZE : tcp_state.client_window_size;
		pthread_mutex_unlock(&tcp_state.tcp_state_lock);
	}

	return total_bytes_read;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
  • 407
  • 408
  • 409
  • 410
  • 411
  • 412
  • 413
  • 414
  • 415
  • 416
  • 417
  • 418
  • 419
  • 420
  • 421
  • 422
  • 423
  • 424
  • 425
  • 426
  • 427
  • 428
  • 429
  • 430
  • 431
  • 432
  • 433
  • 434
  • 435
  • 436
  • 437
  • 438
  • 439
  • 440
  • 441
  • 442
  • 443
  • 444
  • 445
  • 446
  • 447
  • 448
  • 449
  • 450
  • 451
  • 452
  • 453
  • 454
  • 455
  • 456
  • 457
  • 458
  • 459
  • 460
  • 461
  • 462
  • 463
  • 464
  • 465
  • 466
  • 467
  • 468
  • 469
  • 470
  • 471
  • 472
  • 473
  • 474
  • 475
  • 476
  • 477
  • 478
  • 479
  • 480
  • 481
  • 482
  • 483
  • 484
  • 485
  • 486
  • 487
  • 488
  • 489
  • 490
  • 491
  • 492
  • 493
  • 494
  • 495
  • 496
  • 497
  • 498
  • 499
  • 500
  • 501
  • 502
  • 503
  • 504
  • 505
  • 506
  • 507
  • 508
  • 509
  • 510
  • 511
  • 512
  • 513
  • 514
  • 515
  • 516
  • 517
  • 518
  • 519
  • 520
  • 521
  • 522
  • 523
  • 524
  • 525
  • 526
  • 527
  • 528
  • 529
  • 530
  • 531
  • 532
  • 533
  • 534
  • 535
  • 536
  • 537
  • 538
  • 539
  • 540
  • 541
  • 542
  • 543
  • 544
  • 545
  • 546
  • 547
  • 548
  • 549
  • 550
  • 551
  • 552
  • 553
  • 554
  • 555
  • 556
  • 557
  • 558
  • 559
  • 560
  • 561
  • 562
  • 563
  • 564
  • 565
  • 566
  • 567
  • 568
  • 569
  • 570
  • 571
  • 572
  • 573
  • 574
  • 575
  • 576
  • 577
  • 578
  • 579
  • 580
  • 581
  • 582
  • 583
  • 584
  • 585
  • 586
  • 587
  • 588
  • 589
  • 590
  • 591
  • 592
  • 593
  • 594
  • 595
  • 596
  • 597
  • 598
  • 599
  • 600
  • 601
  • 602
  • 603
  • 604
  • 605
  • 606
  • 607
  • 608
  • 609
  • 610
  • 611
  • 612
  • 613
  • 614
  • 615
  • 616
  • 617
  • 618
  • 619
  • 620
  • 621
  • 622
  • 623
  • 624
  • 625
  • 626
  • 627
  • 628
  • 629
  • 630
  • 631
  • 632
  • 633
  • 634
  • 635
  • 636
  • 637
  • 638
  • 639
  • 640
  • 641
  • 642
  • 643
  • 644
  • 645
  • 646
  • 647
  • 648
  • 649
  • 650
  • 651
  • 652
  • 653
  • 654
  • 655
  • 656
  • 657
  • 658
  • 659
  • 660
  • 661
  • 662
  • 663
  • 664
  • 665
  • 666
  • 667
  • 668
  • 669
  • 670
  • 671
  • 672
  • 673
  • 674
  • 675
  • 676
  • 677
  • 678
  • 679
  • 680
  • 681
  • 682
  • 683
  • 684
  • 685
  • 686
  • 687
  • 688
  • 689
  • 690
  • 691
  • 692
  • 693
  • 694
  • 695
  • 696
  • 697
  • 698
  • 699
  • 700
  • 701
  • 702
  • 703
  • 704
  • 705
  • 706
  • 707
  • 708
  • 709
  • 710
  • 711
  • 712
  • 713
  • 714
  • 715
  • 716
  • 717
  • 718
  • 719
  • 720
  • 721
  • 722
  • 723
  • 724
  • 725
  • 726
  • 727
  • 728
  • 729
  • 730
  • 731
  • 732
  • 733
  • 734
  • 735
  • 736
  • 737
  • 738
  • 739
  • 740
  • 741
  • 742
  • 743
  • 744
  • 745
  • 746
  • 747
  • 748
  • 749
  • 750
  • 751
  • 752
  • 753
  • 754
  • 755
  • 756
  • 757
  • 758
  • 759
  • 760
  • 761
  • 762
  • 763
  • 764
  • 765
  • 766
  • 767
  • 768
  • 769
  • 770
  • 771
  • 772
  • 773
  • 774
  • 775

tcp_ハンドラ.h

#ifndef TCP_HANDLER_H_
#define TCP_HANDLER_H_

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <errno.h>
#include <string.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <string.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <pthread.h>
#include <signal.h>
#include <time.h>
#include <sys/time.h>

#define TOTAL_LAYERS  2
#define IP_LAYER_OFFSET  0
#define TCP_LAYER_OFFSET 1
#define PAYLOAD_OFFSET 2
#define CLIENT_PORT 35555
#define HTTP_PORT 80
#define RTAX_MAX 8
#define IP_OFFSET 0
#define TCP_OFFSET 1
#define DATA_OFFSET 2
#define MAX_BUFFER_SIZE 400
#define MAX_CLIENT_SEGMENT_SIZE 1460
// #define CLIENT_WINDOW_SIZE 16384
#define CLIENT_WINDOW_SIZE 12000
#define WORD_LENGTH 4
// #define PACKET_MAX_SIZE 16384
#define PACKET_MAX_SIZE 12000
#define MAX_PAYLOAD_LEN (PACKET_MAX_SIZE - sizeof(struct iphdr) - sizeof(struct tcphdr))
#define MAX_CONGESTION_WINDOW_SIZE 1000

typedef enum
{
	SYN_SENT = 1,
	ESTABLISHED = 2,
	FIN_WAIT_1 = 4,
	FIN_WAIT_2 = 8,
	CLOSE_WAIT = 16,
	CLOSING = 32,
	LAST_ACK = 64,
	CLOSED = 128
} tcp_state_machine_t;

typedef struct
{
	uint8_t syn :1;
	uint8_t ack :1;
	uint8_t fin :1;
	uint8_t psh :1;
} tcp_flags_t;

typedef struct
{
	uint8_t option_type;
	uint8_t option_len;
	uint16_t option_value;
} tcp_options_t;

typedef struct
{
	char payload[PACKET_MAX_SIZE];
	char* offset[TOTAL_LAYERS + 1];
	timer_t retransmit_timer_id;
	uint16_t payload_len;
} packet_t;

typedef struct
{
	packet_t* packet;
	uint32_t packet_seq;
} buffered_packet_t;

// TCP 伪首部
typedef struct
{
	u_int32_t source_address;
	u_int32_t dest_address;
	u_int8_t placeholder;
	u_int8_t protocol;
	u_int16_t tcp_length;
} pseudo_header;

typedef struct
{
	struct sockaddr_in src_addr;
	struct sockaddr_in dst_addr;
	uint16_t src_port;
	uint16_t dst_port;
	int send_fd;
	int recv_fd;
	pthread_mutex_t send_fd_lock;
} session_info__t;

typedef struct
{
	buffered_packet_t send_buffer[MAX_BUFFER_SIZE];
	uint16_t send_buffer_head;
	uint16_t send_buffer_tail;
	buffered_packet_t retx_buffer[MAX_BUFFER_SIZE];
	uint16_t retx_buffer_head;
	uint16_t retx_buffer_tail;
	pthread_mutex_t tcp_send_lock;
	pthread_mutex_t tcp_retx_lock;
	pthread_cond_t send_buffer_empty;
	pthread_cond_t send_buffer_full;
} tcp_send_data_t;

typedef struct
{
	buffered_packet_t recv_buffer[MAX_BUFFER_SIZE];
	uint16_t recv_buffer_head;
	uint16_t recv_buffer_tail;
	pthread_mutex_t tcp_recv_lock;
	pthread_cond_t recv_buffer_empty;
	pthread_cond_t recv_buffer_full;
} tcp_recv_data_t;

typedef struct
{
	session_info__t session_info;
	uint32_t client_next_seq_num;    // 本端发送的下一个数据包的seq
	uint32_t last_acked_seq_num;     // (相对的)三次回应包的seq
	uint32_t server_next_seq_num;    // 对端下一个包的seq(即希望对方下一个包的数据是从第seq开始的)
	uint16_t server_window_size;
	uint16_t client_window_size;
	uint16_t max_segment_size;
	uint16_t cwindow_size;
	uint16_t ssthresh;
	pthread_cond_t send_window_low_thresh;
	uint8_t syn_retries;
	tcp_send_data_t sender_info;
	tcp_recv_data_t recv_info;
	pthread_mutex_t tcp_state_lock;
	pthread_cond_t tcp_session_closed_notify;
	uint8_t tcp_write_end_closed;
	uint8_t tcp_read_end_closed;
	pthread_t tcp_worker_threads[2];
	tcp_state_machine_t tcp_current_state;
} tcp_state__t;

int connect_tcp(int send_fd, int recv_fd, struct sockaddr_in* dst_addr,
		struct sockaddr_in* src_addr);

int send_data(char* buffer, int buffer_len);

int receive_data(char* buffer, int buffer_len);

int close_tcp();

#endif /* TCP_HANDLER_H_ */

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160

このコードのリファレンス: https://github.com/praveenkmurthy/Raw-Sockets