// NatCheck.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <process.h>
#include <stdio.h>
#include <afx.h>
#include "winsock2.h"
#include "./Include/packet.h"
#pragma comment(lib,"./lib/wininet.lib")
#pragma comment(lib,"wsock32.lib")
#include "ws2tcpip.h"
#include "string.h"
#define N_SuperNode 5
#define N_NatCheckRequestQueue 20
#define PORT_SERVER_NATCHECK 8888
#define PORT_SERVER_NATCHECK_1 8889
#define PORT_CLIENT_NATCHECK 7777
#define PORT_SERVER_CLIENT_INFO 4444
#define N_CheckTime 5 //最多检测次数
SOCKET sClient,sServer;//客户端和服务端的socket号
struct sockaddr_in sn1_addr,sn2_addr,sn_addr,client_addr;
struct sockaddr_in client_addr_deal;
struct in_addr in_addr_tmp,in_addr_tmp1;
FILE *fp; //客户端读取hostcache.txt文件指针
int i=0,j=0;
unsigned long int snIP[N_SuperNode];//读取的SN的IP地址列表
unsigned short int snPort[N_SuperNode];//读取的SN的Port列表
char tmpIP[15],tmpPort[5];
char ch;
char IP_return[15];
/* 本client的网络类型:
* 0 = public net
* 1 = full cone nat
* 2 = symmetric nat
* 3 = restricted cone nat
* 4 = port restricted cone nat
*/
unsigned long int myID=0,friendID=26;//本client和friend的用户ID
char myNetType=-1,friendNetType=-1;
unsigned long int myPubIp,friendPubIp,myPriIp,friendPriIp;
unsigned short int myPubPort,friendPubPort,myPriPort,friendPriPort;
//natCheck请求包结构
struct natCheckPacket{
char version;
char dowhat;
unsigned short int port;
unsigned long int ip;
unsigned long int id;
}natCheckPacket;
typedef struct natCheckPacket NCP;
char buff[sizeof(natCheckPacket)];//发包用的缓冲区
//natCheck请求数据结构
struct natCheckRequest{
NCP ncp;//缓存到来的请求包
struct natCheckRequest * next;//指向下一个请求数据
unsigned long int ip;//发送请求的client IP地址
unsigned short int port;//发送请求的client Port
}natCheckRequest;
typedef struct natCheckRequest NCR;
struct netInfoResponsePacket{
NCP ncp;
unsigned long int ip_pub;
unsigned short int port_pub;
unsigned short int no;
}netInfoResponsePacket;
typedef struct netInfoResponsePacket NIRP;
//natCheck请求数据循环队列
NCR natCheckRequestQueue[N_NatCheckRequestQueue];
NCR * h_NatCheckRequestQueue,* t_NatCheckRequestQueue;
/*
* 获得本地主机IP地址
*/
char * getownIP()
{
//////////////////
// 获得主机名.
char hostname[256];
int res = gethostname(hostname, sizeof(hostname));
if (res != 0) {
printf("Error: %u/n", WSAGetLastError());
return "failed";
}
////////////////
// 根据主机名获取主机信息.
hostent* pHostent = gethostbyname(hostname);
if (pHostent==NULL) {
printf("Error: %u/n", WSAGetLastError());
return "failed";
}
//////////////////
// 解析返回的hostent信息.
hostent& he = *pHostent;
sockaddr_in sa;
memcpy ( &sa.sin_addr.s_addr, he.h_addr_list[0],he.h_length);
return inet_ntoa(sa.sin_addr);
}
unsigned long int getownIP_uli()
{
//////////////////
// 获得主机名.
char hostname[256];
int res = gethostname(hostname, sizeof(hostname));
if (res != 0) {
printf("Error: %u/n", WSAGetLastError());
return -1;
}
////////////////
// 根据主机名获取主机信息.
hostent* pHostent = gethostbyname(hostname);
if (pHostent==NULL) {
printf("Error: %u/n", WSAGetLastError());
return -1;
}
//////////////////
// 解析返回的hostent信息.
hostent& he = *pHostent;
sockaddr_in sa;
memcpy ( &sa.sin_addr.s_addr, he.h_addr_list[0],he.h_length);
return sa.sin_addr.S_un.S_addr;
}
/*
* superNode接收请求线程入口函数
*/
unsigned int _stdcall ThreadFunction_sn_get(void *param)
{
//创建套接字
if( (sServer = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
{
printf("获取SOCKET号失败!!!/n");
return 0;
}
//绑定套接字和本机地址和端口
sn_addr.sin_family=AF_INET;
sn_addr.sin_port=htons(PORT_SERVER_NATCHECK);
sn_addr.sin_addr.s_addr =INADDR_ANY ;//inet_addr(getownIP()); //
if(bind(sServer, (struct sockaddr*)&sn_addr, sizeof(sn_addr)) < 0 )
{
printf("不能将服务器地址捆绑到SOCKET号上!!!/n");
closesocket(sServer);
return 0;
}
//printf("接收..../n");
int iLen=sizeof(client_addr);
struct natCheckPacket * ncp=(struct natCheckPacket *)buff;
int timeout=300;
while (1)
{
setsockopt(sServer, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,sizeof(timeout));
if(recvfrom(sServer,buff,sizeof(buff),0,(sockaddr*)&client_addr,&iLen)!=-1)
{
//判断队列是否满
if(t_NatCheckRequestQueue->next!=h_NatCheckRequestQueue)
{
//先修改t
NCR * t=t_NatCheckRequestQueue;
t_NatCheckRequestQueue=t->next;
//再写入
t->ncp=*(ncp);
t->ip=client_addr.sin_addr.S_un.S_addr;
t->port=client_addr.sin_port;
}
}
Sleep(300);
//printf("version:%d/tdowhat:%d/tport:%d/tip:%d/n",ncp->version,ncp->dowhat,
// ncp->port,ncp->ip);
//printf("Client said: %s/n",buff);
//strcpy(buff,"I am a server!!/n");
//sendto(sServer,buff,sizeof(buff),0,(sockaddr*)&client_addr,sizeof(client_addr));
}
//closesocket(sServer);
return 0;
}
/*
* 构造NCP包发送给SuperNode
* 接受返回的NCP包
*/
int sendNCPtoSNandRecvNCP(unsigned long int ip_SN,unsigned short int port_SN,
NCP ncp_send)
{
int timeout=300;
sn_addr.sin_addr.S_un.S_addr=ip_SN;
sn_addr.sin_family=AF_INET;
sn_addr.sin_port=htons(port_SN);
int iLen=sizeof(sn_addr);
NCP * ncp=(NCP *)buff;
ncp->version=ncp_send.version;
ncp->dowhat=ncp_send.dowhat;
ncp->port=ncp_send.port;
ncp->ip=ncp_send.ip;
ncp->id=ncp_send.id;
setsockopt(sClient, SOL_SOCKET , SO_SNDTIMEO, (char *)&timeout,sizeof(timeout));
sendto(sClient,buff,sizeof(buff),0,(SOCKADDR*)&sn_addr,iLen);
in_addr_tmp.S_un.S_addr=ip_SN;
in_addr_tmp1.S_un.S_addr=ncp->ip;
char * ipaddr=NULL;
char addr[15];
in_addr inaddr;
inaddr. s_addr=ncp->ip;
ipaddr= inet_ntoa(inaddr);
strcpy(addr,ipaddr);
printf("[send][SN(%s)]/n/tversion:%d/tdowhat:%d/tport:%d/tip:%s/n",inet_ntoa(in_addr_tmp),
ncp->version,ncp->dowhat,ncp->port,addr);
timeout=1500;
setsockopt(sClient, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,sizeof(timeout));
if(recvfrom(sClient,buff,sizeof(buff),0,(sockaddr*)&sn_addr,&iLen)<0)
return 0;
else
{
inaddr. s_addr=sn_addr.sin_addr.S_un.S_addr;
ipaddr= inet_ntoa(inaddr);
strcpy(addr,ipaddr);
in_addr_tmp.S_un.S_addr=((NCP *)buff)->ip;
printf("[rece][sn(%s)]/n/tversion:%d/tdowhat:%d/tport:%d/tip:%s/n",addr,((NCP *)buff)->version,
((NCP *)buff)->dowhat,ntohs(((NCP *)buff)->port),inet_ntoa(in_addr_tmp));
return 1;
}
}
/*
* 构造NCP包发送给SuperNode
* 接受返回的NIRP包
*/
int sendNCPtoSNandRecvNIRP(unsigned long int ip_SN,unsigned short int port_SN,
NCP ncp_send)
{
FILE * fp_n;
FILE * fp_c;//for compare
//打开文件natCheckResult.txt
if(!(fp_n=fopen("./natCheckResult.txt","a")))
{
printf("natCheckResult.txt file not found!/n");
return 0;
}
char one_line[100],one_line_f[100];
int timeout=300;
sn_addr.sin_addr.S_un.S_addr=ip_SN;
sn_addr.sin_family=AF_INET;
sn_addr.sin_port=htons(port_SN);
int iLen=sizeof(sn_addr);
char buff_recv[sizeof(NIRP)];
NCP * ncp=(NCP *)buff;
NIRP * nirp=(NIRP *)buff_recv;
ncp->version=ncp_send.version;
ncp->dowhat=ncp_send.dowhat;
ncp->port=ncp_send.port;
ncp->ip=ncp_send.ip;
ncp->id=ncp_send.id;
setsockopt(sClient, SOL_SOCKET , SO_SNDTIMEO, (char *)&timeout,sizeof(timeout));
sendto(sClient,buff,sizeof(buff),0,(SOCKADDR*)&sn_addr,iLen);
in_addr_tmp.S_un.S_addr=ip_SN;
in_addr_tmp1.S_un.S_addr=ncp->ip;
char * ipaddr=NULL;
char addr[15];
in_addr inaddr;
inaddr. s_addr=ncp->ip;
ipaddr= inet_ntoa(inaddr);
strcpy(addr,ipaddr);
printf("[send][SN(%s)]/n/tversion:%d/tdowhat:%d/tport:%d/tip:%s/n",
inet_ntoa(in_addr_tmp),ncp->version,ncp->dowhat,ncp->port,addr);
timeout=1500;
setsockopt(sClient, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,sizeof(timeout));
int stop=0;
while(!stop)
{
setsockopt(sClient, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,sizeof(timeout));
if(recvfrom(sClient,buff_recv,sizeof(buff_recv),0,(sockaddr*)&sn_addr,&iLen)<0)
stop=1;
else
{
sprintf(one_line,"%u %u %u %u %u %u",
((NIRP *)buff_recv)->ncp.id,
((NIRP *)buff_recv)->ncp.dowhat,
((NIRP *)buff_recv)->ip_pub,
((NIRP *)buff_recv)->port_pub,
((NIRP *)buff_recv)->ncp.ip,
((NIRP *)buff_recv)->ncp.port);
printf("%s/n",one_line);
friendNetType=((NIRP *)buff_recv)->ncp.dowhat;
friendPubIp=((NIRP *)buff_recv)->ip_pub;
friendPubPort=((NIRP *)buff_recv)->port_pub;
friendPriIp=((NIRP *)buff_recv)->ncp.ip;
friendPriPort=((NIRP *)buff_recv)->ncp.port;
//打开文件natCheckResult.txt
if(!(fp_c=fopen("./natCheckResult.txt","r")))
{
printf("natCheckResult.txt file not found!/n");
return 0;
}
while(!feof(fp_c))
{
i=0;
while((ch=fgetc(fp_c))!=10 && ch!=-1)
one_line_f[i++]=ch;
if(ch==-1)
break;
one_line_f[i]='/0';
if(strcmp(one_line,one_line_f)==0)
{
fclose(fp_c);
fclose(fp_n);
return 1;
}
}
fprintf(fp_n,"%s/n",one_line);
fflush(fp_n);
}
}
fclose(fp_c);
fclose(fp_n);
return 1;
}
void longIP2string(unsigned long int ip,char* addr)
{
in_addr inaddr;
char * ipaddr=NULL;
inaddr. s_addr=sn_addr.sin_addr.S_un.S_addr;
ipaddr= inet_ntoa(inaddr);
strcpy(addr,ipaddr);
}
/*
* 从client端的hostcache.txt文件获取一个SN
* 写入ip_SN,port_SN
* 如果文件已经到结尾,或者文件语法错误,则返回0
*/
int getSNfromHostCache(FILE * fp,unsigned long int &ip_SN,unsigned short int &port_SN)
{
if(feof(fp))
return 0;
i=0;
while((ch=fgetc(fp))!=' ' && ch!=10 && ch!=-1)
tmpIP[i++]=ch;
if(ch==10 || ch==-1)
{
printf("hostcache.txt file error!/n");
return 0;
}
tmpIP[i]='/0';
i=0;
while((ch=fgetc(fp))!=10 && ch!=-1)
tmpPort[i++]=ch;
tmpPort[i]='/0';
ip_SN=inet_addr(tmpIP);
port_SN=(unsigned short int)atoi(tmpPort);
return 1;
}
/*
* client最先知道检测结果
* client需要向自己缓存的SN节点汇报自己的网络类型信息
* 这里依然使用了NCP包
void broadcastNatCheckResult(char version,
char dowhat,unsigned long int ip,unsigned short int port,
unsigned long int id)
*/
void broadcastNatCheckResult(NCP ncp_send)
{
FILE * fp_b=fp;
fseek(fp_b,0L,0);
while (!feof(fp_b)) {
i=0;
while((ch=fgetc(fp_b))!=' ' && ch!=10 && ch!=-1)
tmpIP[i++]=ch;
if(ch==10 || ch==-1)
{
printf("hostcache.txt file error!/n");
return;
}
tmpIP[i]='/0';
i=0;
while((ch=fgetc(fp_b))!=10 && ch!=-1)
tmpPort[i++]=ch;
tmpPort[i]='/0';
int timeout=300;
sn_addr.sin_addr.S_un.S_addr=inet_addr(tmpIP);
sn_addr.sin_family=AF_INET;
sn_addr.sin_port=htons((unsigned short int)atoi(tmpPort));
int iLen=sizeof(sn_addr);
NCP * ncp=(NCP *)buff;
ncp->version=ncp_send.version;
ncp->dowhat=ncp_send.dowhat;
ncp->port=ncp_send.port;
ncp->ip=ncp_send.ip;
ncp->id=ncp_send.id;
setsockopt(sClient, SOL_SOCKET , SO_SNDTIMEO, (char *)&timeout,sizeof(timeout));
sendto(sClient,buff,sizeof(buff),0,(SOCKADDR*)&sn_addr,iLen);
}
fclose(fp_b);
return;
}
/*
* SN收到client汇报的结果,
* 向NatCheckResult.txt 写入id 网络类型 外网ip port 内网ip port
*/
int storeNatCheckResult(unsigned long int id,char type,
unsigned long int pub_ip,unsigned short int pub_port,
unsigned long int pri_ip,unsigned short int pri_port)
{
FILE * fp_n;
char one_line[100],one_line_f[100];
sprintf(one_line,"%u %u %u %u %u %u",id,type,pub_ip,pub_port,pri_ip,pri_port);
//打开文件natCheckResult.txt
if(!(fp_n=fopen("./natCheckResult.txt","rw")))
{
printf("natCheckResult.txt file not found!/n");
return 0;
}
while(!feof(fp_n))
{
i=0;
while((ch=fgetc(fp_n))!=10 && ch!=-1)
one_line_f[i++]=ch;
if(ch==-1)
{
break;
}
one_line_f[i]='/0';
if(strcmp(one_line,one_line_f)==0)
return 0;
}
fclose(fp_n);
if(!(fp_n=fopen("./natCheckResult.txt","a")))
{
printf("natCheckResult.txt file not found!/n");
return 0;
}
fprintf(fp_n,"%u %u %u %u %u %u/n",id,type,pub_ip,pub_port,pri_ip,pri_port);
printf("%u %u %u %u %u %u/n",id,type,pub_ip,pub_port,pri_ip,pri_port);
fflush(fp_n);
fclose(fp_n);
return 1;
}
/*
* SN收到client的查询请求,
* 从NatCheckResult.txt 中查找id对应的 网络类型 外网ip port 内网ip port
*/
int searchNatCheckResult(NCP ncp,SOCKET sServer,sockaddr_in addr)
{
FILE * fp_n;
char id[32];
//打开文件natCheckResult.txt
if(!(fp_n=fopen("./natCheckResult.txt","r")))
{
printf("natCheckResult.txt file not found!/n");
return 0;
}
int j=0;
while(!feof(fp_n))
{
i=0;
while((ch=fgetc(fp_n))!=' ' && ch!=10 && ch!=-1)
id[i++]=ch;
if(ch==10)
{
printf("natCheckResult.txt file error!/n");
return 0;
}
if(ch==-1)
{
break;
}
id[i]='/0';
if(ncp.id!=(unsigned long int)atoi(id))
{
while(fgetc(fp_n)!=10);
continue;
}
unsigned long int ip_pub;
unsigned short int port_pub;
fscanf(fp_n,"%d %d %d %d %d/n",&(ncp.dowhat),&ip_pub,&port_pub,&(ncp.ip),&(ncp.port));
char buff_send[sizeof(NIRP)];
NIRP * nirp = (NIRP *) buff_send;
nirp->ncp=ncp;
nirp->ip_pub=ip_pub;
nirp->port_pub=port_pub;
nirp->no=j++;
sendto(sServer,buff_send,sizeof(buff_send),0,(sockaddr*)&addr,sizeof(addr));
}
fclose(fp_n);
return 1;
}
/*
* main函数
*/
int main(int argc, char* argv[])
{
if(argc < 2)
{
printf("usage: %s -c or -s /n", argv[0]);
printf("-c: for clients/n-s: for superNode/n");
return 0;
}
//////////////////
// 初始化winsock环境.
WSADATA wsadata;
WORD wVersion=MAKEWORD(2,0); //winsock 2.0
if(WSAStartup(wVersion,&wsadata)!=0)
{
printf("winsocket initalize failed!/n");
WSACleanup();
return 0;
}
///////////////////////////////////////////////////////////////////
//客户端程序入口
////////////////////////////////////////////////////////////////////
if(strcmp(argv[1],"-c")==0)
{
if(argc>=3)
myID=atoi(argv[2]);
NCP ncp_send;
ncp_send.version=0;
ncp_send.id=myID;
//////////////////
// 读取hostcache文件中的前两个supernode
if(!(fp=fopen("./hostcache.txt","r")))
{
printf("hostcache.txt file not found!/n");
return 0;
}
if( (sClient=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP)) < 0)
{
printf("获取SOCKET号失败!!!/n");
return 0;
}
myPriIp=inet_addr(getownIP());
myPriPort=htons(PORT_CLIENT_NATCHECK);
client_addr.sin_addr.S_un.S_addr=INADDR_ANY; /* use my IP address */
client_addr.sin_family=AF_INET;
client_addr.sin_port=htons(PORT_CLIENT_NATCHECK);
printf("[info]client ip=%s/tport:%d/n",getownIP(),ntohs(myPriPort));
//bind(int sockfd, const struct sockaddr *my_addr, int addrlen);
if(bind(sClient,(struct sockaddr*)&client_addr,sizeof(client_addr))<0)
{
printf("不能捆绑到SOCKET号上!!!/n");
closesocket(sClient);
return 0;
}
/*/////////////////////////////////////////////////////////////////////////////////////
// NAT检测开始
// 检测流程:
1.向超级节点SN1发送0号包,等待一段超时时间,如果没有返回,换下一个超级节点。
否则go 2,如果hostcache中的节点都失效了,那么开始向中心节点发请求,来得到一批
新的superNode节点列表;
2.判断超级节点返回的7号包中携带的(ip,port)和自己发包时用的(ip,port)是否相同,
如果相同的话,说明本地是公网IP;如果不同的话,说明在NAT后;
3.向SN1发送1号包,并携带一个自己列表中的另一个superNode,SN2的(ip,port),让SN1
发8号包给SN2,告诉本client的外网(ip,port),让SN2给本client发6号包;另外SN1还可
以在自己维护的临近的SN列表中选择3个也给client发送6号包。
4.如果client在一段超时时间内,没有收到任何包,那么在将3中的过程进行一次,总共最多
可以进行N_CheckTime(5)次。其中只要有一次收到包,就go 5。
5.如果收到了SN2、SN3、SN4中的任何一个,检测就停止,结果是full cone Nat。如果没有
收到任何包,检测继续,go 6
6.client从自己的hostcache中选择一个SN2,向其发送2号包,等待一段超时时间,如果没有
收到5号包的话,继续从hostcache中另选择一个SN3,如果hostcache中的所有SN都不给回应
5号包的话,从中心节点获取新的SN后,继续发2号包。收到第一个5号包,开始比较,如果和
SN1的返回结果(ip,port)中如果有任何一对不一致,则说明是Symmetric NAT,检测停止。
否则是Restricted Cone NAT,同时继续检测,go 7
7.client向SN1发送3号包,让SN1换用另一个端口发4号包,重复若干次,如果client能收到说明
是Restricted Cone NAT,否则是Port Restricted Cone NAT。检测结束。
*///////////////////////////////////////////////////////////////////////////////////////
//读取第一个SN,SN1的(IP,Port),并给其发0号包
if(getSNfromHostCache(fp,snIP[0],snPort[0])==0)
{
printf("[error]there is no SN in HostCache.txt!/n");
return 0;
}
/*
int sendNCPtoSNandRecvNCP(unsigned long int ip_SN,
unsigned short int port_SN,
char version,
char dowhat,
unsigned long int ip,
unsigned short int port)
*/
ncp_send.dowhat=0;
ncp_send.ip=0;
ncp_send.port=0;
while(sendNCPtoSNandRecvNCP(snIP[0],snPort[0],ncp_send)==0)
{
if(getSNfromHostCache(fp,snIP[0],snPort[0])==0)
{
printf("[error]there is no more SN in HostCache.txt!/n");
//此时应该从中心节点获取更新的SN列表
//......
printf("[error]check failed temporarily");
return 0;
}
}
long ft=ftell(fp);
in_addr_tmp.S_un.S_addr=snIP[0];
printf("[info]SN1 ip=%s/tport=%d/n",inet_ntoa(in_addr_tmp),snPort[0]);
//对比返回的(ip,port) ip_return port_return
unsigned long int ip_return=((NCP *)buff)->ip;
unsigned short int port_return=((NCP *)buff)->port;
if(myPriIp==ip_return && myPriPort==port_return)
{
printf("[Reslut]public net/n");
myNetType=0;
ncp_send.dowhat=9;
ncp_send.ip=myPubIp=myPriIp;
ncp_send.port=myPubPort=myPriPort;
broadcastNatCheckResult(ncp_send);
return 0;
}
//再读取一个SN,SN2的(IP,Port)
int checkTime=N_CheckTime;
while(checkTime>0 && !feof(fp))
{
if(getSNfromHostCache(fp,snIP[1],snPort[1])==0)
{
printf("[error]there is no more SN in HostCache.txt!/n");
break;
}
ncp_send.dowhat=1;
ncp_send.ip=snIP[1];
ncp_send.port=snPort[1];
if(sendNCPtoSNandRecvNCP(snIP[0],snPort[0],ncp_send)==1)
{
printf("[Reslut]full cone nat/n");
myNetType=1;
ncp_send.dowhat=10;
ncp_send.ip=myPriIp;
ncp_send.port=myPriPort;
myPubIp=ip_return;
myPubPort=port_return;
broadcastNatCheckResult(ncp_send);
return 0;
}
checkTime--;
}
printf("[Reslut]not full cone nat, checking is continued./n");
in_addr_tmp.S_un.S_addr=snIP[1];
printf("[info]SN2 ip=%s/tport=%d/n",inet_ntoa(in_addr_tmp),snPort[1]);
//在hostcache中的SN1下再找一个SN3,给他发送2号包,让他返回client的ip和port
fseek(fp,ft,0);
if(getSNfromHostCache(fp,snIP[1],snPort[1])==0)
{
printf("[error]there is no SN in HostCache.txt!/n");
return 0;
}
ncp_send.dowhat=2;
ncp_send.ip=0;
ncp_send.port=0;
while(sendNCPtoSNandRecvNCP(snIP[1],snPort[1],ncp_send)==0)
{
if(getSNfromHostCache(fp,snIP[1],snPort[1])==0)
{
printf("[error]there is no more SN in HostCache.txt!/n");
//此时应该从中心节点获取更新的SN列表
//......
printf("[error]check failed temporarily");
return 0;
}
}
in_addr_tmp.S_un.S_addr=snIP[1];
printf("[info]SN3 ip=%s/tport=%d/n",inet_ntoa(in_addr_tmp),snPort[1]);
//对比返回的(ip,port) ip_return port_return
unsigned long int ip_return1=((NCP *)buff)->ip;
unsigned short int port_return1=((NCP *)buff)->port;
if(ip_return1!=ip_return || port_return1!=port_return)
{
printf("[Reslut]symmetric nat/n");
myNetType=2;
ncp_send.dowhat=11;
ncp_send.ip=myPriIp;
ncp_send.port=myPriPort;
broadcastNatCheckResult(ncp_send);
return 0;
}
ncp_send.dowhat=3;
ncp_send.ip=0;
ncp_send.port=0;
if(sendNCPtoSNandRecvNCP(snIP[0],snPort[0],ncp_send)==1)
{
printf("[Reslut]Restricted Cone nat/n");
myNetType=3;
ncp_send.dowhat=12;
ncp_send.ip=myPriIp;
ncp_send.port=myPriPort;
myPubIp=ip_return;
myPubPort=port_return;
broadcastNatCheckResult(ncp_send);
return 0;
}
printf("[Reslut]Port Restricted Cone nat/n");
myNetType=4;
ncp_send.dowhat=13;
ncp_send.ip=myPriIp;
ncp_send.port=myPriPort;
myPubIp=ip_return;
myPubPort=port_return;
broadcastNatCheckResult(ncp_send);
//以上检测网络类型结束,下面开始与某好友通讯
printf("do you want to talk with someone? [Y]yes [N]no/n");
scanf("%c",&ch);
if(ch!='Y' && ch!='y')
return 0;
printf("which friend would you want to talk with? Input his id:/n");
scanf("%d",&friendID);
//从SN1获取friend网络类型列表
ncp_send.dowhat=14;
ncp_send.ip=0;
ncp_send.port=0;
ncp_send.id=friendID;
if(sendNCPtoSNandRecvNIRP(snIP[0],snPort[0],ncp_send)==0)
{
printf("[error]查询好友网络信息失败!/n");
return 0;
}
switch(friendNetType)
{
case 9:
break;
case 10:
break;
case 11:
break;
case 12:
break;
case 13:
break;
default:
break;
}
}
////////////////////////////////////////////////////////////////////
//服务端程序入口
/////////////////////////////////////////////////////////////////////
else if(strcmp(argv[1],"-s")==0)
{
//创建另一个套接字
SOCKET sServer1;
if( (sServer1 = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
{
printf("获取SOCKET号失败!!!/n");
return 0;
}
//绑定套接字和本机地址和端口
sn1_addr.sin_family=AF_INET;
sn1_addr.sin_port=htons(PORT_SERVER_NATCHECK_1);
sn1_addr.sin_addr.s_addr =INADDR_ANY ;//inet_addr(getownIP()); //
if(bind(sServer1, (struct sockaddr*)&sn1_addr, sizeof(sn1_addr)) < 0 )
{
printf("不能将服务器地址捆绑到SOCKET号上!!!/n");
closesocket(sServer1);
return 0;
}
//////////////////
// 循环队列natCheckRequestQueue初始化
for(i=0;i<N_NatCheckRequestQueue-1;i++)
{
natCheckRequestQueue[i].next= & natCheckRequestQueue[i+1];
}
natCheckRequestQueue[N_NatCheckRequestQueue-1].next
= & natCheckRequestQueue[0];
h_NatCheckRequestQueue = & natCheckRequestQueue[0];
t_NatCheckRequestQueue = & natCheckRequestQueue[0];
//////////////////
// 启动接受请求的服务线程
// 入口函数为:ThreadFunction_sn_get
// 判断队列是否满,不满的条件下,先修改t,再写进t指向的单元
//HANDLE thread_sn_get = (HANDLE)_beginthread(ThreadFunction_sn_get,0,NULL);
HANDLE thread_sn_get = (HANDLE)_beginthreadex(0,0,&ThreadFunction_sn_get,0,0,NULL);
//////////////////
// 主服务线程
// 用来从循环队列natCheckRequestQueue的头指针得到请求数据来处理
// 判断队列是否空,非空的条件下,先读出h指向的单元,再修改h
while(1)
{
//判断队列是否空
if(t_NatCheckRequestQueue!=h_NatCheckRequestQueue)
{
//先读出
NCP * ncp_deal=(NCP *)buff;
*(ncp_deal)=h_NatCheckRequestQueue->ncp;
unsigned long int ip_deal=h_NatCheckRequestQueue->ip;
unsigned short int port_deal=h_NatCheckRequestQueue->port;
//再修改h
h_NatCheckRequestQueue=h_NatCheckRequestQueue->next;
//处理这个来自(ip,port)的请求
switch(ncp_deal->dowhat)
{
/* dowhat字段:
* 0 请求用户返回Ip:port 7 单独的响应包
* 1 客户请求提供其他主机检测 6 其他主机响应包
* 2 同时请求两主机发回响应 5 针对2的回应包
* 3 请求使用另一端口发回响应 4 使用另一端口响应
* 8 SN请求其他主机检测
-----------------------------------------------------------
* 9 汇报检测结果给SN public net
* 10 汇报检测结果给SN full cone nat
* 11 汇报检测结果给SN symmetric nat
* 12 汇报检测结果给SN restricted cone nat
* 13 汇报检测结果给SN port restricted cone nat
-----------------------------------------------------------
*/
case 0:
ncp_deal->dowhat=7;
ncp_deal->ip=ip_deal;
ncp_deal->port=port_deal;
client_addr_deal.sin_family=AF_INET;
client_addr_deal.sin_addr.S_un.S_addr=ip_deal;
client_addr_deal.sin_port=port_deal;
printf("[deal][0]send [7] to:%d.%d.%d.%d:%d/n",
client_addr_deal.sin_addr.S_un.S_un_b.s_b1,
client_addr_deal.sin_addr.S_un.S_un_b.s_b2,
client_addr_deal.sin_addr.S_un.S_un_b.s_b3,
client_addr_deal.sin_addr.S_un.S_un_b.s_b4,
htons(client_addr_deal.sin_port));
sendto(sServer,buff,sizeof(buff),0,(sockaddr*)&client_addr_deal,sizeof(client_addr_deal));
break;
case 1:
client_addr_deal.sin_family=AF_INET;
client_addr_deal.sin_addr.S_un.S_addr=ncp_deal->ip;
client_addr_deal.sin_port=htons(ncp_deal->port);
ncp_deal->dowhat=8;
ncp_deal->ip=ip_deal;
ncp_deal->port=port_deal;
printf("[deal][1]send [8] to:%d.%d.%d.%d:%d/n",
client_addr_deal.sin_addr.S_un.S_un_b.s_b1,
client_addr_deal.sin_addr.S_un.S_un_b.s_b2,
client_addr_deal.sin_addr.S_un.S_un_b.s_b3,
client_addr_deal.sin_addr.S_un.S_un_b.s_b4,
htons(client_addr_deal.sin_port));
sendto(sServer,buff,sizeof(buff),0,(sockaddr*)&client_addr_deal,sizeof(client_addr_deal));
break;
case 2:
client_addr_deal.sin_family=AF_INET;
client_addr_deal.sin_addr.S_un.S_addr=ip_deal;
client_addr_deal.sin_port=port_deal;
ncp_deal->dowhat=5;
ncp_deal->ip=ip_deal;
ncp_deal->port=port_deal;
printf("[deal][2]send [5] to:%d.%d.%d.%d:%d/n",
client_addr_deal.sin_addr.S_un.S_un_b.s_b1,
client_addr_deal.sin_addr.S_un.S_un_b.s_b2,
client_addr_deal.sin_addr.S_un.S_un_b.s_b3,
client_addr_deal.sin_addr.S_un.S_un_b.s_b4,
htons(client_addr_deal.sin_port));
sendto(sServer,buff,sizeof(buff),0,(sockaddr*)&client_addr_deal,sizeof(client_addr_deal));
break;
case 3:
client_addr_deal.sin_family=AF_INET;
client_addr_deal.sin_addr.S_un.S_addr=ip_deal;
client_addr_deal.sin_port=port_deal;
ncp_deal->dowhat=4;
ncp_deal->ip=ip_deal;
ncp_deal->port=port_deal;
printf("[deal][3]send [4] to:%d.%d.%d.%d:%d/n",
client_addr_deal.sin_addr.S_un.S_un_b.s_b1,
client_addr_deal.sin_addr.S_un.S_un_b.s_b2,
client_addr_deal.sin_addr.S_un.S_un_b.s_b3,
client_addr_deal.sin_addr.S_un.S_un_b.s_b4,
htons(client_addr_deal.sin_port));
sendto(sServer1,buff,sizeof(buff),0,(sockaddr*)&client_addr_deal,sizeof(client_addr_deal));
break;
case 8:
ncp_deal->dowhat=6;
client_addr_deal.sin_family=AF_INET;
client_addr_deal.sin_addr.S_un.S_addr=ncp_deal->ip;
client_addr_deal.sin_port=htons(ncp_deal->port);
ncp_deal->ip=getownIP_uli();
ncp_deal->port=htons(PORT_SERVER_NATCHECK);
printf("[deal][8] send[6] to:%d.%d.%d.%d:%d/n",
client_addr_deal.sin_addr.S_un.S_un_b.s_b1,
client_addr_deal.sin_addr.S_un.S_un_b.s_b2,
client_addr_deal.sin_addr.S_un.S_un_b.s_b3,
client_addr_deal.sin_addr.S_un.S_un_b.s_b4,
htons(client_addr_deal.sin_port));
sendto(sServer,buff,sizeof(buff),0,(sockaddr*)&client_addr_deal,sizeof(client_addr_deal));
break;
case 9:
//写入id 网络类型 外网ip port 内网ip port
storeNatCheckResult(ncp_deal->id,
ncp_deal->dowhat,ip_deal,port_deal,
ncp_deal->ip,ncp_deal->port);
printf("[deal][9] writing file/n");
break;
case 10:
//写入id 网络类型 外网ip port 内网ip port
storeNatCheckResult(ncp_deal->id,
ncp_deal->dowhat,ip_deal,port_deal,
ncp_deal->ip,ncp_deal->port);
printf("[deal][10] writing file/n");
break;
case 11:
//写入id 网络类型 外网ip port 内网ip port
storeNatCheckResult(ncp_deal->id,
ncp_deal->dowhat,ip_deal,port_deal,
ncp_deal->ip,ncp_deal->port);
printf("[deal][11] writing file/n");
break;
case 12:
//写入id 网络类型 外网ip port 内网ip port
storeNatCheckResult(ncp_deal->id,
ncp_deal->dowhat,ip_deal,port_deal,
ncp_deal->ip,ncp_deal->port);
printf("[deal][12] writing file/n");
break;
case 13:
//写入id 网络类型 外网ip port 内网ip port
storeNatCheckResult(ncp_deal->id,
ncp_deal->dowhat,ip_deal,port_deal,
ncp_deal->ip,ncp_deal->port);
printf("[deal][13] writing file/n");
break;
case 14:
//处理client发来的查询请求
//查询id对应用户的网络信息
client_addr_deal.sin_family=AF_INET;
client_addr_deal.sin_addr.S_un.S_addr=ip_deal;
client_addr_deal.sin_port=port_deal;
printf("[deal][14]send [15] to:%d.%d.%d.%d:%d/n",
client_addr_deal.sin_addr.S_un.S_un_b.s_b1,
client_addr_deal.sin_addr.S_un.S_un_b.s_b2,
client_addr_deal.sin_addr.S_un.S_un_b.s_b3,
client_addr_deal.sin_addr.S_un.S_un_b.s_b4,
htons(client_addr_deal.sin_port));
searchNatCheckResult(*ncp_deal,sServer,client_addr_deal);
break;
default:
break;
}
}
Sleep(300);
}
}
//////////////////
// 终止 Windows sockets API
WSACleanup();
return 0;
}