1 /*
2 * file com_dg_server.c - send ingame datagrams to server
3 *
4 * $Id: com_dg_server.c,v 1.16 2006/02/18 21:40:02 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 * locals typedefs
28 */
29 typedef struct
30 {
31 XBCommDgram dgram;
32 } XBCommDgramServer;
33
34 /***********
35 * handler *
36 ***********/
37
38 /*
39 * client received ping or times from server
40 */
41 static void
ReceivePing(XBCommDgram * dComm,unsigned clientID,unsigned short pingTime)42 ReceivePing (XBCommDgram * dComm, unsigned clientID, unsigned short pingTime)
43 {
44 if (0 == clientID) {
45 /* server wants a reply */
46 Dbg_D2S ("server requests ping, queueing ping\n");
47 Dgram_SendPing (dComm);
48 }
49 else {
50 /* we have received the ping time of a client */
51 if (pingTime < 0xFFFE) {
52 Client_ReceivePingTime (clientID, (int)((unsigned)pingTime));
53 Dbg_D2S ("server sends pingtime for client %u (%u)\n", clientID, pingTime);
54 }
55 else {
56 Client_ReceivePingTime (clientID, -1);
57 }
58 }
59 dComm->connected = XBTrue;
60 } /* ReceivePing */
61
62 /*
63 * client encountered some event while parsing
64 * return XBTrue will trigger delete handler
65 */
66 static XBBool
ReceiveInfo(XBCommDgram * dgram,XBDgramInfo info)67 ReceiveInfo (XBCommDgram * dgram, XBDgramInfo info)
68 {
69 assert (dgram != NULL);
70 switch (info) {
71 case XBDI_CONFAIL:
72 Dbg_D2S ("failed to connect to server!\n");
73 return (Client_DgramEvent (XBCC_ConnFailed));
74 case XBDI_CONSUCC:
75 Dbg_D2S ("udp connection established to server!\n");
76 return (Client_DgramEvent (XBCC_ConnFailed));
77 case XBDI_LOSS:
78 Dbg_D2S ("data loss from server!\n");
79 return (Client_DgramEvent (XBCC_Loss));
80 case XBDI_FINISH:
81 Dbg_D2S ("receive FINISH from server!\n");
82 Client_ReceiveFinish ();
83 return XBFalse;
84 case XBDI_IGNORE:
85 Dbg_D2S ("gametime %lu from server ignored\n", (unsigned long)dgram->ignore);
86 return XBFalse;
87 case XBDI_PARSED:
88 Dbg_D2S ("Frames parsed [%lu,%lu]\n", (unsigned long)dgram->rcvfirst, (unsigned long)dgram->rcvnext - 1);
89 dgram->queue = dgram->rcvfirst;
90 return XBFalse;
91 case XBDI_WRITEERR:
92 Dbg_D2S ("write error to server!\n");
93 return (Client_DgramEvent (XBCC_WriteError));
94 case XBDI_CLOSE:
95 Dbg_D2C ("udp to server removed\n");
96 return (Client_DgramEvent (XBCC_DgramClosed));
97 default:
98 Dbg_D2S ("unrecognized dgram info!\n");
99 return XBFalse;
100 }
101 } /* ReceiveInfo */
102
103 /*
104 * client received player actions from server
105 */
106 static void
ReceivePlayerAction(XBCommDgram * dComm,int gameTime,const PlayerAction * playerAction)107 ReceivePlayerAction (XBCommDgram * dComm, int gameTime, const PlayerAction * playerAction)
108 {
109 Dbg_D2S ("actions for gt=%u received from server\n", gameTime);
110 Client_ReceivePlayerAction (gameTime, playerAction);
111 } /* ReceivePlayerAction */
112
113 /***************
114 * constructor *
115 ***************/
116
117 /*
118 * create datagram connection server
119 */
120 XBComm *
D2S_CreateComm(const char * localname,const char * hostname,unsigned short port)121 D2S_CreateComm (const char *localname, const char *hostname, unsigned short port)
122 {
123 XBCommDgramServer *dComm;
124 XBSocket *pSocket;
125
126 /* create socket */
127 pSocket = Net_BindUdp (localname, 0);
128 if (NULL == pSocket) {
129 Dbg_D2S ("failed to create udp to server\n");
130 return NULL;
131 }
132 Dbg_D2S ("created udp to server\n");
133 /* connect it */
134 if (!Net_ConnectUdp (pSocket, hostname, port)) {
135 Net_Close (pSocket);
136 Dbg_D2S ("failed to connect udp to server %s:%u\n", hostname, port);
137 return NULL;
138 }
139 Dbg_D2S ("connected to server %s:%u\n", hostname, port);
140 /* create communication data structure */
141 dComm = calloc (1, sizeof (*dComm));
142 assert (NULL != dComm);
143 /* set values */
144 Dgram_CommInit (&dComm->dgram, COMM_DgServer, pSocket, ReceivePing, ReceiveInfo,
145 ReceivePlayerAction);
146 /* that's all */
147 return &dComm->dgram.comm;
148 } /* D2C_CreateComm */
149
150 /******************
151 * get local data *
152 ******************/
153
154 /*
155 * get port for client
156 */
157 unsigned short
D2S_Port(const XBComm * comm)158 D2S_Port (const XBComm * comm)
159 {
160 return Dgram_Port ((const XBCommDgram *) comm);
161 } /* D2C_Port */
162
163 /******************
164 * set local data *
165 ******************/
166
167 /*
168 * reset datagram connection
169 */
170 void
D2S_Reset(XBComm * comm)171 D2S_Reset (XBComm * comm)
172 {
173 Dbg_D2S ("resetting frames for server\n");
174 Dgram_Reset ((XBCommDgram *) comm);
175 } /* D2S_Reset */
176
177 /*
178 * set mask bytes
179 */
180 void
D2S_SetMaskBytes(XBComm * comm,unsigned num)181 D2S_SetMaskBytes (XBComm * comm, unsigned num)
182 {
183 Dbg_D2S ("setting mask bytes to %u\n", num);
184 Dgram_SetMaskBytes ((XBCommDgram *) comm, num);
185 } /* D2S_SetMaskBytes */
186
187 /*
188 * check for datagram timeout
189 */
190 XBBool
D2S_Timeout(const XBComm * comm,const struct timeval * tv)191 D2S_Timeout (const XBComm * comm, const struct timeval *tv)
192 {
193 const XBCommDgram *dgram = (const XBCommDgram *) comm;
194 assert (NULL != dgram);
195 assert (NULL != tv);
196 return (0 != dgram->lastSnd.tv_sec && tv->tv_sec - dgram->lastSnd.tv_sec > LINK_LOST);
197 } /* D2S_Timeout */
198
199 /*
200 * check if server is already connected (i.e. has send a datagram)
201 */
202 XBBool
D2S_Connected(const XBComm * comm)203 D2S_Connected (const XBComm * comm)
204 {
205 const XBCommDgram *dgram = (const XBCommDgram *) comm;
206 assert (NULL != dgram);
207 return dgram->connected;
208 } /* D2S_Connected */
209
210 /**************
211 * queue data *
212 **************/
213
214 /*
215 * send connect datagram to server
216 */
217 void
D2S_SendConnect(XBComm * comm)218 D2S_SendConnect (XBComm * comm)
219 {
220 if (comm != NULL) {
221 Dgram_SendPing ((XBCommDgram *) comm);
222 }
223 } /* D2S_SendConnect */
224
225 /*
226 * send player action to client
227 */
228 void
D2S_SendPlayerAction(XBComm * comm,int gameTime,const PlayerAction * playerAction)229 D2S_SendPlayerAction (XBComm * comm, int gameTime, const PlayerAction * playerAction)
230 {
231 if (comm != NULL) {
232 Dbg_D2S ("queueing action for gt=%u to server\n", gameTime);
233 Dgram_SendPlayerAction ((XBCommDgram *) comm, gameTime, playerAction);
234 }
235 } /* D2C_SendPlayerAction */
236
237 /*
238 * acknowledge level finish
239 */
240 void
D2S_SendFinish(XBComm * comm,int gameTime)241 D2S_SendFinish (XBComm * comm, int gameTime)
242 {
243 if (comm != NULL) {
244 Dbg_D2S ("queueing FINISH for server\n");
245 Dgram_SendFinish ((XBCommDgram *) comm, gameTime);
246 }
247 } /* D2S_SendFinish */
248
249 /*
250 * flush data - resend last send unless acknowledged by remote
251 */
252 XBBool
D2S_Flush(XBComm * comm)253 D2S_Flush (XBComm * comm)
254 {
255 XBCommDgram *dgram = (XBCommDgram *) comm;
256 assert (NULL != dgram);
257 /* for client, last send acknowledged if last receive larger than last sent */
258 if (dgram->rcvnext > dgram->sndnext) {
259 return XBFalse;
260 }
261 Dbg_D2S ("resending frames to server\n");
262 return Dgram_Flush (dgram);
263 } /* D2S_Flush */
264
265 /*
266 * end of file com_dg_server.c
267 */
268