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