3 * Daniel Nelson - 8/30/0
5 * Copyright (C) 2000 Daniel Nelson
6 * Copyright (C) 2004 Andrew Sayman
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 * Daniel Nelson - aluminumangel.org
26 * Handles all that socket stuff. We should be more worried about the size of
27 * integers on various systems.
32 #include <sys/types.h>
37 # include <sys/socket.h>
38 # include <sys/poll.h>
39 # include <netinet/in.h>
41 # include <arpa/inet.h>
44 # include <winsock2.h>
45 # define sleep(x) Sleep(x)
51 #include "Communicator.h"
52 #include "Displayer.h"
53 #include "GarbageGenerator.h"
54 #include "GarbageFlavorImage.h"
55 #include "LevelLights.h"
56 #include "MetaState.h"
59 int Communicator::comm_link
;
60 int Communicator::time_step
;
61 bool Communicator::comm_link_active
;
62 bool Communicator::no_communication
;
63 bool Communicator::have_communicated
;
64 int Communicator::last_recv_sync
;
65 int Communicator::last_own_sync
;
66 CommunicationBuffer
Communicator::send_buffer
;
67 CommunicationBuffer
Communicator::recv_buffer
;
68 CommunicationBuffer
Communicator::work_buffer
;
69 bool Communicator::win_ties
;
70 char Communicator::opponent_name
[GC_PLAYER_NAME_LENGTH
];
72 void Communicator::startupExchange ( char player_name
[GC_PLAYER_NAME_LENGTH
] )
75 commSend(player_name
, GC_PLAYER_NAME_LENGTH
);
76 commRecv(opponent_name
, GC_PLAYER_NAME_LENGTH
);
78 // notify if we have a personal garbage flavor image
79 uint32 flag
= GarbageFlavorImage::personalGarbageFlavorImageExists();
84 GLubyte
*texture
= GarbageFlavorImage::loadPersonalGarbageFlavorImage();
85 commSend(texture
, 4 * DC_GARBAGE_TEX_LENGTH
* DC_GARBAGE_TEX_LENGTH
90 if (texture
!= null
) {
97 // check to see if they have a personal garbage flavor image
102 GLubyte texture
[4 * DC_GARBAGE_TEX_LENGTH
* DC_GARBAGE_TEX_LENGTH
];
103 commRecv(texture
, 4 * DC_GARBAGE_TEX_LENGTH
* DC_GARBAGE_TEX_LENGTH
105 GarbageFlavorImage::handleNetworkGarbageFlavorImage(texture
);
109 void Communicator::initialize ( int mode
, int port
, char host_name
[256],
110 char player_name
[GC_PLAYER_NAME_LENGTH
] )
112 comm_link_active
= false;
117 if (WSAStartup(MAKEWORD(1, 1), &wsa_data
) != 0) {
118 cerr
<< "Winsock startup failed." << endl
;
124 port
= CO_DEFAULT_PORT
;
126 switch (mode
& (CM_SERVER
| CM_CLIENT
)) {
128 int connection_socket
= socket(AF_INET
, SOCK_STREAM
, 0);
133 setsockopt (connection_socket
, SOL_SOCKET
, SO_REUSEADDR
, &val
, sizeof (int));
135 address
.sin_family
= AF_INET
;
136 address
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
137 address
.sin_port
= htons(port
);
139 if (bind(connection_socket
, (sockaddr
*) &address
, sizeof(address
)) < 0) {
140 cerr
<< "Port " << port
<< " is busy." << endl
;
144 cout
<< "Waiting for connection at port " << port
<< "..." << endl
;
145 listen(connection_socket
, 1);
148 if (!(mode
& CM_NO_TIME_OUT
)) {
150 ufds
.fd
= connection_socket
;
151 ufds
.events
= POLLIN
;
153 if (!poll(&ufds
, 1, CO_SERVER_TIME_OUT
* 1000)) {
154 cerr
<< "Timed out." << endl
;
161 unsigned int length
= sizeof(address
);
163 int length
= sizeof(address
);
165 comm_link
= accept(connection_socket
, (sockaddr
*) &address
, &length
);
166 comm_link_active
= true;
169 uint32 version_id
= CO_TEST_INT
;
170 for (char *c
= CO_VERSION
; *c
; c
++)
173 cout
<< "Version id: " << version_id
<< endl
;
175 version_id
= htonl(version_id
);
176 if (send(comm_link
, (char *) &version_id
, sizeof(version_id
), 0) < 1) {
177 cerr
<< "Connection failed." << endl
;
181 // server sends extremeness level
182 uint32 X_level
= ((mode
& CM_X
) ? 1 : 0);
185 // for simplicity, server wins ties - but don't tell anyone; it's the only
186 // available symmetry breaking term
189 cout
<< "Connection made by " << inet_ntoa(address
.sin_addr
) << '.' << endl
;
194 comm_link
= socket(AF_INET
, SOCK_STREAM
, 0);
195 comm_link_active
= true;
198 cout
<< "Hostname: " << host_name
<< endl
;
200 hostent
*host
= gethostbyname(host_name
);
202 cerr
<< "Host '" << host_name
<< "' not found." << endl
;
207 address
.sin_family
= AF_INET
;
208 address
.sin_addr
= *(struct in_addr
*) host
->h_addr
;
209 address
.sin_port
= htons((short) port
);
210 if (connect(comm_link
, (sockaddr
*) &address
, sizeof(address
)) < 0) {
211 cerr
<< "Connection failed. Unable to connect to address." << endl
;
216 uint32 version_id
= CO_TEST_INT
;
217 for (char *c
= CO_VERSION
; *c
; c
++)
220 cout
<< "Version id: " << version_id
<< endl
;
222 uint32 server_version_id
;
223 if (recv(comm_link
, (char *) &server_version_id
, sizeof(server_version_id
),
224 0) != sizeof(server_version_id
)) {
225 cerr
<< "Connection failed. Unable to read version information." << endl
;
228 if (ntohl(server_version_id
) != version_id
) {
229 cerr
<< "Connected to incompatible version." << endl
;
233 // server sends extremeness level
236 if (X_level
== 1) MetaState::mode
|= CM_X
;
238 // for simplicity, client loses ties - but don't tell anyone
241 cout
<< "Connection made to " << inet_ntoa(address
.sin_addr
) << ':'
242 << (short) port
<< '.' << endl
;
246 startupExchange(player_name
);
249 no_communication
= false;
250 have_communicated
= false;
253 void Communicator::cleanUp ( )
255 if (comm_link_active
) {
256 /* One solution to avoid "port is busy" after a game
257 is to have the client initiate the closure, so let's
258 wait a few seconds if we're the server.
259 http://hea-www.harvard.edu/~fine/Tech/addrinuse.html
261 if (MetaState::mode
& CM_SERVER
)
266 closesocket(comm_link
);
268 comm_link_active
= false;
272 void Communicator::exchangeRandomSeed ( )
276 // server sends the the random seed
277 if (MetaState::mode
& CM_SERVER
) {
278 seed
= Random::generateSeed();
286 void Communicator::gameStart ( )
289 no_communication
= false;
290 have_communicated
= false;
293 send_buffer
.count
= 0;
294 recv_buffer
.count
= 0;
295 send_buffer
.level_lights
= 0;
296 recv_buffer
.level_lights
= 0;
297 send_buffer
.game_state
= 0;
299 exchangeRandomSeed();
302 void Communicator::gameFinish ( )
305 no_communication
= false;
306 have_communicated
= false;
309 void Communicator::timeStepPlay_inline_split_ ( )
313 if (have_communicated
) {
314 commRecv(recv_buffer
);
316 // add new garbage to the queue
317 GarbageGenerator::addToQueue(recv_buffer
);
319 // handle the recved level light data
320 LevelLights::handleRecvBuffer();
322 // if we have been remotely paused
323 if (recv_buffer
.game_state
& GS_PAUSED
)
324 Game::netSignalPause();
326 // if we have been remotely unpaused
327 else if (recv_buffer
.game_state
& GS_UNPAUSED
)
328 Game::netSignalUnpause();
330 // store the current sync state
331 last_recv_sync
= recv_buffer
.sync
;
332 last_own_sync
= time_step
- Game::time_step
;
334 // if we're out of sync with our opponent, enter a sync pause
335 if (last_recv_sync
> last_own_sync
&& (Game::state
& GS_NORMAL
))
336 Game::syncPause(last_recv_sync
- last_own_sync
);
338 // if our opponent thinks he may have lost
339 if (recv_buffer
.game_state
& GS_MAY_HAVE_LOST
) {
341 // if it's a concession
342 if (recv_buffer
.game_state
& GS_CONCESSION
)
343 MetaState::state
|= MS_CONCESSION
;
345 // if we also think we may have lost
346 if (Game::state
& GS_MAY_HAVE_LOST
) {
349 if (recv_buffer
.loss_time_stamp
< send_buffer
.loss_time_stamp
350 || (recv_buffer
.loss_time_stamp
== send_buffer
.loss_time_stamp
358 // if the opponent has confirmed our loss
359 } else if (recv_buffer
.game_state
& GS_MUST_CONFIRM_LOSS
) {
360 Game::lossConfirmation();
361 no_communication
= true;
365 // if we were waiting a cycle for our opponent to recv his loss confirmation
366 if (Game::state
& GS_CONFIRMATION_HOLD
) {
367 Game::state
&= ~GS_CONFIRMATION_HOLD
;
368 no_communication
= true;
369 Game::state
|= GS_END_PLAY
;
373 have_communicated
= true;
377 // ready the level light data for sending
378 LevelLights::readySendBuffer();
380 // ready the game state information for sending - pause and unpause
381 // information have already been set
382 if (Game::state
& GS_MAY_HAVE_LOST
) {
383 send_buffer
.game_state
|= GS_MAY_HAVE_LOST
;
384 if (MetaState::state
& MS_CONCESSION
)
385 send_buffer
.game_state
|= GS_CONCESSION
;
386 } else if (Game::state
& GS_MUST_CONFIRM_LOSS
) {
387 send_buffer
.game_state
|= GS_MUST_CONFIRM_LOSS
;
388 Game::state
&= ~GS_MUST_CONFIRM_LOSS
;
389 Game::state
|= GS_CONFIRMATION_HOLD
;
392 // ready the sync for sending
393 send_buffer
.sync
= (uint32
) (time_step
- Game::time_step
);
395 commSend(send_buffer
);
398 send_buffer
.count
= 0;
399 send_buffer
.level_lights
= 0;
400 send_buffer
.game_state
= 0;
403 void Communicator::timeStepMeta_inline_split_ ( )
407 if (have_communicated
) {
410 // handle recved state data
411 if (state
& MS_REMOTE_KEY_WAIT
)
412 MetaState::remoteKeyPressed();
413 else if (state
& MS_READY_GAME_START
)
414 MetaState::remoteReady();
416 if (MetaState::state
& MS_GAME_PLAY
) return;
419 have_communicated
= true;
421 // ready state data for sending
422 state
= MetaState::state
& (MS_REMOTE_KEY_WAIT
| MS_READY_GAME_START
);
427 void Communicator::barrier ( )
429 uint32 c
= CO_TEST_INT
;
434 assert(c
== CO_TEST_INT
);