File: gt2Connection.c

package info (click to toggle)
openmohaa 0.82.1%2Bdfsg-1
  • links: PTS, VCS
  • area: contrib
  • in suites: forky, sid
  • size: 34,192 kB
  • sloc: cpp: 315,720; ansic: 275,789; sh: 312; xml: 246; asm: 141; makefile: 7
file content (343 lines) | stat: -rw-r--r-- 7,764 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
/*
GameSpy GT2 SDK
Dan "Mr. Pants" Schoenblum
dan@gamespy.com

Copyright 2002 GameSpy Industries, Inc

devsupport@gamespy.com
*/

#include "gt2Connection.h"
#include "gt2Socket.h"
#include "gt2Message.h"
#include "gt2Callback.h"
#include "gt2Utility.h"
#include <stdlib.h>

GT2Result gti2NewOutgoingConnection(GT2Socket socket, GT2Connection * connection, unsigned int ip, unsigned short port)
{
	GT2Result result;

	// create the object
	result = gti2NewSocketConnection(socket, connection, ip, port);
	if(result != GT2Success)
		return result;

	// set initial states
	(*connection)->state = GTI2AwaitingServerChallenge;
	(*connection)->initiated = GT2True;

	return GT2Success;
}

GT2Result gti2NewIncomingConnection(GT2Socket socket, GT2Connection * connection, unsigned int ip, unsigned short port)
{
	GT2Result result;

	// create the object
	result = gti2NewSocketConnection(socket, connection, ip, port);
	if(result != GT2Success)
		return result;

	// set initial states
	(*connection)->state = GTI2AwaitingClientChallenge;
	(*connection)->initiated = GT2False;

	return GT2Success;
}

GT2Result gti2StartConnectionAttempt
(
	GT2Connection connection,
	const GT2Byte * message,
	int len,
	GT2ConnectionCallbacks * callbacks
)
{
	char challenge[GTI2_CHALLENGE_LEN];

	// check the message and len
	gti2MessageCheck(&message, &len);

	// copy off the message
	if(len > 0)
	{
		connection->initialMessage = (char *)gsimalloc((unsigned int)len);
		if(!connection->initialMessage)
			return GT2OutOfMemory;

		memcpy(connection->initialMessage, message, (unsigned int)len);
		connection->initialMessageLen = len;
	}

	// copy the callbacks
	if(callbacks)
		connection->callbacks = *callbacks;

	// generate a challenge
	gti2GetChallenge((GT2Byte *)challenge);

	// generate and store the expected response
	gti2GetResponse((GT2Byte *)connection->response, (GT2Byte *)challenge);

	// send the client challenge
	gti2SendClientChallenge(connection, challenge);

	// update our state
	connection->state = GTI2AwaitingServerChallenge;

	return GT2Success;
}

GT2Bool gti2AcceptConnection(GT2Connection connection, GT2ConnectionCallbacks * callbacks)
{
	// was the connection already closed?
	if(connection->freeAtAcceptReject)
	{
		// clear the flag
		connection->freeAtAcceptReject = GT2False;

		// let the app know if was already closed
		return GT2False;
	}

	// make sure this flag gets cleared
	connection->freeAtAcceptReject = GT2False;

	// check that we're still awaiting this
	if(connection->state != GTI2AwaitingAcceptReject)
		return GT2False;

	// let the other side know
	gti2SendAccept(connection);

	// update our state
	connection->state = GTI2Connected;

	// store the callbacks
	if(callbacks)
		connection->callbacks = *callbacks;

	return GT2True;
}

void gti2RejectConnection(GT2Connection connection, const GT2Byte * message, int len)
{
	// make sure this flag gets cleared
	connection->freeAtAcceptReject = GT2False;

	// check that we're still awaiting this
	if(connection->state != GTI2AwaitingAcceptReject)
		return;

	// check the message and len
	gti2MessageCheck(&message, &len);

	// let the other side know
	gti2SendReject(connection, message, len);

	// update our state
	connection->state = GTI2Closing;
}

GT2Bool gti2ConnectionSendData(GT2Connection connection, const GT2Byte * message, int len)
{
	// send the data on the socket
	if(!gti2SocketSend(connection->socket, connection->ip, connection->port, message, len))
		return GT2False;

	// mark the time (used for keep-alives)
	connection->lastSend = current_time();

	return GT2True;
}

