1 /*
2  * file com_to_central.c - handle communications with centrals
3  *
4  * $Id: com_to_central.c,v 1.7 2006/02/09 21:21:23 fzago Exp $
5  *
6  * Program XBLAST
7  * (C) by Oliver Vogel (e-mail: m.vogel@ndh.net)
8  * Added by Koen De Raedt for central support
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published
12  * by the Free Software Foundation; either version 2; or (at your option)
13  * any later version
14  *
15  * This program is distributed in the hope that it will be entertaining,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILTY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
18  * Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License along
21  * with this program; if not, write to the Free Software Foundation, Inc.
22  * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23  */
24 
25 #include "xblast.h"
26 
27 /*
28  * local types
29  */
30 typedef struct
31 {
32 	XBCommStream stream;
33 } XBCommToCentral;
34 
35 /*
36  * local variables
37  */
38 
39 /*
40  * central sends data
41  */
42 static XBCommResult
HandleDataAvailable(XBCommStream * toCentral,const XBTelegram * tele)43 HandleDataAvailable (XBCommStream * toCentral, const XBTelegram * tele)
44 {
45 	const void *data;
46 	size_t len;
47 	assert (toCentral != NULL);
48 	/* get telegramm data */
49 	data = Net_TeleData (tele, &len);
50 	switch (Net_TeleID (tele)) {
51 	case XBT_ID_PlayerConfig:
52 		/* Dbg_X2C("receiving player config from central\n"); */
53 		User_ReceivePlayerConfig (data);
54 		break;
55 	case XBT_ID_PID:
56 		Dbg_X2C ("receiving pid from central\n");
57 		User_ReceivePlayerPID (data);
58 		break;
59 	default:
60 		Dbg_X2C ("unsupported ID received for DataAvailable\n");
61 		return User_EventToCentral (XBE2C_InvalidID);;
62 	}
63 	return XCR_OK;
64 }								/* HandleDataAvailable */
65 
66 /*
67  * central sends end of data
68  */
69 static XBCommResult
HandleDataNotAvailable(XBCommStream * toCentral,const XBTelegram * tele)70 HandleDataNotAvailable (XBCommStream * toCentral, const XBTelegram * tele)
71 {
72 	switch (Net_TeleID (tele)) {
73 	case XBT_ID_PlayerConfig:
74 		Dbg_X2C ("No more players, disconnecting\n");
75 		User_NoMorePlayers ();
76 		break;
77 	case XBT_ID_PID:
78 		break;
79 	default:
80 		Dbg_X2C ("unsupported ID received for DataNotAvailable\n");
81 		return User_EventToCentral (XBE2C_InvalidID);;
82 	}
83 	return XCR_OK;
84 }								/* HandleDataAvailable */
85 
86 /*
87  * handle telegrams from central
88  */
89 static XBCommResult
HandleTelegram(XBCommStream * stream,const XBTelegram * tele)90 HandleTelegram (XBCommStream * stream, const XBTelegram * tele)
91 {
92 	assert (stream != NULL);
93 	switch (Net_TeleCOT (tele)) {
94 		/* central sends requested data */
95 	case XBT_COT_DataAvailable:
96 		return HandleDataAvailable (stream, tele);
97 		/* central has not requested data */
98 	case XBT_COT_DataNotAvailable:
99 		return HandleDataNotAvailable (stream, tele);
100 	default:
101 		Dbg_X2C ("unsupported CoT received\n");
102 		return User_EventToCentral (XBE2C_InvalidCot);;
103 	}
104 }								/* HandleTelegram */
105 
106 /*
107  * delete handler
108  */
109 static XBCommResult
DeleteToCentral(XBComm * comm)110 DeleteToCentral (XBComm * comm)
111 {
112 	/* delete stream */
113 	Stream_CommFinish ((XBCommStream *) comm);
114 	/* delete structure */
115 	free (comm);
116 	Dbg_X2C ("tcp connection to central removed\n");
117 	return XCR_OK;
118 }								/* DeleteToCentral */
119 
120 /*
121  * handle stream events
122  */
123 static XBBool
EventToCentral(XBCommStream * comm,const XBStreamEvent ev)124 EventToCentral (XBCommStream * comm, const XBStreamEvent ev)
125 {
126 	switch (ev) {
127 	case XBST_IOREAD:
128 		Dbg_X2C ("read error from central\n");
129 		return User_EventToCentral (XBE2C_IORead);
130 	case XBST_IOWRITE:
131 		Dbg_X2C ("write error to central\n");
132 		return User_EventToCentral (XBE2C_IOWrite);
133 	case XBST_EOF:
134 		Dbg_X2C ("eof from central\n");
135 		return User_EventToCentral (XBE2C_UnexpectedEOF);
136 	case XBST_WAIT:
137 		Dbg_X2C ("all data sent to central\n");
138 		return User_EventToCentral (XBE2C_StreamWaiting);
139 	case XBST_BUSY:
140 		/* Dbg_X2C("data waits to be sent to central\n"); */
141 		return User_EventToCentral (XBE2C_StreamBusy);
142 	case XBST_CLOSE:
143 		Dbg_X2C ("connection to central has been removed\n");
144 		(void)User_EventToCentral (XBE2C_StreamClosed);
145 		return XBFalse;
146 	default:
147 		Dbg_X2C ("unknown stream event on socket to central, ignoring\n");
148 		return XBFalse;
149 	}
150 }								/* EventToCentral */
151 
152 /*
153  * create a tcp connection to central
154  */
155 XBComm *
X2C_CreateComm(const CFGCentralSetup * cfg)156 X2C_CreateComm (const CFGCentralSetup * cfg)
157 {
158 	XBSocket *pSocket;
159 	XBCommToCentral *toCentral;
160 
161 	assert (cfg != NULL);
162 	/* create connection to server */
163 	pSocket = Net_ConnectInet (cfg->name, cfg->port);
164 	if (NULL == pSocket) {
165 		Dbg_X2C ("failed to create tcp socket\n");
166 		return NULL;
167 	}
168 	Dbg_X2C ("tcp connection to central %s:%u established\n", cfg->name, cfg->port);
169 	/* create communication data structure */
170 	toCentral = calloc (1, sizeof (*toCentral));
171 	assert (NULL != toCentral);
172 	/* set values */
173 	Stream_CommInit (&toCentral->stream, COMM_ToCentral, pSocket, HandleTelegram, EventToCentral,
174 					 DeleteToCentral);
175 	/* that's all */
176 	return &toCentral->stream.comm;
177 }								/* CommCreateToServer */
178 
179 /**************
180  * local data *
181  **************/
182 
183 /*
184  * return remote address in dot-representation
185  */
186 const char *
X2C_CentralName(XBComm * comm)187 X2C_CentralName (XBComm * comm)
188 {
189 	return Net_RemoteName (comm->socket);
190 }								/* X2C_CentralName */
191 
192 /*
193  * return local address in dot-representation
194  */
195 const char *
X2C_LocalName(XBComm * comm)196 X2C_LocalName (XBComm * comm)
197 {
198 	return Net_LocalName (comm->socket);
199 }								/* X2C_LocalName */
200 
201 /**************
202  * queue data *
203  **************/
204 
205 /*
206  * query player config from central
207  */
208 void
X2C_QueryPlayerConfig(XBComm * comm)209 X2C_QueryPlayerConfig (XBComm * comm)
210 {
211 	XBCommStream *stream = (XBCommStream *) comm;
212 
213 	/* sanity check */
214 	assert (stream != NULL);
215 	assert (stream->sndQueue != NULL);
216 	/* send data */
217 	Socket_RegisterWrite (CommSocket (&stream->comm));
218 	Net_SendTelegram (stream->sndQueue,
219 					  Net_CreateTelegram (XBT_COT_RequestData, XBT_ID_PlayerConfig, 0, NULL, 0));
220 	Dbg_X2C ("queued player query to central\n");
221 }								/* X2C_QueryPlayerConfig */
222 
223 /*
224  * send game config to central
225  */
226 void
X2C_SendPlayerConfig(XBComm * comm,XBAtom atom)227 X2C_SendPlayerConfig (XBComm * comm, XBAtom atom)
228 {
229 	XBCommStream *stream = (XBCommStream *) comm;
230 
231 	/* sanity check */
232 	assert (stream != NULL);
233 	assert (stream->sndQueue != NULL);
234 	/* send database section */
235 	Socket_RegisterWrite (CommSocket (&stream->comm));
236 	SendPlayerConfig (CT_Local, stream->sndQueue, XBT_COT_SendData, 0, atom, XBTrue);
237 	Dbg_X2C ("queued player config to central\n");
238 }								/* X2C_SendPlayerConfig */
239 
240 /*
241  * send game config to central
242  */
243 void
X2C_SendGameStat(XBComm * comm,int numPlayers,int * PID,int * Score)244 X2C_SendGameStat (XBComm * comm, int numPlayers, int *PID, int *Score)
245 {
246 	XBCommStream *stream = (XBCommStream *) comm;
247 	char tmp[256];
248 	int i;
249 	/* sanity check */
250 	assert (stream != NULL);
251 	assert (stream->sndQueue != NULL);
252 	/* queue data */
253 	memcpy (tmp, &numPlayers, 4);
254 	for (i = 0; i < numPlayers; i++) {
255 		memcpy (tmp + 4 + i * 8, PID + i, 4);
256 		memcpy (tmp + 8 + i * 8, Score + i, 4);
257 	}
258 	Socket_RegisterWrite (CommSocket (&stream->comm));
259 	Net_SendTelegram (stream->sndQueue,
260 					  Net_CreateTelegram (XBT_COT_SendData, XBT_ID_GameStat, 0, tmp,
261 										  4 + numPlayers * 8));
262 	Dbg_X2C ("queued game stat to central\n");
263 }								/* X2C_SendGameStat */
264 
265 /*
266  * send request for disconnect to central
267  */
268 void
X2C_SendDisconnect(XBComm * comm)269 X2C_SendDisconnect (XBComm * comm)
270 {
271 	XBCommStream *stream = (XBCommStream *) comm;
272 
273 	/* inform host about disconnect request */
274 	Socket_RegisterWrite (CommSocket (&stream->comm));
275 	Net_SendTelegram (stream->sndQueue,
276 					  Net_CreateTelegram (XBT_COT_Spontaneous, XBT_ID_HostDisconnected, 0, NULL,
277 										  0));
278 	Net_SendTelegram (stream->sndQueue,
279 					  Net_CreateTelegram (XBT_COT_Activate, XBT_ID_RequestDisconnect, 0, NULL, 0));
280 	/* clear the communication, prepare for automatic shutdown */
281 	stream->prepFinish = XBTrue;
282 	Dbg_X2C ("queued disconnect sequence to central\n");
283 }								/* X2C_SendDisconnect */
284 
285 /*
286  * end of file com_to_central.c
287  */
288