Exemplo n.º 1
0
// 这个函数用于连接服务器. 它以套接字ID和服务器的端口号作为输入参数. 套接字ID用于找到TCB条目.  
// 这个函数设置TCB的服务器端口号,  然后使用sip_sendseg()发送一个SYN段给服务器.  
// 在发送了SYN段之后, 一个定时器被启动. 如果在SYNSEG_TIMEOUT时间之内没有收到SYNACK, SYN 段将被重传. 
// 如果收到了, 就返回1. 否则, 如果重传SYN的次数大于SYN_MAX_RETRY, 就将state转换到CLOSED, 并返回-1.
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
int stcp_client_connect(int sockfd, unsigned int server_port)
{
	seg_t sendbuf;
	memset(&sendbuf, 0, sizeof(sendbuf));
	tcb[sockfd]->server_portNum = server_port;
	sendbuf.header.src_port = tcb[sockfd]->client_portNum;
	sendbuf.header.dest_port = tcb[sockfd]->server_portNum;
	sendbuf.header.type = SYN;
	sendbuf.header.seq_num = 0;
	printf("==========client port %d send SYN===========\n", tcb[sockfd]->client_portNum);
	sip_sendseg(sipfd, &sendbuf);
	tcb[sockfd]->state = SYNSENT;
	tcb[sockfd]->next_seqNum = 1;

	int i = 0;
	for(i = 0; i < SYN_MAX_RETRY; i++){
		usleep(SYN_TIMEOUT / 1000);					//sleep and then judge
		if(tcb[sockfd]->state == CONNECTED)
			break;
		printf("==========client port %d send SYN==========\n", tcb[sockfd]->client_portNum);
		sip_sendseg(sipfd, &sendbuf);
		tcb[sockfd]->state = SYNSENT;
	}
	switch(tcb[sockfd]->state){
		case CONNECTED:
			return 1;
		default:
			tcb[sockfd]->state = CLOSED;
			return -1;
	}
	return -1;
}
Exemplo n.º 2
0
int stcp_client_connect(int sockfd, unsigned int server_port) {
	int resend_syn_times = 0;
	seg_t *segPtr1;
	tcb_table[sockfd]->server_portNum = server_port;
	segPtr1 = (seg_t *)malloc(sizeof(seg_t));
	segPtr1->header.src_port = tcb_table[sockfd]->client_portNum;
	segPtr1->header.dest_port = tcb_table[sockfd]->server_portNum;
	segPtr1->header.seq_num = tcb_table[sockfd]->next_seqNum;
	segPtr1->header.ack_num = 0;
	segPtr1->header.length = sizeof(seg_t);//???
	segPtr1->header.type = SYN;
	segPtr1->header.rcv_win = 0;
	segPtr1->header.checksum = 0;
	sip_sendseg(connection, segPtr1);
	printf("Client(SYNSENT): send a SYN segment data(src_port: %d, dest_port: %d)\n", segPtr1->header.src_port, segPtr1->header.dest_port);
	tcb_table[sockfd]->state = SYNSENT;
	// set timer and check state to confirm the ack
	while (resend_syn_times < SYN_MAX_RETRY ) {
		  usleep(SYN_TIMEOUT / 1000);
		if (tcb_table[sockfd]->state == CONNECTED) {
			return 1;
		}
		printf("Client(SYNSENT): Resend a SYN segment data(src_port: %d, dest_port: %d)\n", 
		segPtr1->header.src_port, segPtr1->header.dest_port);
		sip_sendseg(connection, segPtr1);
		resend_syn_times ++;
	}
	tcb_table[sockfd]->state = CLOSED;
	printf("Client(CLOSED): after send SYN(src_port: %d, dest_port: %d), cann't receive SYNACK \n",
	segPtr1->header.src_port, segPtr1->header.dest_port);
	return -1;
}
Exemplo n.º 3
0
// 这个函数用于连接服务器. 它以套接字ID, 服务器节点ID和服务器的端口号作为输入参数. 套接字ID用于找到TCB条目.  
// 这个函数设置TCB的服务器节点ID和服务器端口号,  然后使用sip_sendseg()发送一个SYN段给服务器.  
// 在发送了SYN段之后, 一个定时器被启动. 如果在SYNSEG_TIMEOUT时间之内没有收到SYNACK, SYN 段将被重传. 
// 如果收到了, 就返回1. 否则, 如果重传SYN的次数大于SYN_MAX_RETRY, 就将state转换到CLOSED, 并返回-1.
int stcp_client_connect(int sockfd, int nodeID, unsigned int server_port) 
{
	int num=0;
	client_tcb_t* tmp = tcbtable[sockfd];
	tmp->server_portNum = server_port;
	tmp->server_nodeID=nodeID;
	tmp->state = SYNSENT;
	seg_t tmpseg;
	tmpseg.header.src_port = tmp->client_portNum;
	tmpseg.header.dest_port = tmp->server_portNum;
	tmpseg.header.length = sizeof(stcp_hdr_t);
	tmpseg.header.type = SYN;
	tmpseg.header.seq_num = 0;
	tmpseg.header.ack_num = 0;
	tmpseg.header.rcv_win = 0;
	tmpseg.header.checksum = 0;
	tmpseg.header.checksum = checksum(&tmpseg);

	sip_sendseg(sip_conn,nodeID,&tmpseg);
	//num++;
	usleep(SYN_TIMEOUT/1000);
	while(num<SYN_MAX_RETRY && tmp->state == SYNSENT){
		//定时器
		sip_sendseg(sip_conn,nodeID, &tmpseg);
		num++;
		usleep(SYN_TIMEOUT/1000);
	}
	if(num == SYN_MAX_RETRY)
	{
		tmp->state = CLOSED;
		return -1;
	}
	else 
		return 1;
}
Exemplo n.º 4
0
// 这个函数用于断开到服务器的连接. 它以套接字ID作为输入参数. 套接字ID用于找到TCB表中的条目.  
// 这个函数发送FIN段给服务器. 在发送FIN之后, state将转换到FINWAIT, 并启动一个定时器.
// 如果在最终超时之前state转换到CLOSED, 则表明FINACK已被成功接收. 否则, 如果在经过FIN_MAX_RETRY次尝试之后,
// state仍然为FINWAIT, state将转换到CLOSED, 并返回-1.
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
int stcp_client_disconnect(int sockfd)
{	
	while(client_tcb[sockfd]->sendBufHead != NULL) {
		usleep(100000);
	}
	printf("----------------stcp client disconnect start!----------------\n");
	
  	int tryno;
  	tryno = 0;
	
	seg_t *seg = (seg_t*)malloc(sizeof(seg_t));

	seg->header.src_port = client_tcb[sockfd]->client_portNum;        //源端口号
	seg->header.dest_port = client_tcb[sockfd]->server_portNum;       //目的端口号
	seg->header.seq_num = client_tcb[sockfd]->next_seqNum;         //序号
	seg->header.ack_num = 0;         //确认号
	seg->header.length = 0;    //段数据长度
	seg->header.type = FIN;     //段类型
	seg->header.rcv_win = 0;  //当前未使用
	seg->header.checksum = 0;
	seg->header.checksum = checksum(seg);  //这个段的校验和

	client_tcb[sockfd]->next_seqNum++;
  	sip_sendseg(gSockFd, seg);
	client_tcb[sockfd]->state = FINWAIT;
	
	usleep(100000);
	
  	while (client_tcb[sockfd]->state == FINWAIT) {
		printf("the time to disconnect from the stcp server is out, start resend!\n");
		sip_sendseg(gSockFd, seg);
		tryno++;
		if (tryno > FIN_MAX_RETRY) {
			printf("the resend time is over FIN_MAX_RETRY, the state turn to CLOSED and return -1!\n");
			client_tcb[sockfd]->state = CLOSED;
			segBuf_t *p = client_tcb[sockfd]->sendBufHead;
			while (p != NULL) {//清空缓冲区
				client_tcb[sockfd]->sendBufHead = p->next;
				free(p);
				p = client_tcb[sockfd]->sendBufHead;
				client_tcb[sockfd]->unAck_segNum--;
			}
			return -1;
		}
		usleep(100000);
  	}
	segBuf_t *p = client_tcb[sockfd]->sendBufHead;
	while (p != NULL) {//清空缓冲区
		client_tcb[sockfd]->sendBufHead = p->next;
		free(p);
		p = client_tcb[sockfd]->sendBufHead;
		client_tcb[sockfd]->unAck_segNum--;
	}
  	return 1;
}
Exemplo n.º 5
0
// 这个函数用于断开到服务器的连接. 它以套接字ID作为输入参数. 套接字ID用于找到TCB表中的条目.  
// 这个函数发送FIN段给服务器. 在发送FIN之后, state将转换到FINWAIT, 并启动一个定时器.
// 如果在最终超时之前state转换到CLOSED, 则表明FINACK已被成功接收. 否则, 如果在经过FIN_MAX_RETRY次尝试之后,
// state仍然为FINWAIT, state将转换到CLOSED, 并返回-1.
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
int stcp_client_disconnect(int sockfd)
{
	seg_t sendbuf;
	memset(&sendbuf, 0, sizeof(sendbuf));
	sendbuf.header.src_port = tcb[sockfd]->client_portNum;
	sendbuf.header.dest_port = tcb[sockfd]->server_portNum;
	sendbuf.header.type = FIN;
	tcb[sockfd]->state = FINWAIT;
	printf("===========client port %d send FIN===========\n", tcb[sockfd]->client_portNum);
	sip_sendseg(sipfd, &sendbuf);

	int i = 0;
	for(i = 0; i < FIN_MAX_RETRY; i++){
		usleep(FIN_TIMEOUT / 1000);					//sleep and then judge
		if(tcb[sockfd]->state == CLOSED)
			break;
		printf("try to disconnect times %d\n", i+1);
		tcb[sockfd]->state = FINWAIT;
		printf("==========client port %d send FIN===========\n", tcb[sockfd]->client_portNum);
		sip_sendseg(sipfd, &sendbuf);
	}
	pthread_mutex_lock(tcb[sockfd]->bufMutex);
	segBuf_t *p = tcb[sockfd]->sendBufHead;
	switch(tcb[sockfd]->state){
		case CLOSED:
			while(tcb[sockfd]->sendBufHead != NULL){
				p = tcb[sockfd]->sendBufHead;
				tcb[sockfd]->sendBufHead = tcb[sockfd]->sendBufHead->next;
				free(p);
			}
			pthread_mutex_unlock(tcb[sockfd]->bufMutex);
			return 1;
		case FINWAIT:
			tcb[sockfd]->state = CLOSED;
			pthread_mutex_lock(tcb[sockfd]->bufMutex);
			while(tcb[sockfd]->sendBufHead != NULL){
				p = tcb[sockfd]->sendBufHead;
				tcb[sockfd]->sendBufHead = tcb[sockfd]->sendBufHead->next;
				free(p);
			}
			pthread_mutex_unlock(tcb[sockfd]->bufMutex);
			return -1;
		default:
			pthread_mutex_unlock(tcb[sockfd]->bufMutex);
			printf("can't be here in stcp_client_disconnect\n");
	}
	return -1;
}
Exemplo n.º 6
0
//这个线程持续轮询发送缓冲区以触发超时事件. 如果发送缓冲区非空, 它应一直运行.
//如果(当前时间 - 第一个已发送但未被确认段的发送时间) > DATA_TIMEOUT, 就发生一次超时事件.
//当超时事件发生时, 重新发送所有已发送但未被确认段. 当发送缓冲区为空时, 这个线程将终止.
void* sendBuf_timer(void* clientfd) 
{
	int sockfd = *(int *)clientfd;
	free(clientfd);
	client_tcb_t *tmp = tcb[sockfd];
	printf("sendBuf_timer start running \n");
	while(1){
		usleep(SENDBUF_POLLING_INTERVAL/1000);
		pthread_mutex_lock(tmp->bufMutex);
		if(tmp->sendBufHead == NULL){
			printf("sendBuf_timer exit\n");
			pthread_mutex_unlock(tmp->bufMutex);
			pthread_exit(NULL);
		}
		else if(time(NULL) - tmp->sendBufHead->sentTime > DATA_TIMEOUT) {
			segBuf_t *p = tmp->sendBufHead;
			//int un_ack = tmp->unAck_segNum;
			while(p != tmp->sendBufunSent){
				p->sentTime = time(NULL);
				printf("RE SEND SEG%d----------\n", p->seg.header.seq_num);
				sip_sendseg(sip_conn, tmp->server_nodeID,  &(p->seg));
				p = p->next;
			}
		}
		pthread_mutex_unlock(tmp->bufMutex);
	}
	pthread_exit(NULL);
}
Exemplo n.º 7
0
void* sendBuf_timer(void* clienttcb)
{
	// 设置定时器
	int sockfd = *(int *)clienttcb;
	while (1) {
		if (tcb_table[sockfd]->state == CONNECTED && tcb_table[sockfd]->sendBufHead != NULL) {
			// set timer 
			time_t now;
			time(&now);
			//printf("-----------------------sendBuf_timer----------------\n");
	       // printf("now is %d, interval is %d,sentTime is %d\n", (int)now,(int)now - tcb_table[sockfd]->sendBufHead->sentTime,tcb_table[sockfd]->sendBufHead->sentTime);
	        pthread_mutex_lock(tcb_table[sockfd]->bufMutex);
   	        if (((int)now - tcb_table[sockfd]->sendBufHead->sentTime) >= 1) {
		       printf("Timeout and resend data\n");
		       segBuf_t *q = tcb_table[sockfd]->sendBufHead;
		       for (;q != tcb_table[sockfd]->sendBufunSent; q = q->next) {
				   //printf("Client send data to server(seq_num is %d)\n", q->seg.header.seq_num);
			       sip_sendseg(connection, &q->seg);
			     //  q->sentTime = clock();
				   }
	         }
            pthread_mutex_unlock(tcb_table[sockfd]->bufMutex);
			usleep(SENDBUF_POLLING_INTERVAL/1000000);
		}
		else {
			break;
		}
	}
	//printf("-------------------------timer exit(1)-------------------\n");
  	pthread_exit(NULL);
}
Exemplo n.º 8
0
// 这个线程持续轮询发送缓冲区以触发超时事件. 如果发送缓冲区非空, 它应一直运行.
// 如果(当前时间 - 第一个已发送但未被确认段的发送时间) > DATA_TIMEOUT, 就发生一次超时事件.
// 当超时事件发生时, 重新发送所有已发送但未被确认段. 当发送缓冲区为空时, 这个线程将终止.
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
void* sendBuf_timer(void* clienttcb)
{
	client_tcb_t *tmp = (client_tcb_t *)clienttcb;
	printf("sendBuf_timer start running \n");
//	while(tmp->state == CONNECTED){
	while(1){
		usleep(SENDBUF_POLLING_INTERVAL/1000);
		pthread_mutex_lock(tmp->bufMutex);
		if(tmp->sendBufHead == NULL){
			printf("sendBuf_timer exit\n");
			pthread_mutex_unlock(tmp->bufMutex);
			pthread_exit(NULL);
		}
		else if(time(NULL) - tmp->sendBufHead->sentTime > DATA_TIMEOUT) {
//			printf("last sent time %ld\n", tmp->sendBufHead->sentTime);
			segBuf_t *p = tmp->sendBufHead;
			int un_ack = tmp->unAck_segNum;
//			printf("sendBuf_timer unack %d \n", un_ack);
			while(p != tmp->sendBufunSent){
				p->sentTime = time(NULL);
				printf("RE SEND SEG%d----------\n", p->seg.header.seq_num);
				sip_sendseg(sipfd, &(p->seg));
				p = p->next;
			}
		}
		pthread_mutex_unlock(tmp->bufMutex);
	}
	pthread_exit(NULL);
}
Exemplo n.º 9
0
void sendAck(seg_t *recv, seg_t* send, server_tcb_t* recv_tcb,int ackType) {
	printf("Sending Ack to port: %d, type = %d\n", recv_tcb->client_portNum, ackType);
	memset(send, 0, sizeof(seg_t));
	send->header.type = ackType;
	send->header.dest_port = recv_tcb->client_portNum;
	send->header.src_port = recv_tcb->server_portNum;
	send->header.ack_num = recv_tcb->expect_seqNum;
	send->header.checksum = checksum(send);
	sip_sendseg(global_conn, send);
}
Exemplo n.º 10
0
int stcp_client_disconnect(int sockfd) {
	int resend_fin_times = 0;
	seg_t *segPtr2;
	segPtr2 = (seg_t *)malloc(sizeof(seg_t));
	segPtr2->header.src_port = tcb_table[sockfd]->client_portNum;
	segPtr2->header.dest_port = tcb_table[sockfd]->server_portNum;
	segPtr2->header.seq_num = 0;
	segPtr2->header.ack_num = 0;
	segPtr2->header.length = sizeof(seg_t);//???
	segPtr2->header.type = FIN;
	segPtr2->header.rcv_win = 0;
	segPtr2->header.checksum = 0;
	sip_sendseg(connection, segPtr2);
	printf("Client(FINWAIT): send a FIN segment data(src_port: %d, dest_port: %d)\n",segPtr2->header.src_port,segPtr2->header.dest_port);
	tcb_table[sockfd]->state = FINWAIT;
	// set timer and check state
	while (resend_fin_times < FIN_MAX_RETRY) {
		usleep(FIN_TIMEOUT/1000);
		if (tcb_table[sockfd]->state == CLOSED) {
			return 1;
		}
		sip_sendseg(connection, segPtr2);
		printf("Client(FINWAIT): Resend a FIN segment data(src_port: %d, dest_port: %d)\n",
		segPtr2->header.src_port,segPtr2->header.dest_port);
		resend_fin_times ++;
	}
	tcb_table[sockfd]->state = CLOSED;
	printf("Client(CLOSED): cann't receive FINACK after send FIN(src_port: %d, dest_port: %d)\n",
	segPtr2->header.src_port,segPtr2->header.dest_port);
	// 清空发送缓冲区
	pthread_mutex_lock(tcb_table[sockfd]->bufMutex);
	segBuf_t *p = tcb_table[sockfd]->sendBufHead;
	while (p != NULL) {
		segBuf_t *q = p;
		p = p->next;
		free(q);
	}
	tcb_table[sockfd]->sendBufHead = NULL;
	tcb_table[sockfd]->sendBufunSent = NULL;
	tcb_table[sockfd]->sendBufTail = NULL;
	pthread_mutex_unlock(tcb_table[sockfd]->bufMutex);
	return -1;
}
Exemplo n.º 11
0
// 这个函数用于断开到服务器的连接. 它以套接字ID作为输入参数. 套接字ID用于找到TCB表中的条目.  
// 这个函数发送FIN段给服务器. 在发送FIN之后, state将转换到FINWAIT, 并启动一个定时器.
// 如果在最终超时之前state转换到CLOSED, 则表明FINACK已被成功接收. 否则, 如果在经过FIN_MAX_RETRY次尝试之后,
// state仍然为FINWAIT, state将转换到CLOSED, 并返回-1.
int stcp_client_disconnect(int sockfd) 
{
	client_tcb_t *dscnn_tcb=client_tcb_table[sockfd];
	if(dscnn_tcb==NULL) return -1;
	int flag = 1;
	while(flag) {
		pthread_mutex_lock(dscnn_tcb->bufMutex);
		if(dscnn_tcb->sendBufHead == NULL) {
			flag = 0;
		}
		pthread_mutex_unlock(dscnn_tcb->bufMutex);
		sleep(CLOSEWAIT_TIMEOUT);
	}
	seg_t *seg=malloc(sizeof(seg_t));
	seg->header.src_port=dscnn_tcb->client_portNum;
	seg->header.dest_port=dscnn_tcb->server_portNum;
	seg->header.seq_num=dscnn_tcb->next_seqNum;
	seg->header.ack_num=0;
	seg->header.length = 0;
	seg->header.type=FIN;
	seg->header.rcv_win=0;
	seg->header.checksum = 0;
	memset(seg->data, 0, MAX_SEG_LEN);
	seg->header.checksum=checksum(seg);
	int i=0;
	int retry=0;
	dscnn_tcb->state=FINWAIT;
	while(retry<FIN_MAX_RETRY)
	{
		retry++;
		i=sip_sendseg(sip_conn, dscnn_tcb->server_nodeID,seg);
		struct timeval start, end;
		gettimeofday(&start,0);
		if(i<0)  continue;
		while(1)
		{
			gettimeofday(&end,0);
			double timeuse  = 1000000*(end.tv_sec - start.tv_sec) + end.tv_usec - start.tv_usec;
			if(timeuse>FIN_TIMEOUT/1000)
			{
				printf("FIN time out\n");
				break;	//time out
			}
			if(dscnn_tcb->state==CLOSED) //closed
			{
				printf("disconnection has done\n");
				return 1;
			}
		}
	}
	perror("error: disconnection\n");
	dscnn_tcb->state=CLOSED;
	return -1;
}
Exemplo n.º 12
0
// 这个函数用于连接服务器. 它以套接字ID, 服务器节点ID和服务器的端口号作为输入参数. 套接字ID用于找到TCB条目.  
// 这个函数设置TCB的服务器节点ID和服务器端口号,  然后使用sip_sendseg()发送一个SYN段给服务器.  
// 在发送了SYN段之后, 一个定时器被启动. 如果在SYNSEG_TIMEOUT时间之内没有收到SYNACK, SYN 段将被重传. 
// 如果收到了, 就返回1. 否则, 如果重传SYN的次数大于SYN_MAX_RETRY, 就将state转换到CLOSED, 并返回-1.
int stcp_client_connect(int sockfd, int nodeID, unsigned int server_port) 
{
	client_tcb_t* cnn_tcb=client_tcb_table[sockfd];
	if(cnn_tcb == NULL){
		perror("Error get the tcb!\n");
		//return -1;
	}
	cnn_tcb->server_portNum=server_port;
	cnn_tcb->server_nodeID=nodeID;
	
	seg_t *seg=malloc(sizeof(seg_t));
	seg->header.src_port=cnn_tcb->client_portNum;
	seg->header.dest_port=cnn_tcb->server_portNum;
	seg->header.seq_num=cnn_tcb->next_seqNum;
	seg->header.ack_num=0;
	seg->header.length = 0;
	seg->header.type=SYN;
	seg->header.rcv_win=0;
	seg->header.checksum = 0;
	memset(seg->data, 0, MAX_SEG_LEN);
	seg->header.checksum = checksum(seg);
	printf("send SYN to server_port:%d\n", server_port);
	
	int i=0;
	int retry=0;
	while(retry<SYN_MAX_RETRY)
	{
		cnn_tcb->state=SYNSENT;
		retry++;
		i=sip_sendseg(sip_conn,nodeID,seg);
		//clock函数进行秒级计时,用timeval结构体进行微秒的计时
		struct timeval start, end;
		gettimeofday(&start,0);
		if(i<0)
			continue; //send error!
		while(1)
		{
			gettimeofday(&end,0);
			double timeuse  = 1000000*(end.tv_sec - start.tv_sec) + end.tv_usec - start.tv_usec;
			if(timeuse>SYN_TIMEOUT/1000) {
				printf("SYN time out\n");
				break;	//time out
			}
			if(cnn_tcb->state==CONNECTED)	//connect 
			{
				printf("connection has established \n");
				return 1;
			}
		}
	}
	cnn_tcb->state=CLOSED;
	printf("error: connection has not established  \n");
	return -1;
}
Exemplo n.º 13
0
int stcp_client_connect(int sockfd, unsigned int server_port) {

	seg_t sendbuffer;
	tcb[sockfd]->server_portNum = server_port;

	sendbuffer.header.src_port = tcb[sockfd]->client_portNum;
	sendbuffer.header.dest_port = server_port;
	sendbuffer.header.type = 0;
	sendbuffer.header.length = 0;

	sip_sendseg(tcp_conn,&sendbuffer);
	tcb[sockfd]->state = SYNSENT;

	printf("send syn successful\n");

	int count = 1;
	while (1)
	{
		usleep(100000);
		
		if (tcb[sockfd]->state == CONNECTED)
			return 1;
		if (count<SYN_MAX_RETRY)
		{
			sip_sendseg(tcp_conn,&sendbuffer);
			printf("send syn again\n");
			count++;
		}
		else
		{
			tcb[sockfd]->state = CLOSED;
			printf("send syn over max\n");
			return -1;
		}
		
	}

  return 0;
}
Exemplo n.º 14
0
int stcp_client_disconnect(int sockfd) {

	seg_t sendbuffer;

	sendbuffer.header.src_port = tcb[sockfd]->client_portNum;
	sendbuffer.header.dest_port = tcb[sockfd]->server_portNum;
	sendbuffer.header.type = 2;
	sendbuffer.header.length = 0;

	sip_sendseg(tcp_conn,&sendbuffer);
	printf("send fin successful\n");
	tcb[sockfd]->state = FINWAIT;
	
	int count = 1;
	while (1)
	{
		usleep(100000);
		
		if (tcb[sockfd]->state == CLOSED)
			return 1;
		if (count<FIN_MAX_RETRY)
		{
			sip_sendseg(tcp_conn,&sendbuffer);
			printf("send fin again\n");
			count++;
		}
		else
		{
			tcb[sockfd]->state = CLOSED;
			printf("send fin over max\n");
			return -1;
		}
		
	}
	

  return 0;
}
Exemplo n.º 15
0
// 这个函数用于连接服务器. 它以套接字ID和服务器的端口号作为输入参数. 套接字ID用于找到TCB条目.  
// 这个函数设置TCB的服务器端口号,  然后使用sip_sendseg()发送一个SYN段给服务器.  
// 在发送了SYN段之后, 一个定时器被启动. 如果在SYNSEG_TIMEOUT时间之内没有收到SYNACK, SYN 段将被重传. 
// 如果收到了, 就返回1. 否则, 如果重传SYN的次数大于SYN_MAX_RETRY, 就将state转换到CLOSED, 并返回-1.
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
int stcp_client_connect(int sockfd, unsigned int server_port)
{
	printf("----------------stcp client connect start!----------------\n");
  	int tryno;
  	tryno = 0;
  	client_tcb[sockfd]->server_portNum = server_port;
	client_tcb[sockfd]->state = SYNSENT;
	
	seg_t *seg = (seg_t*)malloc(sizeof(seg_t));

	seg->header.src_port = client_tcb[sockfd]->client_portNum;        //源端口号
	seg->header.dest_port = server_port;       //目的端口号
	seg->header.seq_num = client_tcb[sockfd]->next_seqNum;         //序号
	seg->header.ack_num = 0;         //确认号
	seg->header.length = 0;    //段数据长度
	seg->header.type = SYN;     //段类型
	seg->header.rcv_win = 0;  //当前未使用
	seg->header.checksum = 0;
	seg->header.checksum = checksum(seg);  //这个段的校验和
	client_tcb[sockfd]->next_seqNum++;
  	sip_sendseg(gSockFd, seg);
	usleep(100000);
  	while (client_tcb[sockfd]->state != CONNECTED) {
		printf("the time to connect to the stcp server is out, start resend!\n");
		sip_sendseg(gSockFd, seg);
		if (tryno > SYN_MAX_RETRY) {
			printf("the resend time is over SYN_MAX_RETRY, the state turn to CLOSED and return -1!\n");
			client_tcb[sockfd]->state = CLOSED;
			return -1;
		}
		tryno++;
		usleep(100000);
  	}
	printf("connect to the stcp server on %dth socket succesfully! and the state now is: %d\n", sockfd, client_tcb[sockfd]->state);
  	return 1;
}
Exemplo n.º 16
0
// 这个函数用于断开到服务器的连接. 它以套接字ID作为输入参数. 套接字ID用于找到TCB表中的条目.  
// 这个函数发送FIN段给服务器. 在发送FIN之后, state将转换到FINWAIT, 并启动一个定时器.
// 如果在最终超时之前state转换到CLOSED, 则表明FINACK已被成功接收. 否则, 如果在经过FIN_MAX_RETRY次尝试之后,
// state仍然为FINWAIT, state将转换到CLOSED, 并返回-1.
int stcp_client_disconnect(int sockfd) 
{
	if (sockfd < 0 || sockfd >= MAX_TRANSPORT_CONNECTIONS)
		return -1;
	client_tcb_t *tcb = client_tcb_table[sockfd];
	if (tcb == NULL) 
		return -1;
	if (tcb -> state != CONNECTED)
		return -1;
	tcb -> state = FINWAIT;

	seg_t send_segment;
	build_segment_head(&send_segment, tcb -> client_portNum, tcb -> server_portNum, 0, FIN);
	
	int send_num = 0;
	while (true) { 

		//send FIN to server
		sip_sendseg(sip_conn, tcb -> server_nodeID, &send_segment);
		
		//wait FIN_TIMEOUT nano seconds
		usleep(FIN_TIMEOUT / 1000);

		if (tcb -> state == CLOSED){
			
			//clear buf
			if(tcb -> sendBufHead != NULL){
				segBuf_t* p = tcb -> sendBufHead;
				while(p != NULL){
					tcb -> sendBufHead = p -> next;
					free(p);
					p = tcb -> sendBufHead;
				}
				tcb -> sendBufunSent = tcb -> sendBufTail = NULL;
			}

			return 1;
		}
		
		//timeout
		send_num ++;
		if (send_num > FIN_MAX_RETRY) {
			tcb -> state = CLOSED;
			return -1;
		}
	}
}
Exemplo n.º 17
0
void* sendThread(void* clienttcb){
	client_tcb_t* tmp = (client_tcb_t*)clienttcb;
	//发送到GBN_WINDOW为止
	while(1){
		if(tmp->unAck_segNum <= GBN_WINDOW && tmp->sendBufunSend != NULL)
		{
			pthread_mutex_lock( ((client_tcb_t*)clienttcb)->send_bufMutex );
			tmp->sendBufunSend->sendTime = getCurrentTime1();
			sip_sendseg(sip_conn, tmp->server_nodeID,&tmp->sendBufunSend->seg);
			tmp->sendBufunSend = tmp->sendBufunSend->next;
			tmp->unAck_segNum++;
			pthread_mutex_unlock( ((client_tcb_t*)clienttcb)->send_bufMutex );
		}
		else if(tmp->sendBufunSend == NULL && tmp->sendBufHead==NULL) break;
	}
	return ;
}
Exemplo n.º 18
0
void sendACK(int index, unsigned int client_port, int dest_nodeID, int type, seg_t* seg) {
	printf("the type stcp server sends is %d\n", type);

	seg->header.src_port = server_tcb[index]->server_portNum;        //源端口号
	seg->header.dest_port = client_port;       //目的端口号
	seg->header.seq_num = 0;         //序号
	seg->header.ack_num = server_tcb[index]->expect_seqNum;         //确认号
	seg->header.length = 0;    //段数据长度
	seg->header.type = type;     //段类型
	seg->header.rcv_win = 0;  //当前未使用
	seg->header.checksum = 0;
	seg->header.checksum = checksum(seg);  //这个段的校验和

	server_tcb[index]->expect_seqNum++;
	sip_sendseg(sip_conn, dest_nodeID, seg);
	printf("stcp server send the %d ACK succesfully!\n", type);
}
Exemplo n.º 19
0
//这个线程持续轮询发送缓冲区以触发超时事件. 如果发送缓冲区非空, 它应一直运行.
//如果(当前时间 - 第一个已发送但未被确认段的发送时间) > DATA_TIMEOUT, 就发生一次超时事件.
//当超时事件发生时, 重新发送所有已发送但未被确认段. 当发送缓冲区为空时, 这个线程将终止.
void* sendBuf_timer(void* clienttcb) 
{

	pthread_detach(pthread_self());	//modify

	client_tcb_t* tcb = (client_tcb_t*)clienttcb;

	while(true){

		usleep(SENDBUF_POLLING_INTERVAL / 1000);

		if(tcb -> sendBufHead == NULL)	//send buf empty
			return NULL;
		
		int sentTime = tcb -> sendBufHead -> sentTime;
		int currTime = get_time();

		if((currTime - sentTime) * 100000 > DATA_TIMEOUT){

			//printf("data segment timeout, seq %d\n", (tcb -> sendBufHead -> seg).header.seq_num);
			
			pthread_mutex_lock(tcb -> bufMutex);
			segBuf_t* resent_segBuf = tcb -> sendBufHead;
			int unAck_segNum = tcb -> unAck_segNum;
			int i;
			for ( i = 0; i < unAck_segNum; ++i){
				
				assert(resent_segBuf != NULL);
				sip_sendseg(sip_conn, tcb -> server_nodeID, &(resent_segBuf -> seg));
				//printf("resend the data segment, seq %d\n", (resent_segBuf -> seg). header.seq_num);

				resent_segBuf -> sentTime = get_time();
				resent_segBuf = resent_segBuf -> next;
				
			}

			assert(resent_segBuf == tcb -> sendBufunSent);
			
			pthread_mutex_unlock(tcb -> bufMutex);

			
		}
	}
	return NULL;
}
Exemplo n.º 20
0
int stcp_client_disconnect(int sockfd) {
	client_tcb_t * dscnn_tcb=client_tcb_table[sockfd];
	if(dscnn_tcb==NULL)return -1;
	seg_t *seg=malloc(sizeof(seg_t));
	seg->header.src_port=dscnn_tcb->client_portNum;
	seg->header.dest_port=dscnn_tcb->server_portNum;
	seg->header.seq_num=dscnn_tcb->next_seqNum;
	seg->header.ack_num=0;
	seg->header.length = 0;
	dscnn_tcb->next_seqNum=(dscnn_tcb->next_seqNum+1)%MAX_SEG_LEN;
	seg->header.type=FIN;
	//memset(seg->data, 0, MAX_SEG_LEN);
	int i=0;
	int retry=0;
	dscnn_tcb->state=FINWAIT;
	while(retry<FIN_MAX_RETRY)
	{
		retry++;
		i=sip_sendseg(connection,seg);
		struct timeval start, end;
		gettimeofday(&start,0);
		if(i<0)  continue;
		while(1)
		{
			gettimeofday(&end,0);
			double timeuse  = 1000000*(end.tv_sec - start.tv_sec) + end.tv_usec - start.tv_usec;
			if(timeuse>FIN_TIMEOUT/1000)
			{
				printf("FIN time out\n");
				break;	//time out
			}
			if(dscnn_tcb->state==CLOSED) //closed
			{
				printf("disconnection has done\n");
				return 1;
			}
		}
	}
	printf("error: disconnection\n");
	dscnn_tcb->state=CLOSED;
	return -1;
 
}
Exemplo n.º 21
0
// 这个线程持续轮询发送缓冲区以触发超时事件. 如果发送缓冲区非空, 它应一直运行.
// 如果(当前时间 - 第一个已发送但未被确认段的发送时间) > DATA_TIMEOUT, 就发生一次超时事件.
// 当超时事件发生时, 重新发送所有已发送但未被确认段. 当发送缓冲区为空时, 这个线程将终止.
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
void* sendBuf_timer(void* clienttcb)
{
	long time;
	client_tcb_t *client_tcb = (client_tcb_t *)clienttcb;
	while (client_tcb->sendBufHead != NULL) {
		pthread_mutex_lock(client_tcb->bufMutex);
		time = getCurrentTime() - client_tcb->sendBufHead->sentTime;
		if (time * 1000000 > DATA_TIMEOUT) {
			printf("the sendBuf_timer thread resend the seg which is already sent!\n");
			segBuf_t *p = client_tcb->sendBufHead;
			while (p != NULL && p != client_tcb->sendBufunSent) {
				p->sentTime = getCurrentTime();
				sip_sendseg(gSockFd, &(p->seg));
				p = p->next;
			}
		}
		pthread_mutex_unlock(client_tcb->bufMutex);
		usleep(100000);//睡0.1秒,即100000微秒
	}
	printf("The sendBuf_timer thread is over!\n");
	return;
}
Exemplo n.º 22
0
// 连接STCP服务器
//
// 这个函数用于连接服务器. 它以套接字ID和服务器的端口号作为输入参数. 套接字ID用于找到TCB条目.  
// 这个函数设置TCB的服务器端口号,  然后使用sip_sendseg()发送一个SYN段给服务器.  
// 在发送了SYN段之后, 一个定时器被启动. 如果在SYNSEG_TIMEOUT时间之内没有收到SYNACK, SYN 段将被重传. 
// 如果收到了, 就返回1. 否则, 如果重传SYN的次数大于SYN_MAX_RETRY, 就将state转换到CLOSED, 并返回-1.
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
int stcp_client_connect(int sockfd, unsigned int server_port) {
	client_tcb_t* t=TCBTable[sockfd];
	if(t==NULL)return -1;
	t->server_portNum=server_port;
	seg_t *seg=malloc(sizeof(seg_t));
	seg->header.src_port=t->client_portNum;
	seg->header.dest_port=t->server_portNum;
	seg->header.seq_num=t->next_seqNum;
	seg->header.ack_num=0;
	t->next_seqNum=(t->next_seqNum+1)%MAX_SEQNUM;
	seg->header.type=SYN;
	int i=0;
	int flag=0;
	while(flag<SYN_MAX_RETRY)
	{
		t->state=SYNSENT;
		flag++;
		i=sip_sendseg(son_conn,seg);
		double start=clock();
		if(i<0)continue;
		while(1)
		{
			double now=clock();
			if(now-start>SYN_TIMEOUT/1000){
				printf("SYN time out\n");
				break;	//time out resend
			}
			if(t->state==CONNECTED)	//connect 
			{
				printf("connct successfully\n");
				return 1;
			}
		}
	}
	t->state=CLOSED;
	printf("cannot connect to the server\n");
	return -1;
}
Exemplo n.º 23
0
int stcp_client_disconnect(int sockfd) {
	client_tcb_t * t=TCBTable[sockfd];
	if(t==NULL)return -1;
	seg_t *seg=malloc(sizeof(seg_t));
	seg->header.src_port=t->client_portNum;
	seg->header.dest_port=t->server_portNum;
	seg->header.seq_num=t->next_seqNum;
	seg->header.ack_num=0;
	t->next_seqNum=(t->next_seqNum+1)%MAX_SEQNUM;
	seg->header.type=FIN;
	int i=0;
	int flag=0;
	while(flag<FIN_MAX_RETRY)
	{
		t->state=FINWAIT;
		flag++;
		i=sip_sendseg(son_conn,seg);
		double start=clock();
		if(i<0)continue;
		while(1)
		{
			double now=clock();
			if(now-start>CLOSEWAIT_TIMEOUT/1000)
			{
				printf("FIN time out\n");
				break;	//time out resend
			}
			if(t->state==CLOSED)	//closed
			{
				printf("disconnect successfully\n");
				return 1;
			}
		}
	}
	printf("disconnect unsuccessfully\n");
	t->state=CLOSED;
	return -1;
}
Exemplo n.º 24
0
//这个线程持续轮询发送缓冲区以触发超时事件. 如果发送缓冲区非空, 它应一直运行.
//如果(当前时间 - 第一个已发送但未被确认段的发送时间) > DATA_TIMEOUT, 就发生一次超时事件.
//当超时事件发生时, 重新发送所有已发送但未被确认段. 当发送缓冲区为空时, 这个线程将终止.
void* sendBuf_timer(void* clienttcb) 
{
	client_tcb_t *tcb = (client_tcb_t *)clienttcb;
	if(tcb == NULL) {
		return NULL;
	}
	//int tu = 0;
    while(1)
    {	
		//printf("\n------check time out segs at %d!!!------\n", ++tu);
		pthread_mutex_lock(tcb->bufMutex);
        if(tcb->sendBufHead == NULL) {
			pthread_mutex_unlock(tcb->bufMutex);
			continue;
		}
        if(tcb->sendBufunSent == tcb->sendBufHead) {
			pthread_mutex_unlock(tcb->bufMutex);
			continue;
		}
		struct timeval now;
        gettimeofday(&now, 0);
		if(((now.tv_usec - tcb->sendBufHead->sentTime_usec)+(now.tv_sec-tcb->sendBufHead->sentTime_sec)*1000000) > DATA_TIMEOUT/1000) {
			printf("Time out and resend\n");
			segBuf_t* bufHead = tcb->sendBufHead;
			while(bufHead != tcb->sendBufunSent && bufHead!= NULL) {
				printf("Resend data to server port:%d, seq:%d\n", bufHead->seg.header.dest_port, bufHead->seg.header.seq_num);
				sip_sendseg(sip_conn, tcb->server_nodeID, &(bufHead->seg));
				struct timeval sentTime;
                gettimeofday(&sentTime, 0);
                bufHead->sentTime_usec = sentTime.tv_usec;
                bufHead->sentTime_sec = sentTime.tv_sec;
				bufHead = bufHead->next;
			}
		}
		pthread_mutex_unlock(tcb->bufMutex);
        usleep(SENDBUF_POLLING_INTERVAL/1000);
	}
}
Exemplo n.º 25
0
// 这个函数用于连接服务器. 它以套接字ID, 服务器节点ID和服务器的端口号作为输入参数. 套接字ID用于找到TCB条目.  
// 这个函数设置TCB的服务器节点ID和服务器端口号,  然后使用sip_sendseg()发送一个SYN段给服务器.  
// 在发送了SYN段之后, 一个定时器被启动. 如果在SYNSEG_TIMEOUT时间之内没有收到SYNACK, SYN 段将被重传. 
// 如果收到了, 就返回1. 否则, 如果重传SYN的次数大于SYN_MAX_RETRY, 就将state转换到CLOSED, 并返回-1.
int stcp_client_connect(int sockfd, int nodeID, unsigned int server_port) 
{
	if (sockfd < 0 || sockfd >= MAX_TRANSPORT_CONNECTIONS)
		return -1;
	client_tcb_t *tcb = client_tcb_table[sockfd];
	if (tcb == NULL)
		return -1;
	if (tcb -> state != CLOSED)
		return -1;
	tcb -> state = SYNSENT;
	tcb -> server_nodeID = nodeID;
	tcb -> server_portNum = server_port;
	//set send segment.
	seg_t send_segment;
	memset(&send_segment, 0, sizeof(seg_t));
	build_segment_head(&send_segment, tcb -> client_portNum, server_port, 0, SYN);

	int send_num = 0;
	while (true) {

		//send SYN to server
		sip_sendseg(sip_conn, nodeID, &send_segment);
		
		//wait SYN_TIMEOUT nano seconds
		usleep(SYN_TIMEOUT / 1000);

		if (tcb -> state == CONNECTED)
			return 1;

		//timeout
		send_num ++;
		if (send_num > SYN_MAX_RETRY) {
			tcb -> state = CLOSED;
			return -1;
		}
	}
}
Exemplo n.º 26
0
void *seghandler(void* arg) {
	seg_t tmp;
	int src_node;
	while (1){
		int k = sip_recvseg(sip_connfd, &src_node, &tmp);
		print_pos();
		printf("sip_recvseg = %d\n", k);
		if( k == -1) {
//			usleep(100000);
			printf("\t\t\tWARNING: I lost a package\n");
		}
		else if (k == 2){
			sleep(1);
//			printf("unknown error\n");
		}
		else {
			switch(tmp.header.type){
				case SYN: printf("\t\t\t\tRECV SYN, client:%d server:%d\n", tmp.header.src_port, tmp.header.dest_port); break;
				case FIN: printf("\t\t\t\tRECV FIN, client:%d server:%d\n", tmp.header.src_port, tmp.header.dest_port); break;
				case DATA: printf("\t\t\t\tRECV DATA, client:%d server:%d\n", tmp.header.src_port, tmp.header.dest_port); break;
				default: break;
			}

			int i = 0, k = -1;
			for (i = 0; i < MAX_TRANSPORT_CONNECTIONS; i++) {
				if (tcb[i] != NULL) {
					if (tcb[i]->server_portNum == tmp.header.dest_port) {
						// 3种正常情况
						if (tmp.header.type == SYN && tcb[i]->state == LISTENING){
							printf("\tGOOD MSG: package right case 1: recv SYN\n");
							k = i;
							break;
						}
						if (tmp.header.type == DATA && tcb[i]->state == CONNECTED && tmp.header.src_port == tcb[i]->client_portNum){
							printf("\tGOOD MSG: package right case 2: recv DATA\n");
							k = i;
							break;
						}
						if (tmp.header.type == FIN && tcb[i]->state == CONNECTED && tmp.header.src_port == tcb[i]->client_portNum){
							printf("\tGOOD MSG: package right case 3: recv FIN\n");
							k = i;
							break;
						}
						// 错误情况2种
						if (tmp.header.type == SYN && tcb[i]->state == CONNECTED && tcb[i]->client_portNum == tmp.header.src_port){
							printf("PACKAGE ERROR: error case 1: recv SYN when CONNECTED\n");
							printf("\tERROR MSG: socket:%d client:%d server:%d\n", i, tcb[i]->client_portNum, tcb[i]->server_portNum);
							k = i;
							break;
						}
						if (tmp.header.type == FIN && tcb[i]->state == CLOSEWAIT && tcb[i]->client_portNum == tmp.header.src_port){
							printf("PACKAGE ERROR: error case 2: recv FIN when CLOSEWAIT\n");
							printf("\tERROR MSG: socket:%d client:%d server:%d\n", i, tcb[i]->client_portNum, tcb[i]->server_portNum);
							k = i;
							break;
						}
					}
				}
				else continue;
			}
			if (k == -1) {
				printf("PACKAGE ERROR: no such connect 4 package\n");
				printf("\tERROR MSG: package client:%d server:%d\n", tmp.header.src_port, tmp.header.dest_port);
			}
			else {
				switch(tcb[k]->state){
					case CLOSED: break;
					case LISTENING: 
						     if (tmp.header.type == SYN) {
							     tcb[k]->state = CONNECTED;
							     tcb[k]->client_portNum = tmp.header.src_port;

							     seg_t ack;
							     ack.header.src_port = tmp.header.dest_port;
							     ack.header.dest_port = tmp.header.src_port;
							     ack.header.seq_num = tcb[k]->expect_seqNum;
							     ack.header.ack_num = tmp.header.ack_num;
							     ack.header.length = 0;
							     ack.header.type = SYNACK;
							     ack.header.rcv_win = 0;
							     ack.header.checksum = 0;
							     memset(ack.data, 0, MAX_SEG_LEN);
							     ack.header.checksum = checksum(&ack);

							     printf("\tGOOD MSG: send SYNACK port:%d -> port:%d, src_node=%d\n", ack.header.dest_port, ack.header.src_port, src_node);
							     if (sip_sendseg(sip_connfd, src_node, &ack)) printf("\tGOOD MSG: send SYNACK ok\n");
							     else printf("SEND ERROR: send SYNACK failed\n");
						     }
						     break;
					case CONNECTED:
						     if (tmp.header.type == FIN){
							     tcb[k]->state = CLOSEWAIT;
							     tcb[k]->wait_start = clock();
							     seg_t ack;
							     ack.header.src_port = tmp.header.dest_port;
							     ack.header.dest_port = tmp.header.src_port;
							     ack.header.seq_num = tcb[k]->expect_seqNum;
							     ack.header.ack_num = tmp.header.ack_num;
							     ack.header.length = 0;
							     ack.header.type = FINACK;
							     ack.header.rcv_win = 0;
							     ack.header.checksum = 0;
							     memset(ack.data, 0, MAX_SEG_LEN);
							     ack.header.checksum = checksum(&ack);

							     printf("\tGOOD MSG: send SYNACK port:%d -> port:%d, src_node=%d\n", ack.header.dest_port, ack.header.src_port, src_node);
							     if (sip_sendseg(sip_connfd, src_node, &ack)) printf("\tGOOD MSG: send FINACK ok\n");
							     else printf("SEND ERROR: send FINACK failed\n");
						     }
						     else if (tmp.header.type == DATA){
							     int ackNum = -1;
							     if (tcb[k]->expect_seqNum == tmp.header.seq_num){	//是我想收的序号
								    if (tcb[k]->usedBufLen+tmp.header.length < RECEIVE_BUF_SIZE){//缓冲区未满
									    // printf("MSG: RECV data \'%s\'\n", tmp.data);
									     pthread_mutex_lock(tcb[k]->bufMutex);
									     memcpy(tcb[k]->recvBuf+tcb[k]->usedBufLen, tmp.data, tmp.header.length);
									     tcb[k]->expect_seqNum = tcb[k]->expect_seqNum+tmp.header.length;
									     tcb[k]->usedBufLen += tmp.header.length;
									     pthread_mutex_unlock(tcb[k]->bufMutex);

									     ackNum = tcb[k]->expect_seqNum;
								     }
							     }
							     seg_t ack;
							     ack.header.src_port = tmp.header.dest_port;
							     ack.header.dest_port = tmp.header.src_port;
							     ack.header.seq_num = tcb[k]->expect_seqNum;
							     ack.header.ack_num = tmp.header.seq_num;

							     ack.header.length = 0;
							     ack.header.type = DATAACK;
							     ack.header.rcv_win = 0;
							     ack.header.checksum = 0;
							     memset(ack.data, 0, MAX_SEG_LEN);
							     ack.header.checksum = checksum(&ack);
							     printf("MSG: recv seq_num %d, send ack_num %d\n", tmp.header.seq_num, ack.header.ack_num);
							     printf("MSG: RECV data length %d\n", tmp.header.length);
							     if (ackNum == -1) printf("DATA ERROR: expect %d, but recv %d\n", tcb[k]->expect_seqNum, tmp.header.seq_num);
							     else printf("\tGOOD MSG: recv data right seq:%d\n", tmp.header.seq_num);
							     printf("\tGOOD MSG: send DATAACK 4 client:%d -> server:%d\n", ack.header.dest_port, ack.header.src_port);
							     if (sip_sendseg(sip_connfd, src_node, &ack)) printf("\tGOOD MSG: send DATAACK ok\n");
							     else printf("SEND ERROR: send DATAACK failed\n");

						     }
						     else if (tmp.header.type == SYN){
							     seg_t ack;
							     ack.header.src_port = tmp.header.dest_port;
							     ack.header.dest_port = tmp.header.src_port;
							     ack.header.seq_num = tcb[k]->expect_seqNum;
							     ack.header.ack_num = tmp.header.ack_num;
							     ack.header.length = 0;
							     ack.header.type = SYNACK;
							     ack.header.rcv_win = 0;
							     ack.header.checksum = 0;
							     memset(ack.data, 0, MAX_SEG_LEN);
							     ack.header.checksum = checksum(&ack);

							     printf("SEND ERROR: SYNACK lost\n"); 
							     printf("\tGOOD MSG: send SYNACK 4 client:%d -> server:%d\n", ack.header.dest_port, ack.header.src_port);
							     if (sip_sendseg(sip_connfd, src_node, &ack)) printf("\tGOOD MSG: send SYNACK ok\n");
							     else printf("SEND ERROR: send SYNACK failed\n");
						     }
						     break;
					case CLOSEWAIT: 
						     if (tmp.header.type == FIN){
							     tcb[k]->wait_start = clock();
							     seg_t ack;
							     ack.header.src_port = tmp.header.dest_port;
							     ack.header.dest_port = tmp.header.src_port;
							     ack.header.seq_num = tcb[k]->expect_seqNum;
							     ack.header.ack_num = tmp.header.ack_num;
							     ack.header.length = 0;
							     ack.header.type = FINACK;
							     ack.header.rcv_win = 0;
							     ack.header.checksum = 0;
							     memset(ack.data, 0, MAX_SEG_LEN);
							     ack.header.checksum = checksum(&ack);

							     printf("SEND ERROR: FINACK lost\n"); 
							     printf("\tGOOD MSG: send FINACK 4 client:%d -> server:%d\n", ack.header.dest_port, ack.header.src_port);
							     if (sip_sendseg(sip_connfd, src_node, &ack)) printf("\tGOOD MSG: send FINACK ok\n");
							     else printf("SEND ERROR: send FINACK failed\n");
						     }
						     break;
					default: break;
				}
			}
		}
	}
  return 0;
}
Exemplo n.º 27
0
// 这是由stcp_server_init()启动的线程. 它处理所有来自客户端的进入数据. seghandler被设计为一个调用sip_recvseg()的无穷循环, 
// 如果sip_recvseg()失败, 则说明重叠网络连接已关闭, 线程将终止. 根据STCP段到达时连接所处的状态, 可以采取不同的动作.
// 请查看服务端FSM以了解更多细节.
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
void* seghandler(void* arg)
{
	server_tcb_t *recv_tcb = NULL;
	seg_t *seg = (seg_t *)malloc(sizeof(seg_t));
	seg_t *seg_ack = (seg_t *)malloc(sizeof(seg_t));
	while(1) {
		recv_tcb = NULL;
		memset(seg, 0, sizeof(seg_t));
		memset(seg_ack, 0, sizeof(seg_t));
		int n = sip_recvseg(global_conn, seg);
		if(n == 2) {
			//printf("Seg lost!\n");
			printf("---------------------------------\n");
			continue;
		}
		else if(n == 0) {
			//judge checksum first!
			if(checkchecksum(seg) == -1) {
				printf("Error checksum!\n");
				printf("---------------------------------\n");
				continue;
			}
			//printf("Receive a seg!\n");
			int i = 0;
			int port = seg->header.dest_port;
			for(i=0; i<MAX_TRANSPORT_CONNECTIONS; i++) {
				if(server_tcb_table[i]->server_portNum == port)
					break;
			}
			recv_tcb = server_tcb_table[i];
			if(recv_tcb == NULL || i == MAX_TRANSPORT_CONNECTIONS) {
				perror("Server tcb table error!\n");
				exit(-1);
			}
			switch(recv_tcb->state) {
				case CLOSED: {
					printf("State: CLOSED\n");
					printf("---------------------------------\n");
				} break;
				case LISTENING: {
					printf("State: LISTENING\n");
					printf("---------------------------------\n");
					if(seg->header.type == SYN) { 
						recv_tcb->client_portNum = seg->header.src_port;
						recv_tcb->expect_seqNum = seg->header.seq_num;
						sendAck(seg, seg_ack, recv_tcb, SYNACK);
						recv_tcb->state = CONNECTED;
					}
				} break;
				case CONNECTED: {
					//printf("State: CONNECTED\n");
					//printf("---------------------------------\n");
					if(seg->header.type == SYN) {
						printf("State: CONNECTED -> SYN\n");
						recv_tcb->client_portNum = seg->header.src_port;
						recv_tcb->expect_seqNum = seg->header.seq_num;
						sendAck(seg, seg_ack, recv_tcb, SYNACK);
						recv_tcb->state = CONNECTED;
					}
					else if(seg->header.type == FIN ) {
						printf("State: CONNECTED -> FIN\n");
						if(recv_tcb->expect_seqNum == seg->header.seq_num) {
							sendAck(seg, seg_ack, recv_tcb, FINACK);
							recv_tcb->state = CLOSEWAIT;
						}
						else {
							printf("FIN Seq error!\n");
						}
					}
					else if(seg->header.type == DATA) {
						printf("State: CONNECTED -> DATA\n");
						//judge seq num
						printf("from port: %d to port %d, seq = %d, expected: %d\n", seg->header.src_port, seg->header.dest_port, seg->header.seq_num, recv_tcb->expect_seqNum);
						if(recv_tcb->expect_seqNum == seg->header.seq_num) {
							pthread_mutex_lock(recv_tcb->bufMutex);
							printf("data length: %d\n", seg->header.length);
							memcpy(recv_tcb->recvBuf+recv_tcb->usedBufLen, seg->data, seg->header.length);
							/*
							int i= 0;
							printf("\nin data recv-----------\n");
							for(i = 0; i<seg->header.length; i++) {
								printf("%c", (char *)(recv_tcb->recvBuf)[i]);
							}
							printf("\n-----------\n");
							*/
							/*
							printf("\n-------------\n usedbuflen: %d\n---------------\n",recv_tcb->usedBufLen);
							* */
							recv_tcb->usedBufLen += seg->header.length;
							/*
							printf("\n-------------\n usedbuflen: %d\n----------------\n",recv_tcb->usedBufLen);
							* */
							recv_tcb->expect_seqNum += seg->header.length;
							//recv_tcb->expect_seqNum %= MAX_SEG_LEN;
							//printf("\n+++++++++---------\nrecv_tcb->expect_seqNum = %d\n\n", recv_tcb->expect_seqNum);
							pthread_mutex_unlock(recv_tcb->bufMutex);
							sendAck(seg, seg_ack, recv_tcb, DATAACK);
						}
						else {
							printf("DATA Seq error!\n");
							seg_ack->header.type = DATAACK;
							seg_ack->header.src_port = seg->header.dest_port;
							seg_ack->header.dest_port = seg->header.src_port;
							seg_ack->header.seq_num = 0;
							seg_ack->header.ack_num = recv_tcb->expect_seqNum;
							seg_ack->header.length = 0;
							seg_ack->header.rcv_win=0;
							seg_ack->header.checksum = 0;
							seg_ack->header.checksum = checksum(seg_ack);
							sip_sendseg(global_conn, seg_ack);
						}
					}
				} break;
				case CLOSEWAIT: {
					printf("State: CLOSEWAIT\n");
					printf("---------------------------------\n");
					if(seg->header.type == FIN) {
						sendAck(seg, seg_ack, recv_tcb, FINACK);
						recv_tcb->state = CLOSEWAIT;
					}
				} break;
				default: break;
			}
		}
		else if(n == 1) {
			continue;
		}
	}
	return 0;
}
Exemplo n.º 28
0
// 这是由stcp_client_init()启动的线程. 它处理所有来自服务器的进入段. 
// seghandler被设计为一个调用sip_recvseg()的无穷循环. 如果sip_recvseg()失败, 则说明重叠网络连接已关闭,
// 线程将终止. 根据STCP段到达时连接所处的状态, 可以采取不同的动作. 请查看客户端FSM以了解更多细节.
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
void *seghandler(void* arg)
{
	seg_t recvbuf;
	int i = 0, n;
	while(1){
		if( (n = sip_recvseg(sipfd, &recvbuf)) == 0){
			for(i = 0; i <MAX_TRANSPORT_CONNECTIONS ; i++){
				if(tcb[i] != NULL && tcb[i]->client_portNum == recvbuf.header.dest_port
						&& tcb[i]->server_portNum == recvbuf.header.src_port){
					if(tcb[i]->state == SYNSENT && recvbuf.header.type == SYNACK){
						printf("client port %d receive SYNACK\n",
								tcb[i]->client_portNum);
						tcb[i]->state = CONNECTED;
					}
					//only recv DATAACK when connected
					if(tcb[i]->state == CONNECTED && recvbuf.header.type == DATAACK){
						int ack = recvbuf.header.ack_num;
						printf("client port %d receive DATAACK %d\n",
								tcb[i]->client_portNum, ack);
						pthread_mutex_lock(tcb[i]->bufMutex);
						assert(tcb[i]->sendBufHead != NULL);
						int num = tcb[i]->sendBufHead->seg.header.seq_num;
						printf("unAck_segNum %d \n", tcb[i]->unAck_segNum);
						while(num < ack){
							segBuf_t *tmp = tcb[i]->sendBufHead;
							tcb[i]->sendBufHead = tmp->next;
							printf("delete seg %d \n", tmp->seg.header.seq_num);
							free(tmp);
							tcb[i]->unAck_segNum--;
							printf("unAck_segNum -- %d\n", tcb[i]->unAck_segNum);
							if(tcb[i]->sendBufHead != NULL)
								num = tcb[i]->sendBufHead->seg.header.seq_num;
							else
								break;
						}
						while(tcb[i]->unAck_segNum < GBN_WINDOW && tcb[i]->sendBufunSent != NULL){
							tcb[i]->sendBufunSent->sentTime = time(NULL);
							printf("client send DATA %d \n", tcb[i]->sendBufunSent->seg.header.seq_num);
							sip_sendseg(sipfd, &(tcb[i]->sendBufunSent->seg));
							tcb[i]->sendBufunSent = tcb[i]->sendBufunSent->next;
							tcb[i]->unAck_segNum++;
							printf("unAck_segNum ++ %d\n", tcb[i]->unAck_segNum);
						}
						pthread_mutex_unlock(tcb[i]->bufMutex);
					}

					if(tcb[i]->state == FINWAIT && recvbuf.header.type == FINACK){
						printf("---------client port %d receive FINACK-----------\n",
								tcb[i]->client_portNum);
						tcb[i]->state = CLOSED;
					}
					break;
				}
			}
		}
		else if(n == -1){
//			printf("SON is closed\n");
			pthread_exit(NULL);
		}
	}
	pthread_exit(NULL);
}
Exemplo n.º 29
0
// 发送数据给STCP服务器. 这个函数使用套接字ID找到TCB表中的条目. 
// 然后它使用提供的数据创建segBuf, 将它附加到发送缓冲区链表中. 
// 如果发送缓冲区在插入数据之前为空, 一个名为sendbuf_timer的线程就会启动. 
// 每隔SENDBUF_POLLING_INTERVAL时间查询发送缓冲区以检查是否有超时事件发生.
// 这个函数在成功时返回1,否则返回-1. 
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
int stcp_client_send(int sockfd, void* data, unsigned int length)
{
	pthread_t tid;
	int flag = 0;
	while(tcb[sockfd]->state == CONNECTED){
		pthread_mutex_lock(tcb[sockfd]->bufMutex);
		segBuf_t *sendbuf = malloc(sizeof(segBuf_t));
		memset(sendbuf, 0, sizeof(sendbuf));
		sendbuf->seg.header.src_port = tcb[sockfd]->client_portNum;
		sendbuf->seg.header.dest_port = tcb[sockfd]->server_portNum;
		sendbuf->seg.header.type = DATA;
		sendbuf->seg.header.seq_num = tcb[sockfd]->next_seqNum;
		sendbuf->next = NULL;
		sendbuf->sentTime = time(NULL);
		if(tcb[sockfd]->sendBufHead == NULL){
			tcb[sockfd]->sendBufHead = sendbuf;
			tcb[sockfd]->sendBufunSent = sendbuf;
			tcb[sockfd]->sendBufTail = sendbuf;
			tcb[sockfd]->unAck_segNum = 0;
			pthread_create(&tid, NULL, sendBuf_timer, (void *)tcb[sockfd]);
		}else{
			tcb[sockfd]->sendBufTail->next = sendbuf;
			tcb[sockfd]->sendBufTail = sendbuf;
			//if unSent is null ,then the added is unSent
			if(tcb[sockfd]->sendBufunSent == NULL)
				tcb[sockfd]->sendBufunSent = sendbuf;
		}

		if(length > MAX_SEG_LEN){
			sendbuf->seg.header.length = MAX_SEG_LEN;
			memcpy(&(sendbuf->seg.data), data, MAX_SEG_LEN );

			data += MAX_SEG_LEN;
			length -= MAX_SEG_LEN;
			tcb[sockfd]->next_seqNum += MAX_SEG_LEN;
		}
		else{
			sendbuf->seg.header.length = length;
			memcpy(&(sendbuf->seg.data), data, length );
			tcb[sockfd]->next_seqNum += length;
			flag = 1;
		}


		//send right now or later?
		while(tcb[sockfd]->unAck_segNum < GBN_WINDOW && tcb[sockfd]->sendBufunSent != NULL){
			tcb[sockfd]->sendBufunSent->sentTime = time(NULL);
			printf("client send DATA %d \n", tcb[sockfd]->sendBufunSent->seg.header.seq_num);
			sip_sendseg(sipfd, &(tcb[sockfd]->sendBufunSent->seg));
			tcb[sockfd]->sendBufunSent = tcb[sockfd]->sendBufunSent->next;

			tcb[sockfd]->unAck_segNum++;
			printf("unAck_segNum: %d\n", tcb[sockfd]->unAck_segNum);
		}
		pthread_mutex_unlock(tcb[sockfd]->bufMutex);
		if(flag == 1)
			break;
	}
	if(tcb[sockfd]->state != CONNECTED)
		return -1;
	return 1;
}
Exemplo n.º 30
0
// 这是由stcp_server_init()启动的线程. 它处理所有来自客户端的进入数据. seghandler被设计为一个调用sip_recvseg()的无穷循环, 
// 如果sip_recvseg()失败, 则说明到SIP进程的连接已关闭, 线程将终止. 根据STCP段到达时连接所处的状态, 可以采取不同的动作.
// 请查看服务端FSM以了解更多细节.
void* seghandler(void* arg) 
{
	long i;
	int flag;
	unsigned int client_port;
	seg_t* seg = (seg_t*)malloc(sizeof(seg_t));
	int* src_nodeID = (int*)malloc(sizeof(int));
	while (1) {
		flag = sip_recvseg(sip_conn, src_nodeID, seg);///////////////////////////////////注意src_nodeID的使用
		if (flag == 1) {//报文丢失
			printf("the stcp server does'n receive a segment! segment is lost!\n");
			continue;
		}
		if (checkchecksum(seg) == -1) {
			printf("Checksum error!\n");
			continue;
		}
		if (flag == -1) {//接收不到报文,线程停止
			printf("can't receive anything in tcp level, the seghandler thread is going to end.\n");
			break;
		}
		for (i = 0; i < MAX_TRANSPORT_CONNECTIONS; i++) {
			if ((NULL != server_tcb[i]) && (server_tcb[i]->server_portNum == seg->header.dest_port) && (server_tcb[i]->client_portNum == seg->header.src_port) && (*src_nodeID == server_tcb[i]->client_nodeID)) {
				break;
			}
		}
		if (i == MAX_TRANSPORT_CONNECTIONS) {
			printf("the tcb you want to find does't exist! but...\n");
			if (seg->header.type == SYN) {
				for (i = 0; i < MAX_TRANSPORT_CONNECTIONS; i++) {
					if ((NULL != server_tcb[i]) && (server_tcb[i]->server_portNum == seg->header.dest_port)) {
						break;
					}
				}
				if (i == MAX_TRANSPORT_CONNECTIONS) {
					printf("the tcb you want does't exist really!!\n");
					continue;
				}
			}
			else
				continue;
		}
		switch (seg->header.type) {
			case 0:
				printf("the type stcp server receives is SYN\n");
				break;
			case 1:
				printf("the type stcp server receives is SYNACK\n");
				break;
			case 2:
				printf("the type stcp server receives is FIN\n");
				break;
			case 3:
				printf("the type stcp server receives is FINACK\n");
				break;
			case 4:
				printf("the type stcp server receives is DATA\n");
				break;
			case 5:
				printf("the type stcp server receives is DATAACK\n");
				break;
		}
		client_port = seg->header.src_port;
		switch (server_tcb[i]->state) {
			case CLOSED:
				printf("stcp server now is in CLOSED state!\n");
				break;
			case LISTENING:
				printf("stcp server now is in LISTENING state!\n");
				if (seg->header.type == SYN) {
					printf("receive a SYN!\n");
					server_tcb[i]->state = CONNECTED;
					server_tcb[i]->client_portNum = seg->header.src_port;
					server_tcb[i]->client_nodeID = *src_nodeID;
					sendACK(i, client_port, *src_nodeID, SYNACK, seg);
				}
				break;
			case CONNECTED:
				printf("stcp server now is in CONNECTED state!\n");
				if (seg->header.type == SYN) {
					printf("receive a SYN!\n");
					server_tcb[i]->state = CONNECTED;
					server_tcb[i]->expect_seqNum = seg->header.seq_num;
					sendACK(i, client_port, *src_nodeID, SYNACK, seg);
				}
				else if (seg->header.type == FIN) {
					printf("receive a FIN!\n");
					server_tcb[i]->state = CLOSEWAIT;
					sendACK(i, client_port, *src_nodeID, FINACK, seg);
					pthread_t FINhandle_thread;
					int rc;
					rc = pthread_create(&FINhandle_thread, NULL, FINhandler, (void *)i);
					if (rc) {
						printf("ERROR; return code from pthread_create() is %d\n", rc);
						exit(-1);
					}
					
				}
				else if (seg->header.type == DATA) {
					printf("receive a DATA!\n");
					printf("the expect_seqNum is %d\n", server_tcb[i]->expect_seqNum);
					printf("the seqNum is %d\n", seg->header.seq_num);
					if (seg->header.seq_num == server_tcb[i]->expect_seqNum) {
						printf("the expect_seqNum == seq_num!\n");
						pthread_mutex_lock(server_tcb[i]->bufMutex);
						memcpy(server_tcb[i]->recvBuf + server_tcb[i]->usedBufLen, seg->data, seg->header.length);
						printf("the seg->header.length is %d\n", seg->header.length);
						server_tcb[i]->usedBufLen += seg->header.length;
						server_tcb[i]->expect_seqNum += seg->header.length;
						seg->header.src_port = server_tcb[i]->server_portNum;        //源端口号
						seg->header.dest_port = client_port;       //目的端口号
						seg->header.seq_num = 0;         //序号
						seg->header.ack_num = server_tcb[i]->expect_seqNum;         //确认号
						seg->header.length = 0;    //段数据长度
						seg->header.type = DATAACK;     //段类型
						seg->header.rcv_win = 0;  //当前未使用
						seg->header.checksum = 0;
						seg->header.checksum = checksum(seg);  //这个段的校验和
						sip_sendseg(sip_conn, *src_nodeID, seg);
						printf("stcp server send the changing DATAACK %d succesfully!\n", seg->header.ack_num);
						pthread_mutex_unlock(server_tcb[i]->bufMutex);
					}
					else {
						printf("the expect_seqNum != seq_num!\n");
						seg->header.src_port = server_tcb[i]->server_portNum;        //源端口号
						seg->header.dest_port = client_port;       //目的端口号
						seg->header.seq_num = 0;         //序号
						seg->header.ack_num = server_tcb[i]->expect_seqNum;         //确认号
						seg->header.length = 0;    //段数据长度
						seg->header.type = DATAACK;     //段类型
						seg->header.rcv_win = 0;  //当前未使用
						seg->header.checksum = 0;
						seg->header.checksum = checksum(seg);  //这个段的校验和
						sip_sendseg(sip_conn, *src_nodeID, seg);
						printf("stcp server send the not changed DATAACK %d succesfully!\n", seg->header.ack_num);
					}
				}
				break;
			case CLOSEWAIT:
				printf("stcp server now is in CLOSEWAIT state!\n");
				if (seg->header.type == FIN) {
					printf("receive a FIN!\n");
					sendACK(i, client_port, *src_nodeID, FINACK, seg);
				}
				break;
		}
	}
  	return 0;
}