기술나눔

원시 소켓(1) TCP 3방향 핸드셰이크 구현

2024-07-12

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

연구실 환경:
Windows 물리적 머신: 192.168.1.4
WSL 우분투 20.04.6 LTS:172.19.32.196
Windows의 http 서버: HFS는 다음과 같습니다.
여기에 이미지 설명을 삽입하세요.
클라이언트는 우분투(Ubuntu), 서버는 http 서버(이하 서버 또는 서버라 함)이며, 서버 IP는 매개변수를 통해 프로그램에 전달된다.

소스코드는 맨 마지막에 있습니다.

주요 기능 프로그램은 다음과 같은 부분으로 나누어집니다:
1. 매개변수 가져오기 , netlink 통신을 통해 통신할 네트워크 카드를 선택하고 (실제로 Ubuntu에는 네트워크 카드가 하나 뿐이며 IP는 172.19.32.196입니다) 서버와 클라이언트의 IP와 포트를 초기화합니다. netlink 통신을 통한 통신을 위한 네트워크 카드 선택에 대한 자세한 내용은 다음 링크를 참조하십시오.
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는 소켓 유형이 원시 소켓임을 나타냅니다.
세 번째 매개변수는 프로토콜 매개변수입니다. IPPROTO_RAW는 개발자가 이를 소켓 전송을 위한 프로토콜 유형으로 사용하여 나가는 데이터 패킷을 직접 캡슐화하고 체크섬을 계산할 수 있음을 의미합니다. , 수신된 데이터 패킷이 TCP 데이터 패킷임을 나타냅니다.
       클라이언트 IP와 포트 바인딩: 이 단계는 위에서 언급한 것처럼 양측의 IP 주소와 포트는 변경되지 않습니다.
       소켓 프로토콜 속성 설정:setsockopt는 수신 소켓의 속성을 설정합니다. 두 번째 매개변수는 소켓 옵션입니다.
       (1) 소켓 레벨 옵션(솔_소켓)
SO_REUSEADDR: 로컬 주소 재사용을 허용합니다.
SO_RCVBUF: 수신 버퍼 크기를 설정합니다.
SO_SNDBUF: 전송 버퍼 크기를 설정합니다.
SO_BROADCAST: 브로드캐스트 메시지 전송을 허용합니다.
SO_KEEPALIVE: 연결 유지 메커니즘을 활성화하고 연결이 유효한지 확인합니다.
       (2) IP 계층 옵션(IPPROTO_IP)
IP_TTL: IP 데이터그램의 TTL(Time to Live)을 설정합니다.
IP_HDRINCL: 애플리케이션에 IP 헤더를 제공하도록 지시합니다.
       (3) TCP 레이어 옵션(IPPROTO_TCP)
TCP_NODELAY: 지연을 줄이기 위해 Nagle 알고리즘을 비활성화합니다.
TCP_MAXSEG: TCP 최대 세그먼트 크기를 설정합니다.
이 예에서 소켓 옵션은 IPPROTO_IP의 IP 계층 옵션 IP_HDRINCL로 설정되어 수신된 패킷에 IP 헤더가 포함되어 있음을 나타냅니다.

       

세 번의 악수를 시작하세요

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로 변경되므로 TCP 상태를 설정해야 합니다. tcp_state.tcp_current_state = SYN_SENT를 사용하면 sendto를 사용할 수 있습니다. 데이터를 전송하려면 재전송 타이머를 생성하려면 콜백 기능을 설정해야 합니다. SYN 패킷이 전송된 후 제한 시간 내에 응답이 수신되지 않으면 SYN 패킷을 재전송해야 합니다. 따라서 전송된 패킷을 전송 순환 큐 버퍼에 기록해야 합니다. 시간 초과 후에는 저장된 데이터를 전송 순환 큐에서 꺼내어 다시 전송합니다. 이 기사에서는 순환 큐에 대해 설명하지 않습니다.
       2. SYN/ACK 패킷을 수신합니다. 해당 기능은 receive_syn_ack_segment(&flags)입니다.
데이터를 수신하려면 Recvfrom 함수를 사용하십시오. 데이터를 수신한 후 IP 체크섬 확인, 소스 및 대상 포트와 IP가 올바른지 확인, TCP 체크섬 확인, IP 체크섬 확인 등 일련의 확인을 수행해야 합니다. 패킷은 재전송 패킷입니다. 그런 다음 데이터 패킷의 IP 헤더, TCP 헤더 및 데이터의 오프셋 방향도 설정해야 합니다. 그러면 수신된 패킷의 SYN 플래그와 ACK 플래그가 1인지, RST 패킷인지를 확인할 수 있습니다. 이러한 작업을 완료한 후에도 서버에서 다음 패킷의 seq 설정, 클라이언트에서 다음 패킷의 seq 설정, 서버의 수신 창 값 업데이트, 혼잡 창 값, 수신 창부터 시작합니다. 이 응답 패킷을 순환 대기열에서 삭제하고(처리되었으므로) 이 패킷을 수신하기 위해 생성된 공간을 해제하고 MSS를 업데이트합니다.
       3. ACK 패킷을 보냅니다. 해당 기능은 send_ack_segment(0)입니다.
세 번째 단계는 매우 간단합니다. 3방향 핸드셰이크가 성공했음을 나타내는 응답을 보냅니다. 매개변수 0은 FIN 플래그가 0, 즉 패킷이 ACK 패킷임을 의미합니다. TCP 상태를 ESTABLISHED로 설정합니다.

그러면 결과는 무엇입니까? 프로그램을 실행하고 Wireshark를 사용하여 패킷을 캡처합니다.
여기에 이미지 설명을 삽입하세요.

여기에 이미지 설명을 삽입하세요.
       SYN 패킷을 보내고 SYN/ACK를 받은 후 클라이언트가 어떻게든 또 다른 RST 패킷을 보낸 다음 ACK 패킷을 보낸 것을 볼 수 있습니다. 프로그램은 성공적으로 실행되는 것처럼 보였지만 실제로는 3방향 핸드셰이크를 통해 설정되었습니다. 연결에 실패. .
       그 이유는 무엇입니까?

        이 프로그램은 통신을 위해 시스템 호출이 아닌 원시 소켓을 사용합니다. 클라이언트가 SYN/ACK를 보내면 운영 체제는 먼저 패킷을 수신한 다음 로컬에서 해당 소켓(시스템 호출을 사용하여 생성됨)이 있는지 확인합니다. 아무도 없으면 RST 패킷이 전송되고 3방향 핸드셰이크가 연결 설정에 실패합니다. .

       그렇다면 어떻게 해결해야 할까요?

이 프로그램은 주로 실험 학습을 위한 것이므로 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_handler.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