static GT2Bool gti2CheckTimeout(GT2Connection connection, gsi_time now)
{
	// are we still trying to connect?
	if(connection->state < GTI2Connected)
	{
		GT2Bool timedOut = GT2False;

		// is this the initiator
		if(connection->initiated)
		{
			// do we have a timeout?
			if(connection->timeout)
			{
				// check the time taken against the timeout
				if((now - connection->startTime) > connection->timeout)
					timedOut = GT2True;
			}
		}
		else
		{
			// don't time them out if they're waiting for us
			if(connection->state < GTI2AwaitingAcceptReject)
			{
				// check the time taken against the timeout
				if((now - connection->startTime) > GTI2_SERVER_TIMEOUT)
					timedOut = GT2True;
			}
		}

		// check if we timed out
		if(timedOut)
		{
			// let them know
			gti2SendClosed(connection);

			// mark it as closed
			gti2ConnectionClosed(connection);

			// call the callback
			if(!gti2ConnectedCallback(connection, GT2TimedOut, NULL, 0))
				return GT2False;
		}
	}

	return GT2True;
}

static GT2Bool gti2SendRetries(GT2Connection connection, gsi_time now)
{
	int i;
	int len;
	GTI2OutgoingBufferMessage * message;

	// go through the list of outgoing messages awaiting confirmation
	len = ArrayLength(connection->outgoingBufferMessages);
	for(i = 0 ; i < len ; i++)
	{
		// get the message
		message = (GTI2OutgoingBufferMessage *)ArrayNth(connection->outgoingBufferMessages, i);

		// check if it's time to resend it
		if((now - message->lastSend) > GTI2_RESEND_TIME)
		{
			if(!gti2ResendMessage(connection, message))
				return GT2False;
		}
	}

	return GT2True;
}

static GT2Bool gti2CheckPendingAck(GT2Connection connection, gsi_time now)
{
	// check for nothing pending
	if(!connection->pendingAck)
		return GT2True;

	// check how long it has been pending
	if((now - connection->pendingAckTime) > GTI2_PENDING_ACK_TIME)
	{
		if(!gti2SendAck(connection))
			return GT2False;
	}

	return GT2True;
}

static GT2Bool gti2CheckKeepAlive(GT2Connection connection, gsi_time now)
{
	if((now - connection->lastSend) > GTI2_KEEP_ALIVE_TIME)
	{
		if(!gti2SendKeepAlive(connection))
			return GT2False;
	}

	return GT2True;
}

GT2Bool gti2ConnectionThink(GT2Connection connection, gsi_time now)
{
	// check timeout
	if(!gti2CheckTimeout(connection, now))
		return GT2False;

	// check keep alives
	if(!gti2CheckKeepAlive(connection, now))
		return GT2False;

	// send retries
	if(!gti2SendRetries(connection, now))
		return GT2False;

	// check the pending ack
	if(!gti2CheckPendingAck(connection, now))
		return GT2False;

	return GT2True;
}

void gti2CloseConnection(GT2Connection connection, GT2Bool hard)
{
	// check if it should be hard or soft closed
	if(hard)
	{
		// check if it's already closed
		if(connection->state >= GTI2Closed)
			return;

		// mark it as closed
		gti2ConnectionClosed(connection);

		// send a closed message
		gti2SendClosed(connection);

		// call the callback
		gti2ClosedCallback(connection, GT2LocalClose);

		// try and free it
		gti2FreeSocketConnection(connection);
	}
	else
	{
		// mark it as closing
		connection->state = GTI2Closing;

		// send the close
		gti2SendClose(connection);
	}
}

void gti2ConnectionClosed(GT2Connection connection)
{
	// check for already closed
	if(connection->state == GTI2Closed)
		return;

	// mark the connection as closed
	connection->state = GTI2Closed;

	// remove it from the connected list
	TableRemove(connection->socket->connections, &connection);

	// add it to the closed list
	ArrayAppend(connection->socket->closedConnections, &connection);
}

void gti2ConnectionCleanup(GT2Connection connection)
{
	if(connection->initialMessage)
		gsifree(connection->initialMessage);

	if(connection->incomingBuffer.buffer)
		gsifree(connection->incomingBuffer.buffer);
	if(connection->outgoingBuffer.buffer)
		gsifree(connection->outgoingBuffer.buffer);

	if(connection->incomingBufferMessages)
		ArrayFree(connection->incomingBufferMessages);
	if(connection->outgoingBufferMessages)
		ArrayFree(connection->outgoingBufferMessages);
	
	if(connection->sendFilters)
		ArrayFree(connection->sendFilters);
	if(connection->receiveFilters)
		ArrayFree(connection->receiveFilters);

	gsifree(connection);
}