NAT检测的类

NAT检测的类
2010年09月10日
  // NatCheck.cpp : Defines the entry point for the console application.
  // #include "stdafx.h"
  #include
  #include
  #include
  #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)) 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)) 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_NatCheckRequestQ ueue)
  {
  //先修改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*)&c lient_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\tp ort:%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)ip;
  printf("[rece][sn(%s)]\n\tversion:%d\tdowhat:%d\tp ort:%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\tp ort:%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)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,(sock addr*)&addr,sizeof(addr));
  }
  fclose(fp_n);
  return 1;
  }
  /*
  * main函数
  */
  int main(int argc, char* argv[])
  {
  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)) 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))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_sen d)==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_sen d)==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_se nd)==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)) 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)) SOCKET号上!!!\n");
  closesocket(sServer1);
  return 0;
  }
  //
  // 循环队列natCheckRequestQueue初始化
  for(i=0;incp;
  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*)&cli ent_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*)&cli ent_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*)&cli ent_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*)&cl ient_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*)&cli ent_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;
  }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值