예제 #1
0
파일: d_net.c 프로젝트: HipsterLion/SRB2
// resend the data if needed
void Net_AckTicker(void)
{
#ifndef NONET
	INT32 i;

	for (i = 0; i < MAXACKPACKETS; i++)
	{
		const INT32 nodei = ackpak[i].destinationnode;
		node_t *node = &nodes[nodei];
#ifdef NEWPING
		if (ackpak[i].acknum && ackpak[i].senttime + NODETIMEOUT < I_GetTime())
#else
		if (ackpak[i].acknum && ackpak[i].senttime + node->timeout < I_GetTime())
#endif
		{
			if (ackpak[i].resentnum > 10 && (node->flags & CLOSE))
			{
				DEBFILE(va("ack %d sent 10 times so connection is supposed lost: node %d\n",
					i, nodei));
				Net_CloseConnection(nodei | FORCECLOSE);

				ackpak[i].acknum = 0;
				continue;
			}
#ifdef NEWPING
			DEBFILE(va("Resend ack %d, %u<%d at %u\n", ackpak[i].acknum, ackpak[i].senttime,
				NODETIMEOUT, I_GetTime()));
#else
			DEBFILE(va("Resend ack %d, %u<%d at %u\n", ackpak[i].acknum, ackpak[i].senttime,
				node->timeout, I_GetTime()));
#endif
			M_Memcpy(netbuffer, ackpak[i].pak.raw, ackpak[i].length);
			ackpak[i].senttime = I_GetTime();
			ackpak[i].resentnum++;
			ackpak[i].nextacknum = node->nextacknum;
			retransmit++; // for stat
			HSendPacket((INT32)(node - nodes), false, ackpak[i].acknum,
				(size_t)(ackpak[i].length - BASEPACKETSIZE));
		}
	}

	for (i = 1; i < MAXNETNODES; i++)
	{
		// this is something like node open flag
		if (nodes[i].firstacktosend)
		{
			// we haven't sent a packet for a long time
			// acknowledge packet if needed
			if (nodes[i].lasttimeacktosend_sent + ACKTOSENDTIMEOUT < I_GetTime())
				Net_SendAcks(i);

			if (!(nodes[i].flags & CLOSE)
				&& nodes[i].lasttimepacketreceived + connectiontimeout < I_GetTime())
			{
				Net_ConnectionTimeout(i);
			}
		}
	}
#endif
}
예제 #2
0
static void NET_Get(void)
{
	INT32 mystatus;
	INT32 newnode;
	mypacket.len = MAXPACKETLENGTH;
	if (!NET_CanGet())
	{
		doomcom->remotenode = -1; // no packet
		return;
	}
	mystatus = SDLNet_UDP_Recv(mysocket,&mypacket);
	if (mystatus != -1)
	{
		if (mypacket.channel != -1)
		{
			doomcom->remotenode = mypacket.channel+1; // good packet from a game player
			doomcom->datalength = mypacket.len;
			return;
		}
		newnode = SDLNet_UDP_Bind(mysocket,-1,&mypacket.address);
		if (newnode != -1)
		{
			size_t i;
			newnode++;
			M_Memcpy(&clientaddress[newnode], &mypacket.address, sizeof (IPaddress));
			DEBFILE(va("New node detected: node:%d address:%s\n", newnode,
					NET_GetNodeAddress(newnode)));
			doomcom->remotenode = newnode; // good packet from a game player
			doomcom->datalength = mypacket.len;
			for (i = 0; i < numbans; i++)
			{
				if (NET_cmpaddr(&mypacket.address, &banned[i]))
				{
					DEBFILE("This dude has been banned\n");
					NET_bannednode[newnode] = true;
					break;
				}
			}
			if (i == numbans)
				NET_bannednode[newnode] = false;
			return;
		}
		else
			CONS_Printf("SDL_Net: %s",SDLNet_GetError());
	}
	else if (mystatus == -1)
	{
		CONS_Printf("SDL_Net: %s",SDLNet_GetError());
	}

	DEBFILE("New node detected: No more free slots\n");
	doomcom->remotenode = -1; // no packet
}
예제 #3
0
// remove last packet received ack before resending the ackret
// (the higher layer doesn't have room, or something else ....)
void Net_UnAcknowledgPacket(INT32 node)
{
	INT32 hm1 = (nodes[node].acktosend_head-1+MAXACKTOSEND) % MAXACKTOSEND;
	DEBFILE(va("UnAcknowledge node %d\n", node));
	if (!node)
		return;
	if (nodes[node].acktosend[hm1] == netbuffer->ack)
	{
		nodes[node].acktosend[hm1] = 0;
		nodes[node].acktosend_head = (UINT8)hm1;
	}
	else if (nodes[node].firstacktosend == netbuffer->ack)
	{
		nodes[node].firstacktosend--;
		if (!nodes[node].firstacktosend)
			nodes[node].firstacktosend = UINT8_MAX;
	}
	else
	{
		while (nodes[node].firstacktosend != netbuffer->ack)
		{
			nodes[node].acktosend_tail = (UINT8)
				((nodes[node].acktosend_tail-1+MAXACKTOSEND) % MAXACKTOSEND);
			nodes[node].acktosend[nodes[node].acktosend_tail] = nodes[node].firstacktosend;

			nodes[node].firstacktosend--;
			if (!nodes[node].firstacktosend)
				nodes[node].firstacktosend = UINT8_MAX;
		}
		nodes[node].firstacktosend++;
		if (!nodes[node].firstacktosend)
			nodes[node].firstacktosend = 1;
	}
}
예제 #4
0
static void NET_FreeNodenum(INT32 numnode)
{
	// can't disconnect from self :)
	if (!numnode)
		return;

	DEBFILE(va("Free node %d (%s)\n", numnode, NET_GetNodeAddress(numnode)));

	SDLNet_UDP_Unbind(mysocket,numnode-1);

	memset(&clientaddress[numnode], 0, sizeof (IPaddress));
}
예제 #5
0
// return a free acknum and copy netbuffer in the ackpak table
static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
{
	node_t *node = &nodes[doomcom->remotenode];
	INT32 i, numfreeslote = 0;

	if (cmpack((UINT8)((node->remotefirstack + MAXACKTOSEND) % 256), node->nextacknum) < 0)
	{
		DEBFILE(va("too fast %d %d\n",node->remotefirstack,node->nextacknum));
		return false;
	}

	for (i = 0; i < MAXACKPACKETS; i++)
		if (!ackpak[i].acknum)
		{
			// for low priority packet, make sure let freeslotes so urgents packets can be sent
			numfreeslote++;
			if (netbuffer->packettype >= PT_CANFAIL && numfreeslote < URGENTFREESLOTENUM)
				continue;

			ackpak[i].acknum = node->nextacknum;
			ackpak[i].nextacknum = node->nextacknum;
			node->nextacknum++;
			if (!node->nextacknum)
				node->nextacknum++;
			ackpak[i].destinationnode = (UINT8)(node - nodes);
			ackpak[i].length = doomcom->datalength;
			if (lowtimer)
			{
				// lowtime mean can't be sent now so try it soon as possible
				ackpak[i].senttime = 0;
				ackpak[i].resentnum = 1;
			}
			else
			{
				ackpak[i].senttime = I_GetTime();
				ackpak[i].resentnum = 0;
			}
			M_Memcpy(ackpak[i].pak.raw, netbuffer, ackpak[i].length);

			*freeack = ackpak[i].acknum;

			sendackpacket++; // for stat

			return true;
		}
#ifdef PARANOIA
	if (devparm)
		I_OutputMsg("No more free ackpacket\n");
#endif
	if (netbuffer->packettype < PT_CANFAIL)
		I_Error("Connection lost\n");
	return false;
}
예제 #6
0
파일: i_tcp.c 프로젝트: RedEnchilada/SRB2
static void SOCK_FreeNodenum(INT32 numnode)
{
	// can't disconnect from self :)
	if (!numnode || numnode > MAXNETNODES)
		return;

	DEBFILE(va("Free node %d (%s)\n", numnode, SOCK_GetNodeAddress(numnode)));

	nodeconnected[numnode] = false;
	nodesocket[numnode] = BADSOCKET;

	// put invalid address
	memset(&clientaddress[numnode], 0, sizeof (clientaddress[numnode]));
}
예제 #7
0
파일: d_net.c 프로젝트: HipsterLion/SRB2
static void Removeack(INT32 i)
{
	INT32 node = ackpak[i].destinationnode;
#ifndef NEWPING
	fixed_t trueping = (I_GetTime() - ackpak[i].senttime)<<FRACBITS;
	if (ackpak[i].resentnum)
	{
		// +FRACUNIT/2 for round
		nodes[node].ping = (nodes[node].ping*7 + trueping)/8;
		nodes[node].varping = (nodes[node].varping*7 + abs(nodes[node].ping-trueping))/8;
		nodes[node].timeout = TIMEOUT(nodes[node].ping,nodes[node].varping);
	}
	DEBFILE(va("Remove ack %d trueping %d ping %f var %f timeout %d\n",ackpak[i].acknum,trueping>>FRACBITS,(double)FIXED_TO_FLOAT(nodes[node].ping),(double)FIXED_TO_FLOAT(nodes[node].varping),nodes[node].timeout));
#else
	DEBFILE(va("Remove ack %d\n",ackpak[i].acknum));
#endif
	ackpak[i].acknum = 0;
	if (nodes[node].flags & CLOSE)
		Net_CloseConnection(node);
}
예제 #8
0
파일: d_net.c 프로젝트: HipsterLion/SRB2
//
// HGetPacket
// Returns false if no packet is waiting
// Check Datalength and checksum
//
boolean HGetPacket(void)
{
	// get a packet from self
	if (rebound_tail != rebound_head)
	{
		M_Memcpy(netbuffer, &reboundstore[rebound_tail], reboundsize[rebound_tail]);
		doomcom->datalength = reboundsize[rebound_tail];
		if (netbuffer->packettype == PT_NODETIMEOUT)
			doomcom->remotenode = netbuffer->u.textcmd[0];
		else
			doomcom->remotenode = 0;

		rebound_tail = (rebound_tail+1) % MAXREBOUND;
#ifdef DEBUGFILE
		if (debugfile)
			DebugPrintpacket("GETLOCAL");
#endif
		return true;
	}

	if (!netgame)
		return false;

#ifndef NONET

	while(true)
	{
		I_NetGet();

		if (doomcom->remotenode == -1)
			return false;

		getbytes += packetheaderlength + doomcom->datalength; // for stat

		if (doomcom->remotenode >= MAXNETNODES)
		{
			DEBFILE(va("receive packet from node %d !\n", doomcom->remotenode));
			continue;
		}

		nodes[doomcom->remotenode].lasttimepacketreceived = I_GetTime();

		if (netbuffer->checksum != NetbufferChecksum())
		{
			DEBFILE("Bad packet checksum\n");
			Net_CloseConnection(doomcom->remotenode);
			continue;
		}

#ifdef DEBUGFILE
		if (debugfile)
			DebugPrintpacket("GET");
#endif

		// proceed the ack and ackreturn field
		if (!Processackpak())
			continue; // discarded (duplicated)

		// a packet with just ackreturn
		if (netbuffer->packettype == PT_NOTHING)
		{
			GotAcks();
			continue;
		}
		break;
	}
#endif // ndef NONET

	return true;
}
예제 #9
0
파일: d_net.c 프로젝트: HipsterLion/SRB2
//
// HSendPacket
//
boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlength)
{
	doomcom->datalength = (INT16)(packetlength + BASEPACKETSIZE);
	if (node == 0) // packet is to go back to us
	{
		if ((rebound_head+1) % MAXREBOUND == rebound_tail)
		{
#ifdef PARANOIA
			CONS_Debug(DBG_NETPLAY, "No more rebound buf\n");
#endif
			return false;
		}
		M_Memcpy(&reboundstore[rebound_head], netbuffer,
			doomcom->datalength);
		reboundsize[rebound_head] = doomcom->datalength;
		rebound_head = (rebound_head+1) % MAXREBOUND;
#ifdef DEBUGFILE
		if (debugfile)
		{
			doomcom->remotenode = (INT16)node;
			DebugPrintpacket("SENDLOCAL");
		}
#endif
		return true;
	}

	if (!netgame)
		I_Error("Tried to transmit to another node");

#ifdef NONET
	(void)node;
	(void)reliable;
	(void)acknum;
#else
	// do this before GetFreeAcknum because this function backup
	// the current packet
	doomcom->remotenode = (INT16)node;
	if (doomcom->datalength <= 0)
	{
		DEBFILE("HSendPacket: nothing to send\n");
#ifdef DEBUGFILE
		if (debugfile)
			DebugPrintpacket("TRISEND");
#endif
		return false;
	}

	if (node < MAXNETNODES) // can be a broadcast
		netbuffer->ackreturn = GetAcktosend(node);
	else
		netbuffer->ackreturn = 0;
	if (reliable)
	{
		if (I_NetCanSend && !I_NetCanSend())
		{
			if (netbuffer->packettype < PT_CANFAIL)
				GetFreeAcknum(&netbuffer->ack, true);

			DEBFILE("HSendPacket: Out of bandwidth\n");
			return false;
		}
		else if (!GetFreeAcknum(&netbuffer->ack, false))
			return false;
	}
	else
		netbuffer->ack = acknum;

	netbuffer->checksum = NetbufferChecksum();
	sendbytes += packetheaderlength + doomcom->datalength; // for stat

	// simulate internet :)
	if (true || rand()<(INT32)RAND_MAX/5)
	{
#ifdef DEBUGFILE
		if (debugfile)
			DebugPrintpacket("SEND");
#endif
		I_NetSend();
	}
#ifdef DEBUGFILE
	else if (debugfile)
		DebugPrintpacket("NOTSEND");
#endif

#endif // ndef NONET

	return true;
}
예제 #10
0
파일: d_net.c 프로젝트: HipsterLion/SRB2
// we have got a packet proceed the ack request and ack return
static boolean Processackpak(void)
{
	INT32 i;
	boolean goodpacket = true;
	node_t *node = &nodes[doomcom->remotenode];

	// received an ack return, so remove the ack in the list
	if (netbuffer->ackreturn && cmpack(node->remotefirstack, netbuffer->ackreturn) < 0)
	{
		node->remotefirstack = netbuffer->ackreturn;
		// search the ackbuffer and free it
		for (i = 0; i < MAXACKPACKETS; i++)
			if (ackpak[i].acknum && ackpak[i].destinationnode == node - nodes
				&& cmpack(ackpak[i].acknum, netbuffer->ackreturn) <= 0)
			{
				Removeack(i);
			}
	}

	// received a packet with ack, queue it to send the ack back
	if (netbuffer->ack)
	{
		UINT8 ack = netbuffer->ack;
		getackpacket++;
		if (cmpack(ack, node->firstacktosend) <= 0)
		{
			DEBFILE(va("Discard(1) ack %d (duplicated)\n", ack));
			duppacket++;
			goodpacket = false; // discard packet (duplicate)
		}
		else
		{
			// check if it is not already in the queue
			for (i = node->acktosend_tail; i != node->acktosend_head; i = (i+1) % MAXACKTOSEND)
				if (node->acktosend[i] == ack)
				{
					DEBFILE(va("Discard(2) ack %d (duplicated)\n", ack));
					duppacket++;
					goodpacket = false; // discard packet (duplicate)
					break;
				}
			if (goodpacket)
			{
				// is a good packet so increment the acknowledge number,
				// then search for a "hole" in the queue
				UINT8 nextfirstack = (UINT8)(node->firstacktosend + 1);
				if (!nextfirstack)
					nextfirstack = 1;

				if (ack == nextfirstack)
				{
					UINT8 hm1; // head - 1
					boolean change = true;

					node->firstacktosend = nextfirstack++;
					if (!nextfirstack)
						nextfirstack = 1;
					hm1 = (UINT8)((node->acktosend_head-1+MAXACKTOSEND) % MAXACKTOSEND);
					while (change)
					{
						change = false;
						for (i = node->acktosend_tail; i != node->acktosend_head;
							i = (i+1) % MAXACKTOSEND)
						{
							if (cmpack(node->acktosend[i], nextfirstack) <= 0)
							{
								if (node->acktosend[i] == nextfirstack)
								{
									node->firstacktosend = nextfirstack++;
									if (!nextfirstack)
										nextfirstack = 1;
									change = true;
								}
								if (i == node->acktosend_tail)
								{
									node->acktosend[node->acktosend_tail] = 0;
									node->acktosend_tail = (UINT8)((i+1) % MAXACKTOSEND);
								}
								else if (i == hm1)
								{
									node->acktosend[hm1] = 0;
									node->acktosend_head = hm1;
									hm1 = (UINT8)((hm1-1+MAXACKTOSEND) % MAXACKTOSEND);
								}
							}
						}
					}
				}
				else // out of order packet
				{
					// don't increment firsacktosend, put it in asktosend queue
					// will be incremented when the nextfirstack comes (code above)
					UINT8 newhead = (UINT8)((node->acktosend_head+1) % MAXACKTOSEND);
					DEBFILE(va("out of order packet (%d expected)\n", nextfirstack));
					if (newhead != node->acktosend_tail)
					{
						node->acktosend[node->acktosend_head] = ack;
						node->acktosend_head = newhead;
					}
					else // buffer full discard packet, sender will resend it
					{ // we can admit the packet but we will not detect the duplication after :(
						DEBFILE("no more freeackret\n");
						goodpacket = false;
					}
				}
			}
		}
	}
	return goodpacket;
}
예제 #11
0
파일: i_tcp.c 프로젝트: RedEnchilada/SRB2
static void SOCK_Get(void)
{
	size_t i, n;
	int j;
	ssize_t c;
	mysockaddr_t fromaddress;
	socklen_t fromlen;

	for (n = 0; n < mysocketses; n++)
	{
		fromlen = (socklen_t)sizeof(fromaddress);
		c = recvfrom(mysockets[n], (char *)&doomcom->data, MAXPACKETLENGTH, 0,
			(void *)&fromaddress, &fromlen);
		if (c != ERRSOCKET)
		{
			// find remote node number
			for (j = 0; j <= MAXNETNODES; j++) //include LAN
			{
				if (SOCK_cmpaddr(&fromaddress, &clientaddress[j], 0))
				{
					doomcom->remotenode = (INT16)j; // good packet from a game player
					doomcom->datalength = (INT16)c;
					nodesocket[j] = mysockets[n];
					return;
				}
			}
			// not found

			// find a free slot
			cleanupnodes();
			j = getfreenode();
			if (j > 0)
			{
				M_Memcpy(&clientaddress[j], &fromaddress, fromlen);
				nodesocket[j] = mysockets[n];
				DEBFILE(va("New node detected: node:%d address:%s\n", j,
						SOCK_GetNodeAddress(j)));
				doomcom->remotenode = (INT16)j; // good packet from a game player
				doomcom->datalength = (INT16)c;

				// check if it's a banned dude so we can send a refusal later
				for (i = 0; i < numbans; i++)
				{
					if (SOCK_cmpaddr(&fromaddress, &banned[i], bannedmask[i]))
					{
						SOCK_bannednode[j] = true;
						DEBFILE("This dude has been banned\n");
						break;
					}
				}
				if (i == numbans)
					SOCK_bannednode[j] = false;
				return;
			}
			else
				DEBFILE("New node detected: No more free slots\n");

		}
	}
	doomcom->remotenode = -1; // no packet
}