📄 ztcp.c
字号:
/*Copyright (C) 1997-2007 ZSNES Team ( zsKnight, _Demo_, pagefault, Nach )http://www.zsnes.comhttp://sourceforge.net/projects/zsneshttps://zsnes.bountysource.comThis program is free software; you can redistribute it and/ormodify it under the terms of the GNU General Public Licenseversion 2 as published by the Free Software Foundation.This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with this program; if not, write to the Free SoftwareFoundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*//**********************************************************\* ZSNES TCP/IP MODULE FOR NETWORK PLAY ** ** Coded by the ZSNES team ** TCP/IP drivers coded by _Demo_, revised by Pharos ** UDP drivers coded by _Demo_, revised by zsKnight ** Gameplay netplay implementation by zsKnight ** UDP Packet loss/out of order algorithm/implementation ** by zsKnight, assistance on normal packets by Pharos *\**********************************************************/// UDP Algorithm://// UDP Header (1 byte): 1 = Normal Packet w/ reply req, 2 = Reply Packet,// 3 = Gameplay Packet (single byte),// 4 = Gameplay Packet (larger packet), 5 = Re-request gameplay// packet//// Normal Packets:// Note: The actual implementation turned out to be quite different// than the below descriptions.// First byte contains the packet counter, followed by packet contents.// Remote will send a Reply Packet (just contains packet counter)// Each packet buffer will have a timer counter which decreases after// every 1/60 seconds (value set at start is 60). If this reaches 0// that packet will be re-sent and reset the timer value back to 60.// If the local side receives the reply packet, it will set the timer// counter to -1.//// Gameplay Packets:// Note: Gameplay counter is separate from normal packet counter.// Note2: When referring to TCP/IP, it refers to the Normal Packets above.// Each packet in TCP/IP will contain a byte counter when UDP is// enabled.// Each UDP packet will contain a byte counter, the number of packets,// then each packet will contain a byte size only if there are > 1// packets. If the packet is just one byte long and contains a value<2,// it will follow by a byte containing info on how many packets its has// been like that for (it will not go beyond 32). If the packet is// more than one byte long, it will repeat that packet as the extra// packets for the next 3 packets, with the first byte of those packets// as the byte counter of that packet, then the second as the size.// Also, the send data will be stored in a 256*32 byte buffer in case// of packet loss.// When receiving, since no UDP packets will exceed 32bytes in length,// there will be a 256*32 byte buffer and a 256 byte flag buffer.// The flag clearing pointer will move at an offset of 128 from the// actual point of the receive buffer. When it receives data from// the UDP (or TCP), if the byte count of the data matches the// receive pointer, it will just send the data directly and increase the// receive pointer. Else it will fill the buffer accordingly based on// the send data (for a maximum of 32 bytes). Then if the bit on the// flag buffer is set for the current receive pointer, return the// appropriate buffer and increase receive pointer.// In case of packet loss, if no data has been received for every 500ms, the// local side would send a re-send package request. What this would// do is let the remote side build up a package containing all the// data from the requested send point to the current receive point.// A resend request will start off with 0x00,0xFF, then the counter// number. A resent packet will start off with 0x00,0xFE, the # of// packets, then the packet data (size of packet, data). A resend will// only be done if the requested packet is within the past 64 packets.// In-game chat will be moved to a separate packet in TCP/IP#ifdef __UNIXSDL__#include "gblhdr.h"#define closesocket(A) close(A)#define CopyMemory(A,B,C) memcpy(A,B,C)#define STUB_FUNCTION fprintf(stderr,"STUB: %s at " __FILE__ ", line %d, thread %d\n",__FUNCTION__,__LINE__,getpid())#define UINT unsigned int#define WORD unsigned short#define SOCKET int#define SOCKADDR_IN struct sockaddr_in#define LPSOCKADDR struct sockaddr*#define LPHOSTENT struct hostent*#define HOSTENT struct hostent#define LPINADDR struct in_addr*#define LPIN_ADDR struct in_addr*#define SOCKET_ERROR -1#define INVALID_SOCKET -1#define ioctlsocket ioctl#define FD_SET_VAR fd_set#else#include <stdio.h>#include <time.h>#include <windows.h>#include <winsock.h>#define FD_SET_VAR FD_SET#endifint RecvPtr;int RecvPtr2;unsigned char RecvFlags[256];unsigned char RecvBuffer[256*32];int RecvBufferSize[256];int SendPtr;int SendPtr2;unsigned char SendBuffer[256*32];int SendBufferSize[256];int SendRepeated;int PrevSPacket[16];int PrevSData[16*32];int PrevSSize[16];int PrevSPtr[16];int tcperr;unsigned short portval;int UDPEnable = 1;int UDPConfig = 1;int UDPBackTrace = 6;int blahblahblah = 0;int CounterA = -1;int CounterB = -1;int UDPMode2 = 0;int packetnum,packetnumhead;int packetrecvhead;unsigned char packetdata[2048*16];unsigned char packetrdata[2048*32];int packetconfirm[256];int packetreceived[256];int packetreceivesize[256];int packetsize[256];unsigned char cpacketdata[2048+32];UINT ConnectAddr;int packettimeleft[256];int packetresent[256];int PacketCounter=0;unsigned char CLatencyVal=0;SOCKET gamesocket; /* tcp socket for the game */SOCKET serversocket; /* tcp socket when the server is listening */SOCKET ugamesocket; /* udp socket sending */SOCKET userversocket; /* udp socket listening */SOCKADDR_IN serveraddress; /* address of the server */SOCKADDR_IN ugameaddress; /* address of the server */SOCKADDR_IN userveraddress; /* address of the server */char blah[256];char remotehost[256];char hostname[50] = "IP N/A";// Function Prototypesint SendData(int dsize,unsigned char *dptr);int GetData(int dsize,unsigned char *dptr);int GetLeftUDP();/**********************************************************\* Initialize the zsnes tcpip module ** - no parameters ** - return 0 on success other value on error ** ** - no known side effects *\**********************************************************/int InitTCP(){#ifndef __UNIXSDL__ WORD versionneeded = MAKEWORD(2,2); WSADATA wsadata;#endif UDPEnable=0;#ifndef __UNIXSDL__ /* Startup winsock */ WSAStartup(versionneeded, &wsadata); /* Verify version number and exit on wrong version */ if (wsadata.wVersion != versionneeded) { return(-1); } serversocket=INVALID_SOCKET;#endif return(0);}/**********************************************************\* Deinitialize the zsnes tcpip module ** - no parameters ** ** - no known side effects *\**********************************************************/void DeInitTCP(){#ifndef __UNIXSDL__ WSACleanup();#endif}/**********************************************************\* Gets UDP Status through sending data ** - no parameters ** ** - no known side effects *\**********************************************************/void GetUDPStatus() { int retval; UDPEnable=UDPConfig; if (!UDPEnable){ blah[0]=0; retval = send(gamesocket,blah,1,0); gethostname(blah,255); retval = send(gamesocket,blah,strlen(blah),0); } else { blah[0]=1; retval = send(gamesocket,blah,1,0); gethostname(blah,255); retval = send(gamesocket,blah,strlen(&blah[1])+1,0); } retval = recv(gamesocket,blah,256,0); if (blah[0]==0) UDPEnable=0; retval = recv(gamesocket,blah,256,0);}/**********************************************************\* Connect to game server ** - parameters ** - pointer server name ** - server port ** - return 0 on success other value on error ** ** - no known side effects *\**********************************************************/int isipval(char *name){ int i=0; while(name[i]!=0){ if (!((name[i]=='.') || ((name[i]>='0') && (name[i]<='9')))) return(0); i++; } return(1);}int ConnectServer(char *servername, unsigned int port){ char blah[255]; int retval,i; LPHOSTENT host1=NULL; int yesip; packetnum = 0; packetnumhead = 0; packetrecvhead = 0; RecvPtr = 0; SendPtr = 0; RecvPtr2 = 0; SendPtr2 = 0; ConnectAddr = 0; SendRepeated = 0; for (i=0;i<16;i++) PrevSPacket[i]=0; /* get host and verify if it is valid */ yesip = isipval(servername); if (!yesip){ host1 = gethostbyname(servername); if (host1 == NULL) { return(-1); } }// return(-1); if (UDPConfig) UDPEnable = 1; if (UDPEnable) { PacketCounter=1; for (i=0;i<256;i++) {packettimeleft[i]=-1; packetconfirm[i]=1; packetreceived[i]=0; RecvFlags[i]=0;} userveraddress.sin_family = AF_INET; ugameaddress.sin_family = AF_INET; if (!yesip) { ugameaddress.sin_addr = *( (LPIN_ADDR) *host1->h_addr_list ); } else { ugameaddress.sin_addr.s_addr = inet_addr(servername); } ConnectAddr = ugameaddress.sin_addr.s_addr; userveraddress.sin_addr.s_addr = INADDR_ANY;// port++; ugameaddress.sin_port = htons((unsigned short) port); userveraddress.sin_port = htons((unsigned short) port);// port--; userversocket = socket(AF_INET, SOCK_DGRAM,0); ugamesocket = socket(AF_INET, SOCK_DGRAM,0); if (ugamesocket == INVALID_SOCKET) {#ifdef __UNIXSDL__ STUB_FUNCTION;#else tcperr=WSAGetLastError(); sprintf(blah,"Could not initialize UDP(2) : %d",tcperr); MessageBox(NULL,blah,"Error",MB_SYSTEMMODAL|MB_OK);#endif return(-2); } if (userversocket == INVALID_SOCKET) {#ifdef __UNIXSDL__ STUB_FUNCTION;#else tcperr=WSAGetLastError(); sprintf(blah,"Could not initialize UDP(2.5) : %d",tcperr); MessageBox(NULL,blah,"Error",MB_SYSTEMMODAL|MB_OK);#endif return(-2); } if (bind(userversocket,(struct sockaddr*)&userveraddress,sizeof(userveraddress))== SOCKET_ERROR) {#ifdef __UNIXSDL__ STUB_FUNCTION;#else tcperr=WSAGetLastError(); sprintf(blah,"Could not initialize UDP(16) : %d",tcperr); MessageBox(NULL,blah,"Error",MB_SYSTEMMODAL|MB_OK);#endif return(-2); }// blah[0]=1;// retval = sendto(ugamesocket,blah,1,0,(struct sockaddr*)&ugameaddress,sizeof(struct sockaddr));// if (retval == SOCKET_ERROR) return(-1); blah[0]=1; SendData(1,blah);// retval = sendto(ugamesocket,blah,5,0,(struct sockaddr*)&ugameaddress,sizeof(struct sockaddr));// blah[0]=0;// i = sizeof(struct sockaddr);// retval = recvfrom(userversocket,blah,5,0,(struct sockaddr*)&userveraddress,&i);// MessageBox(NULL,blah,// "Error",// MB_SYSTEMMODAL|MB_OK); return(0);// retval = send(gamesocket,blah,1,0);// retval = recv(gamesocket,blah,1,0); } /* create the game socket and verify if it is valid */ gamesocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (gamesocket == INVALID_SOCKET) { return(-2); } /* initialize server address */ serveraddress.sin_family = AF_INET; if (!yesip) serveraddress.sin_addr = *( (LPIN_ADDR) *host1->h_addr_list ); else serveraddress.sin_addr.s_addr = inet_addr(servername); serveraddress.sin_port = htons((unsigned short)port); /* try to connect to the server */ retval = connect( gamesocket, (LPSOCKADDR)&serveraddress, sizeof(struct sockaddr)); if (retval == SOCKET_ERROR) {#ifdef __UNIXSDL__ STUB_FUNCTION;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -