[Tux4kids-commits] r1531 - in tuxmath/trunk: server src
David Bruce
dbruce-guest at alioth.debian.org
Sat Sep 12 00:19:18 UTC 2009
Author: dbruce-guest
Date: 2009-09-12 00:19:17 +0000 (Sat, 12 Sep 2009)
New Revision: 1531
Added:
tuxmath/trunk/src/server.c
tuxmath/trunk/src/server.h
Removed:
tuxmath/trunk/server/server.c
tuxmath/trunk/server/server.h
Modified:
tuxmath/trunk/server/Makefile.am
tuxmath/trunk/src/Makefile.am
tuxmath/trunk/src/menu.c
Log:
support to run server as either forked process or separate program
Modified: tuxmath/trunk/server/Makefile.am
===================================================================
--- tuxmath/trunk/server/Makefile.am 2009-09-12 00:17:11 UTC (rev 1530)
+++ tuxmath/trunk/server/Makefile.am 2009-09-12 00:19:17 UTC (rev 1531)
@@ -1,16 +1,12 @@
-## Makefile.am for tuxmath server:
+## Makefile.am for tuxmath test client:
## Process with Automake to create Makefile.in
-bin_PROGRAMS = tuxmathserver tuxmathtestclient
+bin_PROGRAMS = tuxmathtestclient
-tuxmathserver_SOURCES = server.c \
- ../src/mathcards.c \
- ../src/throttle.c \
- ../src/options.c
tuxmathtestclient_SOURCES = testclient.c \
../src/throttle.c \
../src/network.c
-EXTRA_DIST = server.h testclient.h
+EXTRA_DIST = testclient.h
Deleted: tuxmath/trunk/server/server.c
===================================================================
--- tuxmath/trunk/server/server.c 2009-09-12 00:17:11 UTC (rev 1530)
+++ tuxmath/trunk/server/server.c 2009-09-12 00:19:17 UTC (rev 1531)
@@ -1,1192 +0,0 @@
-/*
-* C Implementation: server.c
-*
-* Description: Server program for LAN-based play in Tux,of Math Command.
-*
-*
-* Author: Akash Gangil, David Bruce, and the TuxMath team, (C) 2009
-* Developers list: <tuxmath-devel at lists.sourceforge.net>
-*
-* Copyright: See COPYING file that comes with this distribution. (Briefly, GNU GPL).
-*
-* NOTE: This file was initially based on example code from The Game Programming Wiki
-* (http://gpwiki.org), in a tutorial covered by the GNU Free Documentation License 1.2.
-* No invariant sections were indicated, and no separate license for the example code
-* was listed. The author was also not listed. AFAICT,this scenario allows incorporation of
-* derivative works into a GPLv2+ project like TuxMath - David Bruce
-*/
-
-#include "config.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "server.h"
-#include "../src/transtruct.h"
-#include "../src/mathcards.h"
-
-
-#define MAX_CLIENTS 16
-
-
-
-/* ----------- Local function prototypes: ------------ */
-
-// setup and cleanup:
-int setup_server(void);
-void cleanup_server(void);
-void handle_command_args(int argc, char* argv[]);
-
-// top level functions in main loop:
-void check_UDP(void);
-void update_clients(void);
-int check_messages(void);
-
-// client management utilities:
-int find_vacant_client(void);
-void remove_client(int i);
-void check_game_clients(void);
-
-// message reception:
-int handle_client_game_msg(int i, char* buffer);
-void handle_client_nongame_msg(int i, char* buffer);
-int msg_set_name(int i, char* buf);
-void start_game(void);
-void game_msg_correct_answer(int i, char* inbuf);
-void game_msg_wrong_answer(int i, char* inbuf);
-void game_msg_quit(int i);
-void game_msg_exit(int i);
-
-//message sending:
-int send_counter_updates(void);
-int add_question(MC_FlashCard* fc);
-int remove_question(int id);
-//int SendQuestion(MC_FlashCard flash, TCPsocket client_sock);
-int SendMessage(int message, int ques_id, char* name, TCPsocket client_sock);
-int player_msg(int i, char* msg);
-void broadcast_msg(char* msg);
-int transmit(int i, char* msg);
-int transmit_all(char* msg);
-
-// For non-blocking input:
-int read_stdin_nonblock(char* buf, size_t max_length);
-
-
-// not really deprecated but not done in response to
-// client message --needs better name:
-void game_msg_next_question(void);
-
-
-
-/* ------------ "Local globals" for server.c: ---------- */
-char server_name[NAME_SIZE]; /* User-visible name for server selection */
-int need_server_name = 1;
-UDPsocket udpsock = NULL; /* Used to listen for client's server autodetection */
-TCPsocket server_sock = NULL; /* Socket descriptor for server to accept client TCP sockets. */
-IPaddress ip;
-SDLNet_SocketSet client_set = NULL, temp_set = NULL;
-static client_type client[MAX_CLIENTS];
-static int num_clients = 0;
-static int numready = 0;
-static int game_in_progress = 0;
-static int quit = 0;
-static int frame = 0;
-MC_FlashCard flash;
-
-
-
-
-int main(int argc, char **argv)
-{
- printf("Started tuxmathserver, waiting for client to connect:\n>\n");
-
- handle_command_args(argc, argv);
-
- /* ---------------- Setup: --------------------------- */
- if (!setup_server())
- {
- fprintf(stderr, "setup_server() failed - exiting.\n");
- cleanup_server();
- exit(EXIT_FAILURE);
- }
-
-
- printf("Waiting for clients to connect:\n>");
- fflush(stdout);
-
- /* ------------- Main server loop: ------------------ */
- while (!quit)
- {
- /* Respond to any clients pinging us to find the server: */
- check_UDP();
- /* Now we check to see if anyone is trying to connect. */
- update_clients();
- /* Check for any pending messages from clients already connected: */
- check_messages();
-
- /* Limit frame rate to keep from eating all CPU: */
- /* NOTE almost certainly could make this longer wtihout noticably */
- /* affecting performance, but even throttling to 1 msec/loop cuts */
- /* CPU from 100% to ~2% on my desktop - DSB */
- Throttle(5); //min loop time 5 msec
- }
-
- /* ----- Free resources before exiting: ------- */
- cleanup_server();
-
- return EXIT_SUCCESS;
-}
-
-
-
-/*********************************************************************/
-/* "Private" (to server.c) functions */
-/*********************************************************************/
-
-
-/* ----- Setup and Cleanup: ------------------- */
-
-
-// setup_server() - all the things needed to get server running:
-int setup_server(void)
-{
- //Initialize SDL and SDL_net:
- if(SDL_Init(0) == -1)
- {
- printf("SDL_Init: %s\n", SDL_GetError());
- return 0;;
- }
-
- if (SDLNet_Init() < 0)
- {
- fprintf(stderr, "SDLNet_Init: %s\n", SDLNet_GetError());
- return 0;
- }
-
-
- /* Resolving the host using NULL make network interface to listen */
- if (SDLNet_ResolveHost(&ip, NULL, DEFAULT_PORT) < 0)
- {
- fprintf(stderr, "SDLNet_ResolveHost: %s\n", SDLNet_GetError());
- return 0;
- }
-
- /* Open a connection with the IP provided (listen on the host's port) */
- if (!(server_sock = SDLNet_TCP_Open(&ip)))
- {
- fprintf(stderr, "SDLNet_TCP_Open: %s\n", SDLNet_GetError());
- return 0;
- }
-
- client_set = SDLNet_AllocSocketSet(MAX_CLIENTS);
- if(!client_set)
- {
- printf("SDLNet_AllocSocketSet: %s\n", SDLNet_GetError());
- return 0;
- }
-
- //this sets up our mathcards "library" with hard-coded defaults - no
- //settings read from config file here as of yet:
- if (!MC_Initialize())
- {
- fprintf(stderr, "Could not initialize MathCards\n");
- return 0;
- }
-
- /* Get server name: */
- /* We use default name after 30 sec timeout if no name entered. */
- /* FIXME we should save this to disc so it doesn't */
- /* have to be entered every time. */
- if(need_server_name)
- {
- Uint32 timeout = SDL_GetTicks() + SERVER_NAME_TIMEOUT;
- int name_recvd = 0;
- server_name[0] = '\0';
- fcntl(0, F_SETFL, fcntl(0, F_GETFL, 0) | O_NONBLOCK);
-
- printf("Enter the SERVER's NAME: \n>");
- fflush(stdout);
-
- while(!name_recvd && (SDL_GetTicks() < timeout))
- {
- if(read_stdin_nonblock(server_name, NAME_SIZE))
- name_recvd = 1;
- Throttle(10);
- }
- if(!name_recvd)
- printf("No name entered within timeout, will use default: %s\n",
- DEFAULT_SERVER_NAME);
-
- /* If no nickname received, use default: */
- if(strlen(server_name) == 0)
- strncpy(server_name, DEFAULT_SERVER_NAME, NAME_SIZE);
- }
-
-
- // Zero out our client list:
- {
- int i = 0;
- for(i = 0; i < MAX_CLIENTS; i++)
- {
- client[i].game_ready = 0; /* waiting for user to OK game start */
- client[i].name[0] = '\0'; /* no nicknames yet */
- client[i].sock = NULL; /* sockets start out unconnected */
- }
- }
-
-
- //Now open a UDP socket to listen for clients broadcasting to find the server:
- udpsock = SDLNet_UDP_Open(DEFAULT_PORT);
- if(!udpsock)
- {
- printf("SDLNet_UDP_Open: %s\n", SDLNet_GetError());
- return 0;
- }
-
- // Indicates success:
- return 1;
-}
-
-
-
-//Free resources, closing sockets, call MC_EndGame(), and so forth:
-void cleanup_server(void)
-{
- int i;
- /* Close the client socket(s) */
-
- for(i = 0; i < MAX_CLIENTS; i++)
- {
- if(client[i].sock != NULL)
- {
- SDLNet_TCP_Close(client[i].sock); //close all the client sockets one by one
- client[i].sock = NULL; // So we don't segfault in case cleanup()
- } // somehow gets called more than once.
- }
-
- if (client_set != NULL)
- {
- SDLNet_FreeSocketSet(client_set); //releasing the memory of the client socket set
- client_set = NULL; //this helps us remember that this set is not allocated
- }
-
- if(server_sock != NULL)
- {
- SDLNet_TCP_Close(server_sock);
- server_sock = NULL;
- }
-
- SDLNet_Quit();
-
- /* Clean up mathcards heap memory */
- MC_EndGame();
-}
-
-
-/* Handle any arguments passed from command line */
-void handle_command_args(int argc, char* argv[])
-{
- int i;
-
- for (i = 1; i < argc; i++)
- {
- if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0)
- {
- /* Display help message: */
- printf("\n");
- cleanup_server();
- exit(0);
- }
- else if (strcmp(argv[i], "--copyright") == 0 ||
- strcmp(argv[i], "-c") == 0)
- {
- printf(
- "\n\"Tux, of Math Command Server\" version " VERSION ", Copyright (C) 2009,\n"
- "David Bruce, Akash Gangil, and the Tux4Kids Project.\n"
- "This program is free software; you can redistribute it and/or\n"
- "modify it under the terms of the GNU General Public License\n"
- "as published by the Free Software Foundation. See COPYING.txt\n"
- "\n"
- "This program is distributed in the hope that it will be useful,\n"
- "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
- "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
- "\n");
-
- cleanup_server();
- exit(0);
- }
- else if (strcmp(argv[i], "--usage") == 0 ||
- strcmp(argv[i], "-u") == 0)
- {
- /* Display (happy) usage: */
-
-// usage(0, argv[0]);
- }
- else if ((strcmp(argv[i], "--name") == 0 || strcmp(argv[i], "-n") == 0)
- && (i + 1 < argc))
- {
- strncpy(server_name, argv[i + 1], NAME_SIZE);
- need_server_name = 0;
- }
- }
-}
-
-
-// ----------- Top level functions in main loop ---------------:
-
-//check_UDP() is the server side of the client-server autodetection system.
-//When a client wants to connect, it sends a UDP broadcast to the local
-//network on this port, and the server sends a response.
-void check_UDP(void)
-{
- char buf[NET_BUF_LEN];
- int recvd = 0;
- UDPpacket* in = SDLNet_AllocPacket(NET_BUF_LEN);
- recvd = SDLNet_UDP_Recv(udpsock, in);
-
- // See if packet contains identifying string:
- if(strncmp((char*)in->data, "TUXMATH_CLIENT", strlen("TUXMATH_CLIENT")) == 0)
- {
- UDPpacket* out;
- IPaddress bcast_ip;
- int sent = 0;
- char buf[NET_BUF_LEN];
- // Send "I am here" reply so client knows where to connect socket,
- // with configurable identifying string so user can distinguish
- // between multiple servers on same network (e.g. "Mrs. Adams' Class");
- out = SDLNet_AllocPacket(NET_BUF_LEN);
- snprintf(buf, NET_BUF_LEN, "%s\t%s", "TUXMATH_SERVER", server_name);
- snprintf(out->data, NET_BUF_LEN, "%s", buf);
- out->len = strlen(buf) + 1;
- out->address.host = in->address.host;
- out->address.port = in->address.port;
-
- sent = SDLNet_UDP_Send(udpsock, -1, out);
-
- SDLNet_FreePacket(out);
- }
-}
-
-
-
-
-//update_clients() sees if anyone is trying to connect, and connects if a slot
-//is open and the game is not in progress. The purpose is to make sure our
-//client set accurately reflects the current state.
-void update_clients(void)
-{
- TCPsocket temp_sock = NULL; /* Just used when client can't be accepted */
- int slot = 0;
- int sockets_used = 0;
- char buffer[NET_BUF_LEN];
-
-
- /* See if we have a pending connection: */
- temp_sock = SDLNet_TCP_Accept(server_sock);
- if (!temp_sock) /* No one waiting to join - do nothing */
- {
- return; // Leave num_clients unchanged
- }
-
- // See if any slots are available:
- slot = find_vacant_client();
- if (slot == -1) /* No vacancies: */
- {
- snprintf(buffer, NET_BUF_LEN,
- "%s\t%s",
- "PLAYER_MSG",
- "Sorry, already have maximum number of clients connected");
- SDLNet_TCP_Send(temp_sock, buffer, NET_BUF_LEN);
- //hang up:
- SDLNet_TCP_Close(temp_sock);
- temp_sock = NULL;
-#ifdef LAN_DEBUG
- printf("buffer sent:\n");
- printf("buffer is: %s\n", buffer);
-#endif
- return; // Leave num_clients unchanged
- }
-
- //If everyone is disconnected, game no longer in progress:
- check_game_clients();
-
- // If game already started, send our regrets:
- if(game_in_progress)
- {
- snprintf(buffer, NET_BUF_LEN,
- "%s",
- "GAME_IN_PROGRESS");
- SDLNet_TCP_Send(temp_sock, buffer, NET_BUF_LEN);
- //hang up:
- SDLNet_TCP_Close(temp_sock);
- temp_sock = NULL;
-#ifdef LAN_DEBUG
- printf("buffer sent\n");
- printf("buffer is: %s\n", buffer);
-#endif
- return; // Leave num_clients unchanged
- }
-
- // If we get to here, we have room for the new connection and the
- // game is not in progress, so we connect:
-
-#ifdef LAN_DEBUG
- printf("creating connection for client[%d].sock:\n", slot);
-#endif
-
- client[slot].sock = temp_sock;
-
- /* Add client socket to set: */
- sockets_used = SDLNet_TCP_AddSocket(client_set, client[slot].sock);
- if(sockets_used == -1) //No way this should happen
- {
- printf("SDLNet_AddSocket: %s\n", SDLNet_GetError());
- cleanup_server();
- exit(EXIT_FAILURE);
- }
-
- /* At this point num_clients can be updated: */
- num_clients = sockets_used;
-
- /* Now we can communicate with the client using client[i].sock socket
- /* serv_sock will remain opened waiting other connections */
-
-
-#ifdef LAN_DEBUG
- /* Get the remote address */
- {
- IPaddress* client_ip = NULL;
- client_ip = SDLNet_TCP_GetPeerAddress(client[slot].sock);
-
- printf("num_clients = %d\n", num_clients);
- if (client_ip != NULL)
- /* Print the address, converting in the host format */
- {
- printf("Client connected\n>\n");
- printf("Client: IP = %x, Port = %d\n",
- SDLNet_Read32(&client_ip->host),
- SDLNet_Read16(&client_ip->port));
- }
- else
- fprintf(stderr, "SDLNet_TCP_GetPeerAddress: %s\n", SDLNet_GetError());
- }
-#endif
-
- return;
-}
-
-
-
-// check_messages() is where we look at the client socket set to see which
-// have sent us messages. This function is used in each server loop whether
-// or not a math game is in progress (although we expect different messages
-// during a game from those encountered outside of a game)
-
-int check_messages(void)
-{
- int actives = 0, i = 0;
- int ready_found = 0;
- char buffer[NET_BUF_LEN];
-
-
- /* Check the client socket set for activity: */
- actives = SDLNet_CheckSockets(client_set, 0);
-// printf("in check_messages(), actives = %d\n", actives);
- if(actives == -1)
- {
- printf("SDLNet_CheckSockets: %s\n", SDLNet_GetError());
- //most of the time this is a system error, where perror might help you.
- perror("SDLNet_CheckSockets");
- }
-
- else if(actives)
- {
-#ifdef LAN_DEBUG
- printf("There are %d sockets with activity\n", actives);
-#endif
-
- // check all sockets with SDLNet_SocketReady and handle the active ones.
- // NOTE we have to check all the slots in the set because
- // the set will become discontinuous if someone disconnects
- // NOTE this will only pick up the first message for each socket each time
- // check_messages() called - probably OK if we just get it next time through.
- for(i = 0; i < MAX_CLIENTS; i++)
- {
- if((client[i].sock != NULL)
- && (SDLNet_SocketReady(client[i].sock)))
- {
- ready_found++;
-
-#ifdef LAN_DEBUG
- printf("client socket %d is ready\n", i);
-#endif
- if (SDLNet_TCP_Recv(client[i].sock, buffer, NET_BUF_LEN) > 0)
- {
-
-#ifdef LAN_DEBUG
- printf("buffer received from client %d is: %s\n", i, buffer);
-#endif
-
- /* Here we pass the client number and the message buffer */
- /* to a suitable function for further action: */
- if(game_in_progress)
- {
- handle_client_game_msg(i, buffer);
- }
- else
- {
- handle_client_nongame_msg(i, buffer);
- }
- // See if game is ended because everyone has left:
- check_game_clients();
- }
- else // Socket activity but cannot receive - client invalid
- {
- printf("Client %d active but receive failed - apparently disconnected\n>\n", i);
- remove_client(i);
- }
- }
- } // end of for() loop - all client sockets checked
- // Make sure all the active sockets reported by SDLNet_CheckSockets()
- // are accounted for:
-
- if(actives > ready_found)
- {
- printf("Warning: SDLNet_CheckSockets() reported %d active sockets,\n"
- "but only %d detected by SDLNet_SocketReady()\n", actives, ready_found);
- //Presently, this just runs ping_client() on all the sockets:
- //test_connections();
- }
- }
-}
-
-
-
-
-// client management utilities:
-
-//Returns the index of the first vacant client, or -1 if all clients full
-int find_vacant_client(void)
-{
- int i = 0;
- while (client[i].sock && i < MAX_CLIENTS)
- i++;
- if (i == MAX_CLIENTS)
- {
- fprintf(stderr, "All clients checked, none vacant\n");
- i = -1;
- }
- return i;
-}
-
-
-void remove_client(int i)
-{
- printf("Removing client[%d] - name: %s\n>\n", i, client[i].name);
-
- SDLNet_TCP_DelSocket(client_set, client[i].sock);
-
- if(client[i].sock != NULL)
- SDLNet_TCP_Close(client[i].sock);
-
- client[i].sock = NULL;
- client[i].game_ready = 0;
- client[i].name[0] = '\0';
-}
-
-
-// check_game_clients() reviews the game_ready flags of all the connected
-// clients to determine if a new game is started, or if an old game needs
-// to be ended because all the players have left. If it finds both "playing"
-// and "nonplaying clients", it leaves game_in_progress unchanged.
-
-// TODO this is not very sophisticated, and only supports one game at a time.
-// We may want to make this extensible to multiple simultaneous games, perhaps
-// with each game in its own thread with its own socket set and mathcards instance.
-// FIXME we need to do more than just toggle game_in_progress - should have
-// start_game() and end_game() functions that make sure mathcards is
-// properly set up or cleaned up.
-void check_game_clients(void)
-{
- int i = 0;
-
- //If the game is already started, we leave it running as long as at least
- //one client is both connected and willing to play:
- if(game_in_progress)
- {
- int someone_still_playing = 0;
- for(i = 0; i < MAX_CLIENTS; i++)
- {
- if((client[i].sock != NULL)
- && client[i].game_ready)
- {
- someone_still_playing = 1;
- break;
- }
- }
-
- if(!someone_still_playing)
- {
- printf("All the clients have left the game, setting game_in_progress = 0.\n");
- game_in_progress = 0;
- }
- }
- //If the game hasn't started yet, we only start it
- //if all connected clients are ready:
- //FIXME should add a timeout so the game eventually starts without
- //those who don't answer
- else
- {
- int someone_connected = 0;
- int someone_not_ready = 0;
- for(i = 0; i < MAX_CLIENTS; i++)
- {
- if(client[i].sock != NULL)
- {
- someone_connected = 1;
- if (!client[i].game_ready)
- {
- someone_not_ready = 1;
- }
- }
- }
- if(someone_connected && !someone_not_ready)
- start_game();
- }
-}
-
-
-
-void handle_client_nongame_msg(int i, char* buffer)
-{
- char buf[NET_BUF_LEN];
- int x;
-
- if(strncmp(buffer, "START_GAME", strlen("START_GAME")) == 0)
- {
- snprintf(buf, NET_BUF_LEN,
- "Player %s ready to start math game",
- client[i].name);
- broadcast_msg(buf);
- client[i].game_ready = 1;
- //This will call start_game() if all the other clients are ready:
- check_game_clients();
- }
- else if(strncmp(buffer, "SET_NAME", strlen("SET_NAME")) == 0)
- {
- msg_set_name(i, buffer);
- }
-}
-
-
-int handle_client_game_msg(int i , char* buffer)
-{
-#ifdef LAN_DEBUG
- printf("Buffer received from client: %s\n", buffer);
-#endif
-
- if(strncmp(buffer, "CORRECT_ANSWER", strlen("CORRECT_ANSWER")) == 0)
- {
- game_msg_correct_answer(i, buffer);
- }
-
- else if(strncmp(buffer, "WRONG_ANSWER",strlen("WRONG_ANSWER")) == 0) /* Player answered the question incorrectly , meaning comet crashed into a city or an igloo */
- {
- game_msg_wrong_answer(i, buffer);
- }
- /* FIXME currently thinking the clients won't be asking for questions - server decides. */
- else if(strncmp(buffer, "NEXT_QUESTION",strlen("NEXT_QUESTION")) == 0) /* Send Next Question */
- {
- game_msg_next_question();
- }
- else if(strncmp(buffer, "LEAVE_GAME", strlen("LEAVE_GAME")) == 0)
- {
- client[i].game_ready = 0; /* Player quitting game but not disconnecting */
- }
-
- else if(strncmp(buffer, "exit",strlen("exit")) == 0) /* Terminate this connection */
- {
- game_msg_exit(i);
- }
-
- else if(strncmp(buffer, "quit",strlen("quit")) == 0) /* Quit the program */
- {
- game_msg_quit(i);
- return(1);
- }
- else
- {
- printf("command %s not recognized\n", buffer);
- }
- return(0);
-}
-
-
-
-int msg_set_name(int i, char* buf)
-{
- char* p;
-
- if(buf == NULL)
- return 0;
-
- p = strchr(buf, '\t');
- if(p)
- {
- p++;
- strncpy(client[i].name, p, NAME_SIZE);
- return 1;
- }
- else
- return 0;
-}
-
-
-
-void game_msg_correct_answer(int i, char* inbuf)
-{
- char outbuf[NET_BUF_LEN];
- char* p;
- int id;
-
- if(!inbuf)
- return;
-
- //parse inbuf to get question id:
- p = strchr(inbuf, '\t');
- if(!p)
- return;
- p++;
- id = atoi(p);
-
- //Tell mathcards so lists get updated:
- if(!MC_AnsweredCorrectly(id))
- return;
- //If we get to here, the id was successfully parsed out of inbuf
- //and the corresponding question was found.
-
- //Announcement for server and all clients:
- snprintf(outbuf, NET_BUF_LEN,
- "question id %d was answered correctly by %s\n",
- id, client[i].name);
- broadcast_msg(outbuf);
- //Tell all players to remove that question:
- remove_question(id);
- //send the next question to everyone:
- game_msg_next_question();
- //and update the game counters:
- send_counter_updates();
-}
-
-
-void game_msg_wrong_answer(int i, char* inbuf)
-{
- char outbuf[NET_BUF_LEN];
- char* p;
- int id;
-
- if(!inbuf)
- return;
-
- //parse inbuf to get question id:
- p = strchr(inbuf, '\t');
- if(!p)
- return;
- p++;
- id = atoi(p);
-
- //Tell mathcards so lists get updated:
- if(!MC_NotAnsweredCorrectly(id))
- return;
- //If we get to here, the id was successfully parsed out of inbuf
- //and the corresponding question was found.
-
- //Announcement for server and all clients:
- snprintf(outbuf, NET_BUF_LEN,
- "question id %d was missed by %s\n",
- id, client[i].name);
- broadcast_msg(outbuf);
- //Tell all players to remove that question:
- remove_question(id);
- //send the next question to everyone:
- game_msg_next_question();
- //and update the game counters:
- send_counter_updates();
-}
-
-
-
-void game_msg_next_question(void)
-{
- if (!MC_NextQuestion(&flash))
- {
- /* no more questions available */
- printf("MC_NextQuestion() returned NULL - no questions available\n");
- return;
- }
-
-#ifdef LAN_DEBUG
- printf("WILL SEND >>\n");
- printf("QUESTION_ID : %d\n", flash.question_id);
- printf("FORMULA_STRING : %s\n", flash.formula_string);
- printf("ANSWER STRING : %s\n", flash.answer_string);
- printf("ANSWER : %d\n", flash.answer);
- printf("DIFFICULTY : %d\n", flash.difficulty);
-#endif
-
-
- add_question(&flash);
-
-/* for(n = 0; n < MAX_CLIENTS && client[n].sock; n++)
- {
-#ifdef LAN_DEBUG
- printf("About to send next question to client[%d]\n", n);
-#endif
- if(!SendQuestion(flash, client[n].sock))
- {
- printf("Unable to send Question\n");
- }
- } */
-}
-
-
-
-
-
-void game_msg_exit(int i)
-{
- printf("LEFT the GAME : %s",client[i].name);
- remove_client(i);
-}
-
-
-
-//FIXME don't think we want to allow players to shut down the server
-void game_msg_quit(int i)
-{
- printf("Server has been shut down by %s\n",client[i].name);
- cleanup_server();
- exit(9); // '9' means exit ;) (just taken an arbitary no:)
-}
-
-
-
-
-
-
-/* Now this gets called to actually start the game once all the players */
-/* have indicated that they are ready: */
-void start_game(void)
-{
- char buf[NET_BUF_LEN];
- char buffer[NET_BUF_LEN];
- int x,j;
-
-
- /* NOTE this should no longer be needed - doing the same thing earlier */
- /*This loop sees that the game starts only when all the players are ready */
- /* i.e. if someone is connected but not ready, we return. */
- for(j = 0; j < MAX_CLIENTS; j++)
- {
- // Only check sockets that aren't null:
- if((client[j].game_ready != 1)
- && (client[j].sock != NULL))
- {
- printf("Warning - start_game() entered when someone not ready\n");
- return;
- }
- }
-
-
- /***********************Will be modified**************/
- //Tell everyone we are starting and count who's really in:
- num_clients = 0;
- snprintf(buf, NET_BUF_LEN,
- "%s\n",
- "GO_TO_GAME");
- for(j = 0; j < MAX_CLIENTS; j++)
- {
- if((client[j].game_ready == 1)
- && (client[j].sock != NULL))
- {
- if(SDLNet_TCP_Send(client[j].sock, buf, NET_BUF_LEN) == NET_BUF_LEN)
- num_clients++;
- else
- {
- printf("in start_game() - failed to send to client %d, removing\n", j);
- remove_client(j);
- }
- }
- }
- /*****************************************************/
-
-
- /* If no players join the game (should not happen) */
- if(num_clients == 0)
- {
- printf("There were no players........=(\n");
- return;
- }
-
-#ifdef LAN_DEBUG
- printf("We have %d players.......\n", num_clients);
-#endif
-
-
- game_in_progress = 1; //setting the game_in_progress flag to '1'
- //Start a new math game as far as mathcards is concerned:
- if (!MC_StartGame())
- {
- fprintf(stderr, "\nMC_StartGame() failed!");
- return;
- }
-
- game_in_progress = 1;
-
-
- /* Send enough questions to fill the initial comet slots (currently 10) */
- for(j = 0; j < QUEST_QUEUE_SIZE; j++)
- {
-
- int k = 0;
-
- if (!MC_NextQuestion(&flash))
- {
- /* no more questions available */
- printf("MC_NextQuestion() returned NULL - no questions available\n");
- return;
- }
-
-#ifdef LAN_DEBUG
- printf("WILL SEND >>\n");
- printf("QUESTION_ID : %d\n", flash.question_id);
- printf("FORMULA_STRING : %s\n", flash.formula_string);
- printf("ANSWER STRING : %s\n", flash.answer_string);
- printf("ANSWER : %d\n",flash.answer);
- printf("DIFFICULTY : %d\n",flash.difficulty);
-#endif
-
- //Send to all clients with add_question();
- add_question(&flash);
- }
- //Send all the clients the counter totals:
- send_counter_updates();
-}
-
-
-
-
-//More centralized function to update the clients of the number of
-//questions remaining, whether the mission has been accomplished,
-//and so forth:
-int send_counter_updates(void)
-{
- int i, total_questions;
-
- //If game won, tell everyone:
- if(MC_MissionAccomplished())
- {
- char buf[NET_BUF_LEN];
- snprintf(buf, NET_BUF_LEN, "%s", "MISSION_ACCOMPLISHED");
- transmit_all(buf);
- }
-
- //Tell everyone how many questions left:
- total_questions = MC_TotalQuestionsLeft();
- {
- char buf[NET_BUF_LEN];
- snprintf(buf, NET_BUF_LEN, "%s\t%d", "TOTAL_QUESTIONS", total_questions);
- transmit_all(buf);
- }
- return 1;
-}
-
-/* Sends a new question to all clients: */
-int add_question(MC_FlashCard* fc)
-{
- char buf[NET_BUF_LEN];
-
- if(!fc)
- return 0;
-
- snprintf(buf, NET_BUF_LEN,"%s\t%d\t%d\t%d\t%s\t%s\n",
- "ADD_QUESTION",
- fc->question_id,
- fc->difficulty,
- fc->answer,
- fc->answer_string,
- fc->formula_string);
- transmit_all(buf);
- return 1;
-}
-
-/* Tells all clients to remove a specific question: */
-int remove_question(int id)
-{
- char buf[NET_BUF_LEN];
- snprintf(buf, NET_BUF_LEN, "%s\t%d", "REMOVE_QUESTION", id);
- transmit_all(buf);
- return 1;
-}
-
-
-
-
-/*Function to send any messages to the client be it any warnings
- or anything the client is made to be informed */
-int SendMessage(int message, int ques_id, char *name, TCPsocket client_sock)
-{
- int x, len;
- char buf[NET_BUF_LEN];
- char msg[100];
-
- /* Create appropriate message: */
- switch(message)
- {
- case NO_QUESTION_LIST:
- sprintf(msg,"%s", "Please! first setup the question list by typing <a>\n");
- break;
- case ANSWER_CORRECT:
- sprintf(msg,"%s %d %s %s", "Question ID:",
- ques_id, "was answered correctly by the client",name);
- break;
- case LIST_SET_UP:
- sprintf(msg,"%s", "Question list was successfully setup\n");
- break;
- default :
- fprintf(stderr, "SendMessage() - unrecognized message type\n");
- return 0;
- }
- //transmit:
- snprintf(buf, NET_BUF_LEN, "%s\t%s\n", "SEND_MESSAGE", msg);
- x = SDLNet_TCP_Send(client_sock, buf, NET_BUF_LEN);
-
-#ifdef LAN_DEBUG
- printf("buf is: %s\n", buf);
- printf("SendMessage() - buf sent:::: %d bytes\n", x);
-#endif
-
- return 1;
-}
-
-
-
-/* Sends a string for the client to display to player: */
-int player_msg(int i, char* msg)
-{
- char buf[NET_BUF_LEN];
- if(!msg)
- {
-#ifdef LAN_DEBUG
- printf("player_msg() - msg argument is NULL\n");
-#endif
- return 0;
- }
-
- /* Add header: */
- snprintf(buf, NET_BUF_LEN, "%s\t%s", "PLAYER_MSG", msg);
- //NOTE transmit() validates index and socket
- return transmit(i, buf);
-}
-
-/* Send a player message to all clients: */
-void broadcast_msg(char* msg)
-{
- int i = 0;
- if (!msg)
- return;
- for(i = 0; i < MAX_CLIENTS; i++)
- player_msg(i, msg);
-}
-
-/* Send string to client. String should already have its header */
-int transmit(int i, char* msg)
-{
- char buf[NET_BUF_LEN];
-
- //Validate arguments;
- if(i < 0 || i > MAX_CLIENTS)
- {
-#ifdef LAN_DEBUG
- printf("transmit() - invalid index argument\n");
-#endif
- return 0;
- }
-
- if(!msg)
- {
-#ifdef LAN_DEBUG
- printf("transmit() - msg argument is NULL\n");
-#endif
- return 0;
- }
-
- if(!client[i].sock)
- {
- return 0;
- }
-
- //NOTE SDLNet's Send() keeps sending until the requested length is
- //sent, so it really is an error if we send less thatn NET_BUF_LEN
- snprintf(buf, NET_BUF_LEN, "%s", msg);
- if(SDLNet_TCP_Send(client[i].sock, buf, NET_BUF_LEN) < NET_BUF_LEN)
- {
- printf("The client %s is disconnected\n", client[i].name);
- remove_client(i);
- return 0;
- }
- //Success:
- return 1;
-}
-
-
-/* Send the message to all clients: */
-int transmit_all(char* msg)
-{
- int i = 0;
- if (!msg)
- return 0;
-
- for(i = 0; i < MAX_CLIENTS; i++)
- transmit(i, msg);
-
- return 1;
-}
-
-
-
-//Here we read up to max_length bytes from stdin into the buffer.
-//The first '\n' in the buffer, if present, is replaced with a
-//null terminator.
-//returns 0 if no data ready, 1 if at least one byte read.
-//NOTE for this to work we must first set stdin to O_NONBLOCK with:
-// fcntl(0, F_SETFL, fcntl(0, F_GETFL, 0) | O_NONBLOCK);
-
-int read_stdin_nonblock(char* buf, size_t max_length)
-{
- int bytes_read = 0;
- char* term = NULL;
- buf[0] = '\0';
-
- bytes_read = fread (buf, 1, max_length, stdin);
- term = strchr(buf, '\n');
- if (term)
- *term = '\0';
-
- if(bytes_read > 0)
- bytes_read = 1;
- else
- bytes_read = 0;
-
- return bytes_read;
-}
-
-
-
-
-
-
Deleted: tuxmath/trunk/server/server.h
===================================================================
--- tuxmath/trunk/server/server.h 2009-09-12 00:17:11 UTC (rev 1530)
+++ tuxmath/trunk/server/server.h 2009-09-12 00:19:17 UTC (rev 1531)
@@ -1,50 +0,0 @@
-/*
-
- server.h
-
- Description: As of now it conatins the enum, which identifies
- the network commands , as they are added(WORK IN PROGRESS).
-
- Author: David Bruce, Akash Gangil and the TuxMath team, (C) 2009
-
- Copyright: See COPYING file that comes with this distribution (briefly, GNU GPL version 2 or later)
-
-*/
-
-#ifndef SERVER_H
-#define SERVER_H == 1)
-
-#include "SDL_net.h"
-
-
-#define NAME_SIZE 50
-#define DEFAULT_SERVER_NAME "TuxMath LAN Server"
-#define SERVER_NAME_TIMEOUT 30000
-
-typedef struct client_type {
- int game_ready; //game_ready = 1 , if client has said OK to start, and 0 otherwise
- char name[NAME_SIZE];
- TCPsocket sock;
-}client_type;
-
-
-
-/*enum for commands coming from the client side*/
-enum {
- EXIT,
- QUIT,
- CORRECT_ANSWER,
- NOT_ANSWERED_CORRECTLY,
- NEXT_QUESTION,
- TOTAL_QUESTIONS_LEFT
-};
-
-
-/*enum for messages for SendMessage*/
-enum {
- ANSWER_CORRECT,
- LIST_SET_UP,
- NO_QUESTION_LIST
-};
-
-#endif
Modified: tuxmath/trunk/src/Makefile.am
===================================================================
--- tuxmath/trunk/src/Makefile.am 2009-09-12 00:17:11 UTC (rev 1530)
+++ tuxmath/trunk/src/Makefile.am 2009-09-12 00:19:17 UTC (rev 1531)
@@ -19,11 +19,15 @@
if BUILD_MINGW32
- bin_PROGRAMS = TuxMath
+ bin_PROGRAMS = TuxMath tuxmathserver
DATA_PREFIX=@MINGW32_PACKAGE_DATA_DIR@
else
TUXMATHRC =
- bin_PROGRAMS = tuxmath tuxmathadmin generate_lesson
+ bin_PROGRAMS = tuxmath \
+ tuxmathadmin \
+ generate_lesson \
+ tuxmathserver
+
DATA_PREFIX=${pkgdatadir}
endif
@@ -52,6 +56,7 @@
lessons.c \
scandir.c \
pixels.c \
+ server.c \
throttle.c
@@ -66,6 +71,12 @@
fileops.c \
lessons.c
+tuxmathserver_SOURCES = servermain.c \
+ server.c \
+ mathcards.c \
+ throttle.c \
+ . options.c
+
EXTRA_DIST = credits.h \
factoroids.h \
fileops.h \
@@ -92,6 +103,7 @@
scandir.h \
pixels.h \
compiler.h \
+ server.h \
transtruct.h \
throttle.h
Modified: tuxmath/trunk/src/menu.c
===================================================================
--- tuxmath/trunk/src/menu.c 2009-09-12 00:17:11 UTC (rev 1530)
+++ tuxmath/trunk/src/menu.c 2009-09-12 00:19:17 UTC (rev 1531)
@@ -30,6 +30,7 @@
#ifdef HAVE_LIBSDL_NET
#include "network.h"
+#include "server.h"
#endif
#include <stdio.h>
@@ -591,17 +592,17 @@
int run_lan_join(void)
{
#ifdef HAVE_LIBSDL_NET
- if(detecting_servers(_("Detecting Servers"), _("Please Wait")))
+ if(detecting_servers(_("Detecting servers"), _("Please wait")))
{
int stdby;
char buf[256];
char player_name[32];
snprintf(buf, 256, _("Connected to server: %s"), LAN_ConnectedServerName());
- NameEntry(player_name, buf, _("Enter your Name:"));
+ NameEntry(player_name, buf, _("Enter your name:"));
LAN_SetName(player_name);
- Ready(_("Click OK when Ready"));
+ Ready(_("Click when ready"));
LAN_StartGame();
- stdby = Standby(_("Waiting For Other Players"),_("To Connect"));
+ stdby = Standby(_("Waiting for other players"),_("to connect"));
if (stdby == 1)
{
Opts_SetLanMode(1); // Tells game() we are playing over network
Copied: tuxmath/trunk/src/server.c (from rev 1530, tuxmath/trunk/server/server.c)
===================================================================
--- tuxmath/trunk/src/server.c (rev 0)
+++ tuxmath/trunk/src/server.c 2009-09-12 00:19:17 UTC (rev 1531)
@@ -0,0 +1,1199 @@
+/*
+* C Implementation: server.c
+*
+* Description: Server program for LAN-based play in Tux,of Math Command.
+*
+*
+* Author: Akash Gangil, David Bruce, and the TuxMath team, (C) 2009
+* Developers list: <tuxmath-devel at lists.sourceforge.net>
+*
+* Copyright: See COPYING file that comes with this distribution. (Briefly, GNU GPL).
+*
+* NOTE: This file was initially based on example code from The Game Programming Wiki
+* (http://gpwiki.org), in a tutorial covered by the GNU Free Documentation License 1.2.
+* No invariant sections were indicated, and no separate license for the example code
+* was listed. The author was also not listed. AFAICT,this scenario allows incorporation of
+* derivative works into a GPLv2+ project like TuxMath - David Bruce
+*/
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "server.h"
+#include "transtruct.h"
+#include "mathcards.h"
+
+
+#define MAX_CLIENTS 16
+
+
+
+/* ----------- Local function prototypes: ------------ */
+
+// setup and cleanup:
+int setup_server(void);
+void cleanup_server(void);
+static void handle_command_args(int argc, char* argv[]);
+
+// top level functions in main loop:
+void check_UDP(void);
+void update_clients(void);
+static int check_messages(void);
+
+// client management utilities:
+int find_vacant_client(void);
+void remove_client(int i);
+void check_game_clients(void);
+
+// message reception:
+int handle_client_game_msg(int i, char* buffer);
+void handle_client_nongame_msg(int i, char* buffer);
+int msg_set_name(int i, char* buf);
+void start_game(void);
+void game_msg_correct_answer(int i, char* inbuf);
+void game_msg_wrong_answer(int i, char* inbuf);
+void game_msg_quit(int i);
+void game_msg_exit(int i);
+
+//message sending:
+int send_counter_updates(void);
+int add_question(MC_FlashCard* fc);
+int remove_question(int id);
+//int SendQuestion(MC_FlashCard flash, TCPsocket client_sock);
+int SendMessage(int message, int ques_id, char* name, TCPsocket client_sock);
+int player_msg(int i, char* msg);
+void broadcast_msg(char* msg);
+int transmit(int i, char* msg);
+int transmit_all(char* msg);
+
+// For non-blocking input:
+int read_stdin_nonblock(char* buf, size_t max_length);
+
+
+// not really deprecated but not done in response to
+// client message --needs better name:
+void game_msg_next_question(void);
+
+
+
+/* ------------ "Local globals" for server.c: ---------- */
+char server_name[NAME_SIZE]; /* User-visible name for server selection */
+int need_server_name = 1;
+UDPsocket udpsock = NULL; /* Used to listen for client's server autodetection */
+TCPsocket server_sock = NULL; /* Socket descriptor for server to accept client TCP sockets. */
+IPaddress ip;
+SDLNet_SocketSet client_set = NULL, temp_set = NULL;
+static client_type client[MAX_CLIENTS];
+static int num_clients = 0;
+static int numready = 0;
+static int game_in_progress = 0;
+static int quit = 0;
+static int frame = 0;
+MC_FlashCard flash;
+
+
+
+
+
+
+
+
+/* The contents of main() are wrapped into this function to allow the */
+/* server to be run as a function in a process or thread within another */
+/* program - DSB */
+int RunServer(int argc, char **argv)
+{
+ printf("Started tuxmathserver, waiting for client to connect:\n>\n");
+
+ handle_command_args(argc, argv);
+
+ /* ---------------- Setup: --------------------------- */
+ if (!setup_server())
+ {
+ fprintf(stderr, "setup_server() failed - exiting.\n");
+ cleanup_server();
+ exit(EXIT_FAILURE);
+ }
+
+
+ printf("Waiting for clients to connect:\n>");
+ fflush(stdout);
+
+ /* ------------- Main server loop: ------------------ */
+ while (!quit)
+ {
+ /* Respond to any clients pinging us to find the server: */
+ check_UDP();
+ /* Now we check to see if anyone is trying to connect. */
+ update_clients();
+ /* Check for any pending messages from clients already connected: */
+ check_messages();
+
+ /* Limit frame rate to keep from eating all CPU: */
+ /* NOTE almost certainly could make this longer wtihout noticably */
+ /* affecting performance, but even throttling to 1 msec/loop cuts */
+ /* CPU from 100% to ~2% on my desktop - DSB */
+ Throttle(5); //min loop time 5 msec
+ }
+
+ /* ----- Free resources before exiting: ------- */
+ cleanup_server();
+
+ return EXIT_SUCCESS;
+}
+
+
+
+/*********************************************************************/
+/* "Private" (to server.c) functions */
+/*********************************************************************/
+
+
+/* ----- Setup and Cleanup: ------------------- */
+
+
+// setup_server() - all the things needed to get server running:
+int setup_server(void)
+{
+ //Initialize SDL and SDL_net:
+ if(SDL_Init(0) == -1)
+ {
+ printf("SDL_Init: %s\n", SDL_GetError());
+ return 0;;
+ }
+
+ if (SDLNet_Init() < 0)
+ {
+ fprintf(stderr, "SDLNet_Init: %s\n", SDLNet_GetError());
+ return 0;
+ }
+
+
+ /* Resolving the host using NULL make network interface to listen */
+ if (SDLNet_ResolveHost(&ip, NULL, DEFAULT_PORT) < 0)
+ {
+ fprintf(stderr, "SDLNet_ResolveHost: %s\n", SDLNet_GetError());
+ return 0;
+ }
+
+ /* Open a connection with the IP provided (listen on the host's port) */
+ if (!(server_sock = SDLNet_TCP_Open(&ip)))
+ {
+ fprintf(stderr, "SDLNet_TCP_Open: %s\n", SDLNet_GetError());
+ return 0;
+ }
+
+ client_set = SDLNet_AllocSocketSet(MAX_CLIENTS);
+ if(!client_set)
+ {
+ printf("SDLNet_AllocSocketSet: %s\n", SDLNet_GetError());
+ return 0;
+ }
+
+ //this sets up our mathcards "library" with hard-coded defaults - no
+ //settings read from config file here as of yet:
+ if (!MC_Initialize())
+ {
+ fprintf(stderr, "Could not initialize MathCards\n");
+ return 0;
+ }
+
+ /* Get server name: */
+ /* We use default name after 30 sec timeout if no name entered. */
+ /* FIXME we should save this to disc so it doesn't */
+ /* have to be entered every time. */
+ if(need_server_name)
+ {
+ Uint32 timeout = SDL_GetTicks() + SERVER_NAME_TIMEOUT;
+ int name_recvd = 0;
+ server_name[0] = '\0';
+ fcntl(0, F_SETFL, fcntl(0, F_GETFL, 0) | O_NONBLOCK);
+
+ printf("Enter the SERVER's NAME: \n>");
+ fflush(stdout);
+
+ while(!name_recvd && (SDL_GetTicks() < timeout))
+ {
+ if(read_stdin_nonblock(server_name, NAME_SIZE))
+ name_recvd = 1;
+ Throttle(10);
+ }
+ if(!name_recvd)
+ printf("No name entered within timeout, will use default: %s\n",
+ DEFAULT_SERVER_NAME);
+
+ /* If no nickname received, use default: */
+ if(strlen(server_name) == 0)
+ strncpy(server_name, DEFAULT_SERVER_NAME, NAME_SIZE);
+ }
+
+
+ // Zero out our client list:
+ {
+ int i = 0;
+ for(i = 0; i < MAX_CLIENTS; i++)
+ {
+ client[i].game_ready = 0; /* waiting for user to OK game start */
+ client[i].name[0] = '\0'; /* no nicknames yet */
+ client[i].sock = NULL; /* sockets start out unconnected */
+ }
+ }
+
+
+ //Now open a UDP socket to listen for clients broadcasting to find the server:
+ udpsock = SDLNet_UDP_Open(DEFAULT_PORT);
+ if(!udpsock)
+ {
+ printf("SDLNet_UDP_Open: %s\n", SDLNet_GetError());
+ return 0;
+ }
+
+ // Indicates success:
+ return 1;
+}
+
+
+
+//Free resources, closing sockets, call MC_EndGame(), and so forth:
+void cleanup_server(void)
+{
+ int i;
+ /* Close the client socket(s) */
+
+ for(i = 0; i < MAX_CLIENTS; i++)
+ {
+ if(client[i].sock != NULL)
+ {
+ SDLNet_TCP_Close(client[i].sock); //close all the client sockets one by one
+ client[i].sock = NULL; // So we don't segfault in case cleanup()
+ } // somehow gets called more than once.
+ }
+
+ if (client_set != NULL)
+ {
+ SDLNet_FreeSocketSet(client_set); //releasing the memory of the client socket set
+ client_set = NULL; //this helps us remember that this set is not allocated
+ }
+
+ if(server_sock != NULL)
+ {
+ SDLNet_TCP_Close(server_sock);
+ server_sock = NULL;
+ }
+
+ SDLNet_Quit();
+
+ /* Clean up mathcards heap memory */
+ MC_EndGame();
+}
+
+
+/* Handle any arguments passed from command line */
+void handle_command_args(int argc, char* argv[])
+{
+ int i;
+
+ for (i = 1; i < argc; i++)
+ {
+ if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0)
+ {
+ /* Display help message: */
+ printf("\n");
+ cleanup_server();
+ exit(0);
+ }
+ else if (strcmp(argv[i], "--copyright") == 0 ||
+ strcmp(argv[i], "-c") == 0)
+ {
+ printf(
+ "\n\"Tux, of Math Command Server\" version " VERSION ", Copyright (C) 2009,\n"
+ "David Bruce, Akash Gangil, and the Tux4Kids Project.\n"
+ "This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License\n"
+ "as published by the Free Software Foundation. See COPYING.txt\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
+ "\n");
+
+ cleanup_server();
+ exit(0);
+ }
+ else if (strcmp(argv[i], "--usage") == 0 ||
+ strcmp(argv[i], "-u") == 0)
+ {
+ /* Display (happy) usage: */
+
+// usage(0, argv[0]);
+ }
+ else if ((strcmp(argv[i], "--name") == 0 || strcmp(argv[i], "-n") == 0)
+ && (i + 1 < argc))
+ {
+ strncpy(server_name, argv[i + 1], NAME_SIZE);
+ need_server_name = 0;
+ }
+ }
+}
+
+
+// ----------- Top level functions in main loop ---------------:
+
+//check_UDP() is the server side of the client-server autodetection system.
+//When a client wants to connect, it sends a UDP broadcast to the local
+//network on this port, and the server sends a response.
+void check_UDP(void)
+{
+ char buf[NET_BUF_LEN];
+ int recvd = 0;
+ UDPpacket* in = SDLNet_AllocPacket(NET_BUF_LEN);
+ recvd = SDLNet_UDP_Recv(udpsock, in);
+
+ // See if packet contains identifying string:
+ if(strncmp((char*)in->data, "TUXMATH_CLIENT", strlen("TUXMATH_CLIENT")) == 0)
+ {
+ UDPpacket* out;
+ IPaddress bcast_ip;
+ int sent = 0;
+ char buf[NET_BUF_LEN];
+ // Send "I am here" reply so client knows where to connect socket,
+ // with configurable identifying string so user can distinguish
+ // between multiple servers on same network (e.g. "Mrs. Adams' Class");
+ out = SDLNet_AllocPacket(NET_BUF_LEN);
+ snprintf(buf, NET_BUF_LEN, "%s\t%s", "TUXMATH_SERVER", server_name);
+ snprintf(out->data, NET_BUF_LEN, "%s", buf);
+ out->len = strlen(buf) + 1;
+ out->address.host = in->address.host;
+ out->address.port = in->address.port;
+
+ sent = SDLNet_UDP_Send(udpsock, -1, out);
+
+ SDLNet_FreePacket(out);
+ }
+}
+
+
+
+
+//update_clients() sees if anyone is trying to connect, and connects if a slot
+//is open and the game is not in progress. The purpose is to make sure our
+//client set accurately reflects the current state.
+void update_clients(void)
+{
+ TCPsocket temp_sock = NULL; /* Just used when client can't be accepted */
+ int slot = 0;
+ int sockets_used = 0;
+ char buffer[NET_BUF_LEN];
+
+
+ /* See if we have a pending connection: */
+ temp_sock = SDLNet_TCP_Accept(server_sock);
+ if (!temp_sock) /* No one waiting to join - do nothing */
+ {
+ return; // Leave num_clients unchanged
+ }
+
+ // See if any slots are available:
+ slot = find_vacant_client();
+ if (slot == -1) /* No vacancies: */
+ {
+ snprintf(buffer, NET_BUF_LEN,
+ "%s\t%s",
+ "PLAYER_MSG",
+ "Sorry, already have maximum number of clients connected");
+ SDLNet_TCP_Send(temp_sock, buffer, NET_BUF_LEN);
+ //hang up:
+ SDLNet_TCP_Close(temp_sock);
+ temp_sock = NULL;
+#ifdef LAN_DEBUG
+ printf("buffer sent:\n");
+ printf("buffer is: %s\n", buffer);
+#endif
+ return; // Leave num_clients unchanged
+ }
+
+ //If everyone is disconnected, game no longer in progress:
+ check_game_clients();
+
+ // If game already started, send our regrets:
+ if(game_in_progress)
+ {
+ snprintf(buffer, NET_BUF_LEN,
+ "%s",
+ "GAME_IN_PROGRESS");
+ SDLNet_TCP_Send(temp_sock, buffer, NET_BUF_LEN);
+ //hang up:
+ SDLNet_TCP_Close(temp_sock);
+ temp_sock = NULL;
+#ifdef LAN_DEBUG
+ printf("buffer sent\n");
+ printf("buffer is: %s\n", buffer);
+#endif
+ return; // Leave num_clients unchanged
+ }
+
+ // If we get to here, we have room for the new connection and the
+ // game is not in progress, so we connect:
+
+#ifdef LAN_DEBUG
+ printf("creating connection for client[%d].sock:\n", slot);
+#endif
+
+ client[slot].sock = temp_sock;
+
+ /* Add client socket to set: */
+ sockets_used = SDLNet_TCP_AddSocket(client_set, client[slot].sock);
+ if(sockets_used == -1) //No way this should happen
+ {
+ printf("SDLNet_AddSocket: %s\n", SDLNet_GetError());
+ cleanup_server();
+ exit(EXIT_FAILURE);
+ }
+
+ /* At this point num_clients can be updated: */
+ num_clients = sockets_used;
+
+ /* Now we can communicate with the client using client[i].sock socket
+ /* serv_sock will remain opened waiting other connections */
+
+
+#ifdef LAN_DEBUG
+ /* Get the remote address */
+ {
+ IPaddress* client_ip = NULL;
+ client_ip = SDLNet_TCP_GetPeerAddress(client[slot].sock);
+
+ printf("num_clients = %d\n", num_clients);
+ if (client_ip != NULL)
+ /* Print the address, converting in the host format */
+ {
+ printf("Client connected\n>\n");
+ printf("Client: IP = %x, Port = %d\n",
+ SDLNet_Read32(&client_ip->host),
+ SDLNet_Read16(&client_ip->port));
+ }
+ else
+ fprintf(stderr, "SDLNet_TCP_GetPeerAddress: %s\n", SDLNet_GetError());
+ }
+#endif
+
+ return;
+}
+
+
+
+// check_messages() is where we look at the client socket set to see which
+// have sent us messages. This function is used in each server loop whether
+// or not a math game is in progress (although we expect different messages
+// during a game from those encountered outside of a game)
+
+int check_messages(void)
+{
+ int actives = 0, i = 0;
+ int ready_found = 0;
+ char buffer[NET_BUF_LEN];
+
+
+ /* Check the client socket set for activity: */
+ actives = SDLNet_CheckSockets(client_set, 0);
+// printf("in check_messages(), actives = %d\n", actives);
+ if(actives == -1)
+ {
+ printf("SDLNet_CheckSockets: %s\n", SDLNet_GetError());
+ //most of the time this is a system error, where perror might help you.
+ perror("SDLNet_CheckSockets");
+ }
+
+ else if(actives)
+ {
+#ifdef LAN_DEBUG
+ printf("There are %d sockets with activity\n", actives);
+#endif
+
+ // check all sockets with SDLNet_SocketReady and handle the active ones.
+ // NOTE we have to check all the slots in the set because
+ // the set will become discontinuous if someone disconnects
+ // NOTE this will only pick up the first message for each socket each time
+ // check_messages() called - probably OK if we just get it next time through.
+ for(i = 0; i < MAX_CLIENTS; i++)
+ {
+ if((client[i].sock != NULL)
+ && (SDLNet_SocketReady(client[i].sock)))
+ {
+ ready_found++;
+
+#ifdef LAN_DEBUG
+ printf("client socket %d is ready\n", i);
+#endif
+ if (SDLNet_TCP_Recv(client[i].sock, buffer, NET_BUF_LEN) > 0)
+ {
+
+#ifdef LAN_DEBUG
+ printf("buffer received from client %d is: %s\n", i, buffer);
+#endif
+
+ /* Here we pass the client number and the message buffer */
+ /* to a suitable function for further action: */
+ if(game_in_progress)
+ {
+ handle_client_game_msg(i, buffer);
+ }
+ else
+ {
+ handle_client_nongame_msg(i, buffer);
+ }
+ // See if game is ended because everyone has left:
+ check_game_clients();
+ }
+ else // Socket activity but cannot receive - client invalid
+ {
+ printf("Client %d active but receive failed - apparently disconnected\n>\n", i);
+ remove_client(i);
+ }
+ }
+ } // end of for() loop - all client sockets checked
+ // Make sure all the active sockets reported by SDLNet_CheckSockets()
+ // are accounted for:
+
+ if(actives > ready_found)
+ {
+ printf("Warning: SDLNet_CheckSockets() reported %d active sockets,\n"
+ "but only %d detected by SDLNet_SocketReady()\n", actives, ready_found);
+ //Presently, this just runs ping_client() on all the sockets:
+ //test_connections();
+ }
+ }
+}
+
+
+
+
+// client management utilities:
+
+//Returns the index of the first vacant client, or -1 if all clients full
+int find_vacant_client(void)
+{
+ int i = 0;
+ while (client[i].sock && i < MAX_CLIENTS)
+ i++;
+ if (i == MAX_CLIENTS)
+ {
+ fprintf(stderr, "All clients checked, none vacant\n");
+ i = -1;
+ }
+ return i;
+}
+
+
+void remove_client(int i)
+{
+ printf("Removing client[%d] - name: %s\n>\n", i, client[i].name);
+
+ SDLNet_TCP_DelSocket(client_set, client[i].sock);
+
+ if(client[i].sock != NULL)
+ SDLNet_TCP_Close(client[i].sock);
+
+ client[i].sock = NULL;
+ client[i].game_ready = 0;
+ client[i].name[0] = '\0';
+}
+
+
+// check_game_clients() reviews the game_ready flags of all the connected
+// clients to determine if a new game is started, or if an old game needs
+// to be ended because all the players have left. If it finds both "playing"
+// and "nonplaying clients", it leaves game_in_progress unchanged.
+
+// TODO this is not very sophisticated, and only supports one game at a time.
+// We may want to make this extensible to multiple simultaneous games, perhaps
+// with each game in its own thread with its own socket set and mathcards instance.
+// FIXME we need to do more than just toggle game_in_progress - should have
+// start_game() and end_game() functions that make sure mathcards is
+// properly set up or cleaned up.
+void check_game_clients(void)
+{
+ int i = 0;
+
+ //If the game is already started, we leave it running as long as at least
+ //one client is both connected and willing to play:
+ if(game_in_progress)
+ {
+ int someone_still_playing = 0;
+ for(i = 0; i < MAX_CLIENTS; i++)
+ {
+ if((client[i].sock != NULL)
+ && client[i].game_ready)
+ {
+ someone_still_playing = 1;
+ break;
+ }
+ }
+
+ if(!someone_still_playing)
+ {
+ printf("All the clients have left the game, setting game_in_progress = 0.\n");
+ game_in_progress = 0;
+ }
+ }
+ //If the game hasn't started yet, we only start it
+ //if all connected clients are ready:
+ //FIXME should add a timeout so the game eventually starts without
+ //those who don't answer
+ else
+ {
+ int someone_connected = 0;
+ int someone_not_ready = 0;
+ for(i = 0; i < MAX_CLIENTS; i++)
+ {
+ if(client[i].sock != NULL)
+ {
+ someone_connected = 1;
+ if (!client[i].game_ready)
+ {
+ someone_not_ready = 1;
+ }
+ }
+ }
+ if(someone_connected && !someone_not_ready)
+ start_game();
+ }
+}
+
+
+
+void handle_client_nongame_msg(int i, char* buffer)
+{
+ char buf[NET_BUF_LEN];
+ int x;
+
+ if(strncmp(buffer, "START_GAME", strlen("START_GAME")) == 0)
+ {
+ snprintf(buf, NET_BUF_LEN,
+ "Player %s ready to start math game",
+ client[i].name);
+ broadcast_msg(buf);
+ client[i].game_ready = 1;
+ //This will call start_game() if all the other clients are ready:
+ check_game_clients();
+ }
+ else if(strncmp(buffer, "SET_NAME", strlen("SET_NAME")) == 0)
+ {
+ msg_set_name(i, buffer);
+ }
+}
+
+
+int handle_client_game_msg(int i , char* buffer)
+{
+#ifdef LAN_DEBUG
+ printf("Buffer received from client: %s\n", buffer);
+#endif
+
+ if(strncmp(buffer, "CORRECT_ANSWER", strlen("CORRECT_ANSWER")) == 0)
+ {
+ game_msg_correct_answer(i, buffer);
+ }
+
+ else if(strncmp(buffer, "WRONG_ANSWER",strlen("WRONG_ANSWER")) == 0) /* Player answered the question incorrectly , meaning comet crashed into a city or an igloo */
+ {
+ game_msg_wrong_answer(i, buffer);
+ }
+ /* FIXME currently thinking the clients won't be asking for questions - server decides. */
+ else if(strncmp(buffer, "NEXT_QUESTION",strlen("NEXT_QUESTION")) == 0) /* Send Next Question */
+ {
+ game_msg_next_question();
+ }
+ else if(strncmp(buffer, "LEAVE_GAME", strlen("LEAVE_GAME")) == 0)
+ {
+ client[i].game_ready = 0; /* Player quitting game but not disconnecting */
+ }
+
+ else if(strncmp(buffer, "exit",strlen("exit")) == 0) /* Terminate this connection */
+ {
+ game_msg_exit(i);
+ }
+
+ else if(strncmp(buffer, "quit",strlen("quit")) == 0) /* Quit the program */
+ {
+ game_msg_quit(i);
+ return(1);
+ }
+ else
+ {
+ printf("command %s not recognized\n", buffer);
+ }
+ return(0);
+}
+
+
+
+int msg_set_name(int i, char* buf)
+{
+ char* p;
+
+ if(buf == NULL)
+ return 0;
+
+ p = strchr(buf, '\t');
+ if(p)
+ {
+ p++;
+ strncpy(client[i].name, p, NAME_SIZE);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+
+
+void game_msg_correct_answer(int i, char* inbuf)
+{
+ char outbuf[NET_BUF_LEN];
+ char* p;
+ int id;
+
+ if(!inbuf)
+ return;
+
+ //parse inbuf to get question id:
+ p = strchr(inbuf, '\t');
+ if(!p)
+ return;
+ p++;
+ id = atoi(p);
+
+ //Tell mathcards so lists get updated:
+ if(!MC_AnsweredCorrectly(id))
+ return;
+ //If we get to here, the id was successfully parsed out of inbuf
+ //and the corresponding question was found.
+
+ //Announcement for server and all clients:
+ snprintf(outbuf, NET_BUF_LEN,
+ "question id %d was answered correctly by %s\n",
+ id, client[i].name);
+ broadcast_msg(outbuf);
+ //Tell all players to remove that question:
+ remove_question(id);
+ //send the next question to everyone:
+ game_msg_next_question();
+ //and update the game counters:
+ send_counter_updates();
+}
+
+
+void game_msg_wrong_answer(int i, char* inbuf)
+{
+ char outbuf[NET_BUF_LEN];
+ char* p;
+ int id;
+
+ if(!inbuf)
+ return;
+
+ //parse inbuf to get question id:
+ p = strchr(inbuf, '\t');
+ if(!p)
+ return;
+ p++;
+ id = atoi(p);
+
+ //Tell mathcards so lists get updated:
+ if(!MC_NotAnsweredCorrectly(id))
+ return;
+ //If we get to here, the id was successfully parsed out of inbuf
+ //and the corresponding question was found.
+
+ //Announcement for server and all clients:
+ snprintf(outbuf, NET_BUF_LEN,
+ "question id %d was missed by %s\n",
+ id, client[i].name);
+ broadcast_msg(outbuf);
+ //Tell all players to remove that question:
+ remove_question(id);
+ //send the next question to everyone:
+ game_msg_next_question();
+ //and update the game counters:
+ send_counter_updates();
+}
+
+
+
+void game_msg_next_question(void)
+{
+ if (!MC_NextQuestion(&flash))
+ {
+ /* no more questions available */
+ printf("MC_NextQuestion() returned NULL - no questions available\n");
+ return;
+ }
+
+#ifdef LAN_DEBUG
+ printf("WILL SEND >>\n");
+ printf("QUESTION_ID : %d\n", flash.question_id);
+ printf("FORMULA_STRING : %s\n", flash.formula_string);
+ printf("ANSWER STRING : %s\n", flash.answer_string);
+ printf("ANSWER : %d\n", flash.answer);
+ printf("DIFFICULTY : %d\n", flash.difficulty);
+#endif
+
+
+ add_question(&flash);
+
+/* for(n = 0; n < MAX_CLIENTS && client[n].sock; n++)
+ {
+#ifdef LAN_DEBUG
+ printf("About to send next question to client[%d]\n", n);
+#endif
+ if(!SendQuestion(flash, client[n].sock))
+ {
+ printf("Unable to send Question\n");
+ }
+ } */
+}
+
+
+
+
+
+void game_msg_exit(int i)
+{
+ printf("LEFT the GAME : %s",client[i].name);
+ remove_client(i);
+}
+
+
+
+//FIXME don't think we want to allow players to shut down the server
+void game_msg_quit(int i)
+{
+ printf("Server has been shut down by %s\n",client[i].name);
+ cleanup_server();
+ exit(9); // '9' means exit ;) (just taken an arbitary no:)
+}
+
+
+
+
+
+
+/* Now this gets called to actually start the game once all the players */
+/* have indicated that they are ready: */
+void start_game(void)
+{
+ char buf[NET_BUF_LEN];
+ char buffer[NET_BUF_LEN];
+ int x,j;
+
+
+ /* NOTE this should no longer be needed - doing the same thing earlier */
+ /*This loop sees that the game starts only when all the players are ready */
+ /* i.e. if someone is connected but not ready, we return. */
+ for(j = 0; j < MAX_CLIENTS; j++)
+ {
+ // Only check sockets that aren't null:
+ if((client[j].game_ready != 1)
+ && (client[j].sock != NULL))
+ {
+ printf("Warning - start_game() entered when someone not ready\n");
+ return;
+ }
+ }
+
+
+ /***********************Will be modified**************/
+ //Tell everyone we are starting and count who's really in:
+ num_clients = 0;
+ snprintf(buf, NET_BUF_LEN,
+ "%s\n",
+ "GO_TO_GAME");
+ for(j = 0; j < MAX_CLIENTS; j++)
+ {
+ if((client[j].game_ready == 1)
+ && (client[j].sock != NULL))
+ {
+ if(SDLNet_TCP_Send(client[j].sock, buf, NET_BUF_LEN) == NET_BUF_LEN)
+ num_clients++;
+ else
+ {
+ printf("in start_game() - failed to send to client %d, removing\n", j);
+ remove_client(j);
+ }
+ }
+ }
+ /*****************************************************/
+
+
+ /* If no players join the game (should not happen) */
+ if(num_clients == 0)
+ {
+ printf("There were no players........=(\n");
+ return;
+ }
+
+#ifdef LAN_DEBUG
+ printf("We have %d players.......\n", num_clients);
+#endif
+
+
+ game_in_progress = 1; //setting the game_in_progress flag to '1'
+ //Start a new math game as far as mathcards is concerned:
+ if (!MC_StartGame())
+ {
+ fprintf(stderr, "\nMC_StartGame() failed!");
+ return;
+ }
+
+ game_in_progress = 1;
+
+
+ /* Send enough questions to fill the initial comet slots (currently 10) */
+ for(j = 0; j < QUEST_QUEUE_SIZE; j++)
+ {
+
+ int k = 0;
+
+ if (!MC_NextQuestion(&flash))
+ {
+ /* no more questions available */
+ printf("MC_NextQuestion() returned NULL - no questions available\n");
+ return;
+ }
+
+#ifdef LAN_DEBUG
+ printf("WILL SEND >>\n");
+ printf("QUESTION_ID : %d\n", flash.question_id);
+ printf("FORMULA_STRING : %s\n", flash.formula_string);
+ printf("ANSWER STRING : %s\n", flash.answer_string);
+ printf("ANSWER : %d\n",flash.answer);
+ printf("DIFFICULTY : %d\n",flash.difficulty);
+#endif
+
+ //Send to all clients with add_question();
+ add_question(&flash);
+ }
+ //Send all the clients the counter totals:
+ send_counter_updates();
+}
+
+
+
+
+//More centralized function to update the clients of the number of
+//questions remaining, whether the mission has been accomplished,
+//and so forth:
+int send_counter_updates(void)
+{
+ int i, total_questions;
+
+ //If game won, tell everyone:
+ if(MC_MissionAccomplished())
+ {
+ char buf[NET_BUF_LEN];
+ snprintf(buf, NET_BUF_LEN, "%s", "MISSION_ACCOMPLISHED");
+ transmit_all(buf);
+ }
+
+ //Tell everyone how many questions left:
+ total_questions = MC_TotalQuestionsLeft();
+ {
+ char buf[NET_BUF_LEN];
+ snprintf(buf, NET_BUF_LEN, "%s\t%d", "TOTAL_QUESTIONS", total_questions);
+ transmit_all(buf);
+ }
+ return 1;
+}
+
+/* Sends a new question to all clients: */
+int add_question(MC_FlashCard* fc)
+{
+ char buf[NET_BUF_LEN];
+
+ if(!fc)
+ return 0;
+
+ snprintf(buf, NET_BUF_LEN,"%s\t%d\t%d\t%d\t%s\t%s\n",
+ "ADD_QUESTION",
+ fc->question_id,
+ fc->difficulty,
+ fc->answer,
+ fc->answer_string,
+ fc->formula_string);
+ transmit_all(buf);
+ return 1;
+}
+
+/* Tells all clients to remove a specific question: */
+int remove_question(int id)
+{
+ char buf[NET_BUF_LEN];
+ snprintf(buf, NET_BUF_LEN, "%s\t%d", "REMOVE_QUESTION", id);
+ transmit_all(buf);
+ return 1;
+}
+
+
+
+
+/*Function to send any messages to the client be it any warnings
+ or anything the client is made to be informed */
+int SendMessage(int message, int ques_id, char *name, TCPsocket client_sock)
+{
+ int x, len;
+ char buf[NET_BUF_LEN];
+ char msg[100];
+
+ /* Create appropriate message: */
+ switch(message)
+ {
+ case NO_QUESTION_LIST:
+ sprintf(msg,"%s", "Please! first setup the question list by typing <a>\n");
+ break;
+ case ANSWER_CORRECT:
+ sprintf(msg,"%s %d %s %s", "Question ID:",
+ ques_id, "was answered correctly by the client",name);
+ break;
+ case LIST_SET_UP:
+ sprintf(msg,"%s", "Question list was successfully setup\n");
+ break;
+ default :
+ fprintf(stderr, "SendMessage() - unrecognized message type\n");
+ return 0;
+ }
+ //transmit:
+ snprintf(buf, NET_BUF_LEN, "%s\t%s\n", "SEND_MESSAGE", msg);
+ x = SDLNet_TCP_Send(client_sock, buf, NET_BUF_LEN);
+
+#ifdef LAN_DEBUG
+ printf("buf is: %s\n", buf);
+ printf("SendMessage() - buf sent:::: %d bytes\n", x);
+#endif
+
+ return 1;
+}
+
+
+
+/* Sends a string for the client to display to player: */
+int player_msg(int i, char* msg)
+{
+ char buf[NET_BUF_LEN];
+ if(!msg)
+ {
+#ifdef LAN_DEBUG
+ printf("player_msg() - msg argument is NULL\n");
+#endif
+ return 0;
+ }
+
+ /* Add header: */
+ snprintf(buf, NET_BUF_LEN, "%s\t%s", "PLAYER_MSG", msg);
+ //NOTE transmit() validates index and socket
+ return transmit(i, buf);
+}
+
+/* Send a player message to all clients: */
+void broadcast_msg(char* msg)
+{
+ int i = 0;
+ if (!msg)
+ return;
+ for(i = 0; i < MAX_CLIENTS; i++)
+ player_msg(i, msg);
+}
+
+/* Send string to client. String should already have its header */
+int transmit(int i, char* msg)
+{
+ char buf[NET_BUF_LEN];
+
+ //Validate arguments;
+ if(i < 0 || i > MAX_CLIENTS)
+ {
+#ifdef LAN_DEBUG
+ printf("transmit() - invalid index argument\n");
+#endif
+ return 0;
+ }
+
+ if(!msg)
+ {
+#ifdef LAN_DEBUG
+ printf("transmit() - msg argument is NULL\n");
+#endif
+ return 0;
+ }
+
+ if(!client[i].sock)
+ {
+ return 0;
+ }
+
+ //NOTE SDLNet's Send() keeps sending until the requested length is
+ //sent, so it really is an error if we send less thatn NET_BUF_LEN
+ snprintf(buf, NET_BUF_LEN, "%s", msg);
+ if(SDLNet_TCP_Send(client[i].sock, buf, NET_BUF_LEN) < NET_BUF_LEN)
+ {
+ printf("The client %s is disconnected\n", client[i].name);
+ remove_client(i);
+ return 0;
+ }
+ //Success:
+ return 1;
+}
+
+
+/* Send the message to all clients: */
+int transmit_all(char* msg)
+{
+ int i = 0;
+ if (!msg)
+ return 0;
+
+ for(i = 0; i < MAX_CLIENTS; i++)
+ transmit(i, msg);
+
+ return 1;
+}
+
+
+
+//Here we read up to max_length bytes from stdin into the buffer.
+//The first '\n' in the buffer, if present, is replaced with a
+//null terminator.
+//returns 0 if no data ready, 1 if at least one byte read.
+//NOTE for this to work we must first set stdin to O_NONBLOCK with:
+// fcntl(0, F_SETFL, fcntl(0, F_GETFL, 0) | O_NONBLOCK);
+
+int read_stdin_nonblock(char* buf, size_t max_length)
+{
+ int bytes_read = 0;
+ char* term = NULL;
+ buf[0] = '\0';
+
+ bytes_read = fread (buf, 1, max_length, stdin);
+ term = strchr(buf, '\n');
+ if (term)
+ *term = '\0';
+
+ if(bytes_read > 0)
+ bytes_read = 1;
+ else
+ bytes_read = 0;
+
+ return bytes_read;
+}
+
+
+
+
+
+
Copied: tuxmath/trunk/src/server.h (from rev 1530, tuxmath/trunk/server/server.h)
===================================================================
--- tuxmath/trunk/src/server.h (rev 0)
+++ tuxmath/trunk/src/server.h 2009-09-12 00:19:17 UTC (rev 1531)
@@ -0,0 +1,52 @@
+/*
+
+ server.h
+
+ Description: As of now it conatins the enum, which identifies
+ the network commands , as they are added(WORK IN PROGRESS).
+
+ Author: David Bruce, Akash Gangil and the TuxMath team, (C) 2009
+
+ Copyright: See COPYING file that comes with this distribution (briefly, GNU GPL version 2 or later)
+
+*/
+
+#ifndef SERVER_H
+#define SERVER_H == 1)
+
+#include "SDL_net.h"
+
+
+#define NAME_SIZE 50
+#define DEFAULT_SERVER_NAME "TuxMath LAN Server"
+#define SERVER_NAME_TIMEOUT 30000
+
+typedef struct client_type {
+ int game_ready; //game_ready = 1 , if client has said OK to start, and 0 otherwise
+ char name[NAME_SIZE];
+ TCPsocket sock;
+}client_type;
+
+
+
+/*enum for commands coming from the client side*/
+// enum {
+// EXIT,
+// QUIT,
+// CORRECT_ANSWER,
+// NOT_ANSWERED_CORRECTLY,
+// NEXT_QUESTION,
+// TOTAL_QUESTIONS_LEFT
+// };
+
+
+/*enum for messages for SendMessage*/
+enum {
+ ANSWER_CORRECT,
+ LIST_SET_UP,
+ NO_QUESTION_LIST
+};
+
+
+int RunServer(int argc, char **argv);
+#endif
More information about the Tux4kids-commits
mailing list