1 /*
2 * file com_query.c - client queryes for local network game
3 *
4 * $Id: com_query.c,v 1.19 2006/02/17 19:52:31 fzago Exp $
5 *
6 * Program XBLAST
7 * (C) by Oliver Vogel (e-mail: m.vogel@ndh.net)
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published
11 * by the Free Software Foundation; either version 2; or (at your option)
12 * any later version
13 *
14 * This program is distributed in the hope that it will be entertaining,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILTY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
17 * Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.
21 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 #include "xblast.h"
25
26 /*
27 * local types
28 */
29 typedef struct
30 {
31 XBCommBrowse browse;
32 char *addrRemote; /* address to connect to */
33 unsigned short port; /* port of remote address */
34 unsigned char serial; /* datagram id */
35 struct timeval tvSend; /* time of last send */
36 unsigned id; /* interface id */
37 XBBool broadcast; /* broadcast flag */
38 XBBool deleted; /* deletion flag */
39 } XBCommQuery;
40
41 /*
42 * handle replies, from either a server or from central
43 */
44 static void
HandleReply(XBCommQuery * qComm,const XBBrowseTeleReply * tele,const char * host)45 HandleReply (XBCommQuery * qComm, const XBBrowseTeleReply * tele, const char *host)
46 {
47 long msec;
48 struct timeval tv;
49 char version[32];
50
51 /* calculate ping time */
52 gettimeofday (&tv, NULL);
53 msec =
54 (tv.tv_sec - qComm->tvSend.tv_sec) * 1000L + (tv.tv_usec - qComm->tvSend.tv_usec) / 1000L;
55 /* create remote version string */
56 sprintf (version, "V%u.%u.%u", (unsigned)tele->version[0], (unsigned)tele->version[1],
57 (unsigned)tele->version[2]);
58 /* check if it is response to latest query */
59 if (tele->any.serial != qComm->serial) {
60 Dbg_Query ("received reply ignored, got serial %u, expected serial %u\n", tele->any.serial,
61 qComm->serial);
62 return;
63 }
64 /* check version and source, inform client */
65 if (((tele->version[0] == VERSION_MAJOR) && (tele->version[1] == VERSION_MINOR))
66 || (tele->frameRate == 0)) {
67 /* versions match or message */
68 if (strlen (tele->host) <= 0) {
69 /* server reply: host entry is empty/NULL */
70 Dbg_Query ("received reply for #%u - game \"%s\" at %s:%hu (%ld msec)\n",
71 tele->any.serial, tele->game, host, tele->port, msec);
72 Client_ReceiveReply (qComm->id, host, tele->port, msec, version, tele->game,
73 tele->numLives, tele->numWins, tele->frameRate);
74 }
75 else {
76 /* central reply: host entry not empty */
77 Dbg_Query ("received reply for #%u - game \"%s\" at %s:%hu (from central %ld msec)\n",
78 tele->any.serial, tele->game, tele->host, tele->port, msec);
79 Client_ReceiveReply (qComm->id, tele->host, tele->port, msec, version, tele->game,
80 tele->numLives, tele->numWins, tele->frameRate);
81 }
82 }
83 else {
84 /* versions don't match and not message */
85 if (strlen (tele->host) <= 0) {
86 /* server reply */
87 Dbg_Query
88 ("received reply for #%u - game \"%s\" at %s:%hu (%ld msec), WRONG VERSION %s\n",
89 tele->any.serial, tele->game, host, tele->port, msec, version);
90 }
91 else {
92 /* central reply */
93 Dbg_Query
94 ("received reply for #%u - game \"%s\" at %s:%hu (from central %ld msec), WRONG VERSION %s\n",
95 tele->any.serial, tele->game, tele->host, tele->port, msec, version);
96 }
97 }
98 } /* HandleReply */
99
100 /*
101 * handle received data
102 */
103 static void
ReceiveQuery(XBCommBrowse * bComm,const XBBrowseTele * tele,const char * host,unsigned short port)104 ReceiveQuery (XBCommBrowse * bComm, const XBBrowseTele * tele, const char *host,
105 unsigned short port)
106 {
107 assert (NULL != bComm);
108 assert (NULL != tele);
109 assert (NULL != host);
110 switch (tele->type) {
111 case XBBT_Reply:
112 HandleReply ((XBCommQuery *) bComm, &tele->reply, host);
113 break;
114 default:
115 Dbg_Query ("receiving invalid signal %u, ignoring\n", tele->type);
116 break;
117 }
118 } /* ReceiveQuery */
119
120 /*
121 * handle browse event
122 */
123 static XBBool
EventQuery(XBCommBrowse * bComm,XBBrowseEvent ev)124 EventQuery (XBCommBrowse * bComm, XBBrowseEvent ev)
125 {
126 #if defined(DEBUG_QUERY) || defined(WMS)
127 XBCommQuery *qComm = (XBCommQuery *) bComm;
128 unsigned id = qComm->id;
129 #endif
130 switch (ev) {
131 case XBBE_Wait:
132 Dbg_Query ("all data sent on #%u\n", id);
133 break;
134 case XBBE_Dgram:
135 Dbg_Query ("received invalid datagram on #%u, ignoring\n", id);
136 break;
137 case XBBE_Browse:
138 Dbg_Query ("received invalid browse on #%u, ignoring\n", id);
139 break;
140 case XBBE_Write:
141 Dbg_Query ("new data waits to be sent on #%u\n", id);
142 break;
143 case XBBE_Close:
144 Dbg_Query ("browse shutdown complete for #%u\n", id);
145 break;
146 default:
147 Dbg_Query ("unknown browse event on #%u, ignoring!\n", ev);
148 }
149 return XBFalse;
150 } /* EventQuery */
151
152 /*
153 * Delete handler for COMM_Query sockets
154 * frees contents of structure but not the structure itself
155 * deleted entry indicates state of the structure
156 */
157 static XBCommResult
DeleteQuery(XBComm * comm)158 DeleteQuery (XBComm * comm)
159 {
160 XBCommQuery *qComm = (XBCommQuery *) comm;
161 assert (NULL != qComm);
162 assert (!qComm->deleted);
163 Browse_Finish (&qComm->browse);
164 assert (NULL != qComm->addrRemote);
165 free (qComm->addrRemote);
166 /* mark as deleted, do *not* free qComm yet */
167 qComm->deleted = XBTrue;
168 /* inform client */
169 Client_ReceiveQueryClose (qComm->id);
170 return XCR_OK;
171 } /* DeleteQuery */
172
173 /*
174 * create broadcast socket to query for network games/central games
175 */
176 XBComm *
Query_CreateComm(unsigned id,const char * local,const char * remote,unsigned short port,XBBool broadcast)177 Query_CreateComm (unsigned id, const char *local, const char *remote, unsigned short port,
178 XBBool broadcast)
179 {
180 XBSocket *pSocket;
181 XBCommQuery *qComm;
182
183 assert (NULL != remote);
184 /* create socket */
185 pSocket = Net_BindUdp (local, 0);
186 if (NULL == pSocket) {
187 Dbg_Query ("failed to establish query socket on %s to %s:%u\n",
188 (local == NULL) ? "auto" : local, remote, port);
189 return NULL;
190 }
191 Dbg_Query ("established udp socket on %s:%u\n", Socket_HostName (pSocket, XBFalse),
192 Socket_HostPort (pSocket, XBFalse));
193 /* create communication data structure */
194 qComm = calloc (1, sizeof (*qComm));
195 assert (NULL != qComm);
196 /* set values */
197 Browse_CommInit (&qComm->browse, COMM_Query, pSocket, ReceiveQuery, EventQuery, DeleteQuery);
198 qComm->addrRemote = DupString (remote);
199 qComm->port = port;
200 qComm->serial = 0;
201 qComm->tvSend.tv_sec = 0;
202 qComm->tvSend.tv_usec = 0;
203 qComm->id = id;
204 qComm->broadcast = broadcast;
205 qComm->deleted = XBFalse;
206 /* that's all ? */
207 return &qComm->browse.comm;
208 } /* Query_CreateComm */
209
210 /*
211 * return deletion flag
212 */
213 XBBool
Query_isDeleted(XBComm * comm)214 Query_isDeleted (XBComm * comm)
215 {
216 XBCommQuery *qComm = (XBCommQuery *) comm;
217 assert (comm->type == COMM_Query);
218 assert (NULL != qComm);
219 return qComm->deleted;
220 } /* Query_isDeleted */
221
222 /*
223 * query central/lan for games
224 */
225 void
Query_Send(XBComm * comm,const struct timeval * tv)226 Query_Send (XBComm * comm, const struct timeval *tv)
227 {
228 XBBrowseTeleQuery tele;
229 XBCommQuery *qComm = (XBCommQuery *) comm;
230
231 assert (NULL != qComm);
232 assert (NULL != tv);
233 /* create browse datagram */
234 tele.any.type = XBBT_Query;
235 tele.any.serial = ++qComm->serial;
236 /* queue data */
237 Browse_Send (&qComm->browse, qComm->addrRemote, qComm->port, qComm->broadcast, &tele.any);
238 /* mark time */
239 qComm->tvSend = *tv;
240 Dbg_Query ("queued query #%u to %s:%hu\n", qComm->serial, qComm->addrRemote, qComm->port);
241 } /* Query_Send */
242
243 /*
244 * end of file com_query.c
245 */
246