OpenMoHAA 0.82.0
Loading...
Searching...
No Matches
qr2.h
1#ifndef _QR2_H_
2#define _QR2_H_
3
4#include "../common/gsCommon.h"
5
6
7/**********
8qr2regkeys.h contains defines for all of the reserved keys currently available.
9***********/
10#include "qr2regkeys.h"
11
12
15#ifndef GSI_UNICODE
16#define qr2_init qr2_initA
17#define qr2_init_socket qr2_init_socketA
18#define qr2_parse_query qr2_parse_queryA
19#define qr2_buffer_add qr2_buffer_addA
20#else
21#define qr2_init qr2_initW
22#define qr2_init_socket qr2_init_socketW
23#define qr2_parse_query qr2_parse_queryW
24#define qr2_buffer_add qr2_buffer_addW
25#endif
26
27
30#ifdef __cplusplus
31extern "C" {
32#endif
33
34//no need to escape strings, more flexible querying, less bandwidth, no need to space check buffers
35
36
37/********
38ERROR CONSTANTS
39---------------
40These constants are returned from qr2_init and the error callback to signal an error condition
41***************/
42typedef enum
43{e_qrnoerror, //no error occured
44e_qrwsockerror, //a standard socket call failed (exhausted resources?)
45e_qrbinderror, //the SDK was unable to find an available port to bind on
46e_qrdnserror, //a DNS lookup (for the master server) failed
47e_qrconnerror, //the server is behind a nat and does not support negotiation
48e_qrnochallengeerror, //no challenge was received from the master - either the master is down, or a firewall is blocking UDP
49qr2_error_t_count
50} qr2_error_t;
51
52
53/********
54KEY TYPES
55---------------
56Server information is reported in key/value pairs. There are three key types:
57key_server - General information about the game in progress
58key_player - Information about a specific player
59key_team - Information about a specific team
60***************/
61typedef enum {key_server, key_player, key_team, key_type_count} qr2_key_type;
62
63/*********
64NUM_PORTS_TO_TRY
65----------------
66This value is the maximum number of ports that will be scanned to
67find an open query port, starting from the value passed to qr2_init
68as the base port. Generally there is no reason to modify this value.
69***********/
70#define NUM_PORTS_TO_TRY 100
71
72
73/*********
74MAGIC VALUES
75----------------
76These values will be used at the start of all QR2 query packets. If you are processing query
77data on your game socket, you can use these bytes to determine if a packet should be forwarded
78to the QR2 SDK for processing.
79***********/
80#define QR_MAGIC_1 0xFE
81#define QR_MAGIC_2 0xFD
82
83/* The app can resolve the master server hostname for this
84game itself and store the IP here before calling qr2_init.
85For more information, contact devsupport@gamespy.com. */
86extern char qr2_hostname[64];
87
88/***********
89qr2_t
90----
91This abstract type is used to instantiate multiple instances of the
92Query & Reporting SDK (for example, if you are running multiple servers
93in the same process).
94For most games, you can ignore this value and pass NULL in to all functions
95that require it. A single global instance will be used in this case.
96************/
97typedef struct qr2_implementation_s *qr2_t;
98
99/***********
100qr2_keybuffer_t
101---------------
102This structure is used to store a list of keys when enumerating available keys.
103Use the qr2_keybuffer_add function to add keys to the list.
104************/
105typedef struct qr2_keybuffer_s *qr2_keybuffer_t;
106
107
108/***********
109qr2_buffer_t
110------------
111This structure stores data that will be sent back to a client in response to
112a query. Use the qr2_buffer_add functions to add data to the buffer in your callbacks.
113************/
114typedef struct qr2_buffer_s *qr2_buffer_t;
115
116typedef struct qr2_ipverify_node_s *qr2_ipverify_node_t;
117
118
119/********
120qr2_serverkeycallback_t
121-------------------
122This is the prototype for one of the callback functions you will need to provide.
123The serverkey callback is called when a client requests information about a specific
124server key.
125[keyid] is the key being requested.
126[outbuf] is the destination buffer for the value information. Use qr2_buffer_add to report the value.
127[userdata] is the pointer that was passed into qr2_init. You can use this for an
128 object or structure pointer if needed.
129If you don't have a value for the provided keyid, you should add a empty ("") string to the buffer.
130********/
131typedef void (*qr2_serverkeycallback_t)(int keyid, qr2_buffer_t outbuf, void *userdata);
132
133/********
134qr2_playerteamkeycallback_t
135-------------------
136This is the prototype for two of the callback functions you will need to provide.
137The player key callback is called when a client requests information about a specific key
138for a specific player.
139The team key callback is called when a client requests the value for a team key.
140[keyid] is the key being requested.
141[index] is the 0-based index of the player or team being requested.
142[outbuf] is the destination buffer for the value information. Use qr2_buffer_add to report the value.
143[userdata] is the pointer that was passed into qr2_init. You can use this for an
144 object or structure pointer if needed.
145If you don't have a value for the provided keyid, you should add a empty ("") string to the buffer.
146********/
147typedef void (*qr2_playerteamkeycallback_t)(int keyid, int index, qr2_buffer_t outbuf, void *userdata);
148
149
150/********
151qr2_keylistcallback_t
152-------------------
153This is the prototype for one of the callback functions you will need to provide.
154The key list callback is called when the SDK needs to determine all of the keys you game has
155values for.
156[keytype] is the type of keys being requested (server, player, team). You should only add keys
157 of this type to the keybuffer.
158[keybuffer] is the structure that holds the list of keys. Use qr2_keybuffer_add to add a key
159 to the buffer.
160[userdata] is the pointer that was passed into qr2_init. You can use this for an
161 object or structure pointer if needed.
162********/
163typedef void (*qr2_keylistcallback_t)(qr2_key_type keytype, qr2_keybuffer_t keybuffer, void *userdata);
164
165
166/********
167qr2_countcallback_t
168-------------------
169This is the prototype for one of the callback functions you will need to provide.
170The count callback is used by the SDK to get a count of player or teams on the server.
171[keytype] should be used to determine whether the player or team count is being requested (key_player or key_team will be passed)
172[userdata] is the pointer that was passed into qr2_init. You can use this for an
173 object or structure pointer if needed.
174If your game does not support teams, you can return 0 for the count of teams.
175********/
176typedef int (*qr2_countcallback_t)(qr2_key_type keytype, void *userdata);
177
178/********
179qr2_adderrorcallback_t
180-------------------
181This is the prototype for one of the callback functions you will need to provide.
182The add error callback is called in response to a message from the master server indicating a problem listing the server.
183[error] is a code that can be used to determine the specific listing error.
184[errmsg] is a human-readable error string returned from the master server.
185[userdata] is the pointer that was passed into qr2_init. You can use this for an
186 object or structure pointer if needed.
187The most common error that will be returned is if the master is unable to list the server due to a firewall or proxy
188that would block incoming game packets.
189********/
190typedef void (*qr2_adderrorcallback_t)(qr2_error_t error, gsi_char *errmsg, void *userdata);
191
192
193//todo - document
194typedef void (*qr2_natnegcallback_t)(int cookie, void *userdata);
195typedef void (*qr2_clientmessagecallback_t)(gsi_char *data, int len, void *userdata);
196typedef void (*qr2_publicaddresscallback_t)(unsigned int ip, unsigned short port, void *userdata);
197typedef void (*qr2_clientconnectedcallback_t)(SOCKET gamesocket, struct sockaddr_in *remoteaddr, void *userdata);
198
199//#if defined(QR2_IP_FILTER)
200typedef void (*qr2_denyqr2responsetoipcallback_t)(void *userdata, unsigned int sender_ip, int * result);
201//#endif //#if defined(QR2_IP_FILTER)
202
203void qr2_register_natneg_callback(qr2_t qrec, qr2_natnegcallback_t nncallback);
204void qr2_register_clientmessage_callback(qr2_t qrec, qr2_clientmessagecallback_t cmcallback);
205void qr2_register_publicaddress_callback(qr2_t qrec, qr2_publicaddresscallback_t pacallback);
206void qr2_register_clientconnected_callback(qr2_t qrec, qr2_clientconnectedcallback_t cccallback);
207
208//#if defined(QR2_IP_FILTER)
209void qr2_register_denyresponsetoip_callback(qr2_t qrec, qr2_denyqr2responsetoipcallback_t dertoipcallback);
210//#endif //#if defined(QR2_IP_FILTER)
211
212
213/*****************
214QR2_REGISTER_KEY
215--------------------
216Use this function to register custom server, player, and team keys that your server reports.
217[keyid] is the ID number you have chosen for this key. The first NUM_RESERVED_KEYS (50) keys are reserved, all other
218 keyid values up to MAX_REGISTERED_KEYS (254) are available for your use.
219[key] is the string name of the key. Player keys should end in "_" (such as "score_") and team keys should end in "_t".
220All custom keys should be registered prior to calling qr2_init. Reserved keys are already registered and should not be
221passed to this function.
222*******************/
223void qr2_register_key(int keyid, const gsi_char *key);
224
225
226/************
227QR2_INIT
228--------
229This function initializes the Query and Reporting SDK and prepares the SDK to accept incoming
230queries and send heartbeats to the master server.
231[qrec] if not null, will be filled with the qr2_t instance for this server.
232 If you are not using more than one instance of the Query & Reporting SDK you
233 can pass in NULL for this value.
234[ip] is an optional parameter that determines which dotted IP address to bind to on
235 a multi-homed machine. You can pass NULL to bind to all IP addresses.
236 If your game networking supports binding to user-specified IPs, you should make sure the same IP
237 is bound by the Query and Reporting SDK.
238[baseport] is the port to accept queries on. If baseport is not available, the
239 Query and Reporting SDK will scan for an available port in the range of
240 baseport -> baseport + NUM_PORTS_TO_TRY
241 Optionally, you can pass in 0 to have a port chosen automatically
242 (makes it harder for debugging/testing).
243[gamename] is the unique gamename that you were given
244[secretkey] is your unique secret key
245[ispublic] is 1 if the server should send heartbeats to the GameSpy master server and be publicly listed,
246 If 0, the server will only be available for LAN browsing
247[natnegotiate] is 1 if the server supports GameSpy's NAT-negotiation technology (or another similar technology)
248 which allows hosting behind a NAT. If you do not support NAT-negotiation (i.e. a 3rd party handshake server),
249 pass 0 to prevent the server from being listed if it is behind a NAT that cannot be traversed by outside clients.
250[qr2_*_callback] are your callback functions, these cannot be NULL
251[userdata] is an optional, implementation specific parameter that will be
252 passed to all callback functions. Use it to store an object or structure
253 pointer if needed.
254
255Returns
256e_qrnoerror is successful, otherwise one of the qr2_error_t constants above.
257************/
258qr2_error_t qr2_init(/*[out]*/qr2_t *qrec, const gsi_char *ip, int baseport, const gsi_char *gamename, const gsi_char *secret_key,
259 int ispublic, int natnegotiate,
260 qr2_serverkeycallback_t server_key_callback,
261 qr2_playerteamkeycallback_t player_key_callback,
262 qr2_playerteamkeycallback_t team_key_callback,
263 qr2_keylistcallback_t key_list_callback,
264 qr2_countcallback_t playerteam_count_callback,
265 qr2_adderrorcallback_t adderror_callback,
266 void *userdata);
267
268/************
269QR2_INIT_SOCKET
270--------
271This version of qr2_init allows the game to specify the UDP socket to use for
272sending heartbeats and query replies. This enables the game and the QR2 SDK to
273share a single UDP socket for all networking, which can make hosting games
274behind a NAT proxy possible (see the documentation for more information).
275You must also use qr2_parse_query to pass in any data received for the QR SDK
276on the socket, since the SDK will not try to read any data off the socket directly.
277[s] is the UDP socket to use for heartbeats and query replies. It must be a valid
278 socket and should be bound to a port before calling qr_init_socket. It can be
279 blocking or non-blocking.
280[boundport] is the local port that the socket is bound to.
281All other parameters are the same as described in qr2_init.
282************/
283qr2_error_t qr2_init_socket(/*[out]*/qr2_t *qrec, SOCKET s, int boundport, const gsi_char *gamename, const gsi_char *secret_key,
284 int ispublic, int natnegotiate,
285 qr2_serverkeycallback_t server_key_callback,
286 qr2_playerteamkeycallback_t player_key_callback,
287 qr2_playerteamkeycallback_t team_key_callback,
288 qr2_keylistcallback_t key_list_callback,
289 qr2_countcallback_t playerteam_count_callback,
290 qr2_adderrorcallback_t adderror_callback,
291 void *userdata);
292
293/*******************
294QR2_THINK
295-------------------
296This function should be called somewhere in your main program loop to
297process any pending server queries and send a heartbeat if needed.
298
299Query replies are very latency sensative, so you should make sure this
300function is called at least every 100ms while your game is in progress.
301The function has very low overhead and should not cause any performance
302problems.
303Unless you are using multiple instances of the SDK, you should pass NULL
304for qrec.
305********************/
306void qr2_think(qr2_t qrec);
307
308/*******************
309QR2_PARSE_QUERY
310-------------------
311Use only with qr2_init_socket to pass in data that is destined for the Q&R SDK
312from your game socket.
313You still need to call qr2_think in your main loop, and just call this
314function whenever data is received.
315Unless you are using multiple instances of the SDK, you should pass NULL
316for qrec.
317[query] is the packet of query data received from the client.
318[len] is the length of the data
319[sender] is the address that the query is received from. The QR SDK will reply
320directly to that address using the socket provided in qr2_init_socket.
321*******************/
322void qr2_parse_query(qr2_t qrec, gsi_char *query, int len, struct sockaddr *sender);
323
324/*****************
325QR2_SEND_STATECHANGED
326--------------------
327This function forces a "statechanged" heartbeat to be sent immediately.
328Use it any time you have changed the gamestate of your game to signal the
329master to update your status.
330Unless you are using multiple instances of the SDK, you should pass NULL
331for qrec.
332*******************/
333void qr2_send_statechanged(qr2_t qrec);
334
335/*****************
336QR2_SHUTDOWN
337------------
338This function closes the sockets created in qr_init and takes care of
339any misc. cleanup. You should try to call it when before exiting the server process.
340An "exiting" statechanged heartbeat will automatically be sent to assist in quickly
341de-listing the server.
342If you pass in a qrec that was returned from qr_init, all resources associated
343with that qrec will be freed. If you passed NULL into qr_int, you can pass
344NULL in here as well.
345******************/
346void qr2_shutdown(qr2_t qrec);
347
348
349
350/*****************
351QR2_KEYBUFFER_ADD
352------------
353Use this function to add a registered key to the key buffer when asked to provide
354a list of supported keys.
355******************/
356gsi_bool qr2_keybuffer_add(qr2_keybuffer_t keybuffer, int keyid);
357
358/*****************
359QR2_BUFFER_ADD / ADD_INT
360------------
361These functions are used to add a key's value to the outgoing buffer when
362requested in a callback function.
363******************/
364gsi_bool qr2_buffer_add(qr2_buffer_t outbuf, const gsi_char *value);
365gsi_bool qr2_buffer_add_int(qr2_buffer_t outbuf, int value);
366
367
368/* for CDKey SDK integration */
369#define REQUEST_KEY_LEN 4
370#define RECENT_CLIENT_MESSAGES_TO_TRACK 10
371typedef void (*cdkey_process_t)(char *buf, int len, struct sockaddr *fromaddr);
372
373/* ip verification / spoof prevention */
374#define QR2_IPVERIFY_TIMEOUT 4000 // timeout after 4 seconds round trip time
375#define QR2_IPVERIFY_ARRAY_SIZE 200 // allowed outstanding queryies in those 4 seconds
376#define QR2_IPVERIFY_MAXDUPLICATES 5 // allow maximum of 5 requests per IP/PORT
378{
379 struct sockaddr_in addr; // addr = 0 when not in use
380 gsi_u32 challenge;
381 gsi_time createtime;
382};
383
385{
386 SOCKET hbsock;
387 char gamename[64];
388 char secret_key[64];
389 char instance_key[REQUEST_KEY_LEN];
390 qr2_serverkeycallback_t server_key_callback;
391 qr2_playerteamkeycallback_t player_key_callback;
392 qr2_playerteamkeycallback_t team_key_callback;
393 qr2_keylistcallback_t key_list_callback;
394 qr2_countcallback_t playerteam_count_callback;
395 qr2_adderrorcallback_t adderror_callback;
396 qr2_natnegcallback_t nn_callback;
397 qr2_clientmessagecallback_t cm_callback;
398 qr2_publicaddresscallback_t pa_callback;
399 qr2_clientconnectedcallback_t cc_callback;
400//#if defined(QR2_IP_FILTER)
401 qr2_denyqr2responsetoipcallback_t denyresp2_ip_callback;
402//#endif //#if defined(QR2_IP_FILTER)
403
404
405 gsi_time lastheartbeat;
406 gsi_time lastka;
407 int userstatechangerequested;
408 int listed_state;
409 int ispublic;
410 int qport;
411 int read_socket;
412 int nat_negotiate;
413 struct sockaddr_in hbaddr;
414 cdkey_process_t cdkeyprocess;
415 int client_message_keys[RECENT_CLIENT_MESSAGES_TO_TRACK];
416 int cur_message_key;
417 unsigned int publicip;
418 unsigned short publicport;
419 void *udata;
420
421 gsi_u8 backendoptions; // received from server inside challenge packet
422 struct qr2_ipverify_info_s ipverify[QR2_IPVERIFY_ARRAY_SIZE];
423};
424
425// These need to be defined, even in GSI_UNICODE MODE
426void qr2_parse_queryA(qr2_t qrec, char *query, int len, struct sockaddr *sender);
427gsi_bool qr2_buffer_addA(qr2_buffer_t outbuf, const char *value);
428qr2_error_t qr2_initA(/*[out]*/qr2_t *qrec, const char *ip, int baseport, const char *gamename, const char *secret_key,
429 int ispublic, int natnegotiate,
430 qr2_serverkeycallback_t server_key_callback,
431 qr2_playerteamkeycallback_t player_key_callback,
432 qr2_playerteamkeycallback_t team_key_callback,
433 qr2_keylistcallback_t key_list_callback,
434 qr2_countcallback_t playerteam_count_callback,
435 qr2_adderrorcallback_t adderror_callback,
436 void *userdata);
437qr2_error_t qr2_init_socketA(/*[out]*/qr2_t *qrec, SOCKET s, int boundport, const char *gamename, const char *secret_key,
438 int ispublic, int natnegotiate,
439 qr2_serverkeycallback_t server_key_callback,
440 qr2_playerteamkeycallback_t player_key_callback,
441 qr2_playerteamkeycallback_t team_key_callback,
442 qr2_keylistcallback_t key_list_callback,
443 qr2_countcallback_t playerteam_count_callback,
444 qr2_adderrorcallback_t adderror_callback,
445 void *userdata);
446
447
448#ifdef __cplusplus
449}
450#endif
451
452
453#endif
Definition qr2.c:95
Definition qr2.h:385
Definition qr2.h:378
Definition qr2.c:89