Logo Search packages:      
Sourcecode: xblast-tnt version File versions  Download package

com_to_server.c

/*
 * file com_to_server.c - client's communication with server
 *
 * $Id: com_to_server.c,v 1.22 2005/03/01 16:14:11 lodott Exp $
 *
 * Program XBLAST
 * (C) by Oliver Vogel (e-mail: m.vogel@ndh.net)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published
 * by the Free Software Foundation; either version 2; or (at your option)
 * any later version
 *
 * This program is distributed in the hope that it will be entertaining,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILTY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
 * Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.
 * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
#include "com_to_server.h"

#include "atom.h"
#include "client.h"
#include "net_tele.h"
#include "net_socket.h"

/*
 * local types
 */
typedef struct {
  XBCommStream stream;
  XBBool       expect;   /* flag for expected disconnect request */
} XBCommToServer;

/************
 * handlers *
 ************/

/*
 * server requests data
 */
static XBCommResult
HandleRequestData (XBCommStream *stream, const XBTelegram *tele)
{
  switch (Net_TeleID (tele)) {
  case XBT_ID_PlayerConfig:
    Dbg_C2S("receiving player config request from server\n");
    Client_ReceivePlayerConfigReq(Net_TeleIOB(tele));
    break;
  case XBT_ID_GameConfig:
    Dbg_C2S("receiving game config request from server\n");
    (void) Client_ReceiveGameConfigReq(Net_TeleIOB(tele));
    break;
  default:
    Dbg_C2S("server sends unrecognized data !!!\n");
    return Client_StreamEvent(XBCC_IDInvalid) ? XCR_Error : XCR_OK;
  }
  return XCR_OK;
} /* HandleRequestData */

/*
 * server sends data
 */
static XBCommResult
HandleSendData (XBCommStream *stream, const XBTelegram *tele)
{
  const char *data;
  size_t      len;
  XBTeleIOB   iob;
  XBChat      *chat;

  data = Net_TeleData (tele, &len);
  iob  = Net_TeleIOB (tele);
  switch (Net_TeleID (tele)) {
  case XBT_ID_GameConfig:
    Dbg_C2S("receiving game config from server\n");
    Client_ReceiveGameConfig (iob, data);
    break;
  case XBT_ID_PlayerConfig:
    Dbg_C2S("receiving player config from server\n");
    Client_ReceivePlayerConfig (iob >> 4, iob & 0x0F, data);
    break;
  case XBT_ID_LevelConfig:
    Dbg_C2S("receiving level config from server\n");
    Client_ReceiveLevelConfig (iob, data);
    break;
  case XBT_ID_Chat:
    chat = Chat_UnpackData(data, len, iob);
    if (NULL != chat) {
      Dbg_C2S("receiving chat from server\n");
      Client_ReceiveChat(chat);
    } else {
      Dbg_C2S("receiving invalid chat data\n");
      return Client_StreamEvent(XBCC_DataInvalid) ? XCR_Error : XCR_OK;
    }
    return XCR_OK;
  default:
    Dbg_C2S("server sent unrecognized data\n");
    return Client_StreamEvent(XBCC_IDInvalid) ? XCR_Error : XCR_OK;
  }
  return XCR_OK;
} /* HandleSendData */

/*
 * server sends a command
 */
static XBCommResult
HandleActivate (XBCommStream *stream, const XBTelegram *tele)
{
  XBCommToServer *toServer = (XBCommToServer *) stream;
  const char *data;
  size_t      len;
  unsigned    value;
  unsigned    tmp;

  data = Net_TeleData (tele, &len);
  switch (Net_TeleID (tele)) {
  case XBT_ID_RequestDisconnect:
    if (toServer->expect) {
      Dbg_C2S("server finishes disconnect announcement, shutting down stream\n");
      (void) Client_StreamEvent(XBCC_ExpectedEOF);
      return XCR_Finished;
    } else {
      Dbg_C2S("server unexpectedly requests disconnect\n");
      (void) Client_StreamEvent(XBCC_UnexpectedEOF);
      return XCR_Error;
    }
  case XBT_ID_StartGame:
    Dbg_C2S("server has started the game!\n");
    Client_ReceiveStart (Net_TeleIOB (tele));
    break;
  case XBT_ID_RandomSeed:
    if (NULL != data && 1 == sscanf (data, "%u", &value) ) {
      Dbg_C2S("server has sent random seed\n");
      Client_ReceiveRandomSeed (value);
    } else {
      Dbg_C2S("server send invalid seed!\n");
      return Client_StreamEvent(XBCC_DataInvalid) ? XCR_Error : XCR_OK;
    }
    break;
  case XBT_ID_DgramPort:
    if (NULL != data && 1 == sscanf (data, "%u", &value) ) {
      Dbg_C2S("server has sent dgram port\n");
      Client_ReceiveDgramPort (Net_TeleIOB (tele), value);
    } else {
      Dbg_C2S("server has sent invalid dgram port!\n");
      return Client_StreamEvent(XBCC_DataInvalid) ? XCR_Error : XCR_OK;
    }
    break;
  case XBT_ID_Sync:
    Dbg_C2S("server has sent sync\n");
    Client_ReceiveSync (Net_TeleIOB (tele));
    break;
  case XBT_ID_Async:
    Dbg_C2S("server has sent async!\n");
    Client_ReceiveAsync (Net_TeleIOB (tele));
    break;
  case XBT_ID_HostChange:
    if (NULL != data && 1 == sscanf(data, "%u", &value) ) {
      Dbg_C2S("server has sent host state\n");
      Client_ReceiveHostState (Net_TeleIOB (tele), value);
    } else {
      Dbg_C2S("server has sent invalid host state!\n");
      return Client_StreamEvent(XBCC_DataInvalid) ? XCR_Error : XCR_OK;
    }
    break;
  case XBT_ID_TeamChange:
    if (NULL != data && 1 == sscanf (data, "%u", &value) ) {
      Dbg_C2S("server has sent team state!\n");
      tmp = Net_TeleIOB(tele);
      Client_ReceiveTeamState (tmp / NUM_LOCAL_PLAYER, tmp % NUM_LOCAL_PLAYER, value);
    } else {
      Dbg_C2S("server has sent invalid team state!\n");
      return Client_StreamEvent(XBCC_DataInvalid) ? XCR_Error : XCR_OK;
    }
    break;
  case XBT_ID_HostChangeReq:
    if (len == 2) {
      Dbg_C2S("server has sent host state\n");
      Client_ReceiveHostStateReq (Net_TeleIOB(tele), data[0], data[1]);
    } else {
      Dbg_C2S("server has sent invalid host state!\n");
      return Client_StreamEvent(XBCC_DataInvalid) ? XCR_Error : XCR_OK;
    }
    break;
  case XBT_ID_TeamChangeReq:
    if (len == 3) {
      Dbg_C2S("server has sent team state request!\n");
      Client_ReceiveTeamStateReq (Net_TeleIOB(tele), data[0], data[1], data[2]);
    } else {
      Dbg_C2S("server has sent invalid team state!\n");
      return Client_StreamEvent(XBCC_DataInvalid) ? XCR_Error : XCR_OK;
    }
    break;
  case XBT_ID_LevelConfig:
    Dbg_C2S("server sends level activation\n");
    Client_ActivateLevel( Net_TeleIOB (tele));
    break;
  default:
    Dbg_C2S("server sends unrecognized command !!!\n");
    return Client_StreamEvent(XBCC_IDInvalid) ? XCR_Error : XCR_OK;
  }
  return XCR_OK;
} /* HandleSendData */

/*
 * handle infos from server
 */
static XBCommResult
HandleSpontaneous (XBCommStream *stream, const XBTelegram *tele)
{
  XBCommToServer *toServer = (XBCommToServer *) stream;
  switch (Net_TeleID (tele)) {
  case XBT_ID_HostDisconnected:
    Dbg_C2S("server sends disconnect info\n");
    toServer->expect = Client_ReceiveDisconnect (Net_TeleIOB (tele));
    return XCR_OK;
  default:
    Dbg_C2S("server sends unrecognized info !!!\n");
    return Client_StreamEvent(XBCC_IDInvalid) ? XCR_Error : XCR_OK;
  }
} /* HandleSpontaneous */


/*
 * handle telegrams from server
 */
static XBCommResult
HandleTelegram (XBCommStream *stream, const XBTelegram *tele)
{
  switch (Net_TeleCOT (tele)) {
    /* server requests data from client */
  case XBT_COT_RequestData:
    return HandleRequestData (stream, tele);
    /* server sends data to client */
  case XBT_COT_SendData:
    return HandleSendData (stream, tele);
    /* server activate command on client */
  case XBT_COT_Activate:
    return HandleActivate (stream, tele);
    /* server send spontaneous status change */
  case XBT_COT_Spontaneous:
    return HandleSpontaneous (stream, tele);
    /* unknown cause of transmission */
  default:
    Dbg_C2S("server sends invalid COT !\n");
    return Client_StreamEvent(XBCC_COTInvalid) ? XCR_Error : XCR_OK;
  }
} /* HandleTelegram */

/*
 * handle delete: triggered by eof on com_stream, local parse errors
 */
static XBCommResult
DeleteToServer (XBComm *comm)
{
  XBCommStream *stream = (XBCommStream *) comm;
  /* delete communication */
  Stream_CommFinish (stream);
  free (comm);
  Dbg_C2S("removed stream to server\n");
  return XCR_OK;
} /* DeleteToServer */

/*
 * handle stream events
 */
static XBBool
EventToServer (XBCommStream *comm, const XBStreamEvent ev)
{
  XBCommToServer *toServer = (XBCommToServer *) comm;
  XBClientConstants code;
  assert (toServer != NULL);
  switch (ev) {
  case XBST_IOREAD: code = XBCC_IOError; break;
  case XBST_IOWRITE: code = XBCC_IOError; break;
  case XBST_EOF: code = XBCC_UnexpectedEOF; break;
  case XBST_WAIT: code = XBCC_StreamWaiting; break;
  case XBST_BUSY: code = XBCC_StreamBusy; break;
  case XBST_CLOSE: code = XBCC_StreamClosed; break;
  default: return XBFalse;
  }
  return Client_StreamEvent(code);
} /* EventToServer */

/***************
 * constructor *
 ***************/

/*
 * create a stream to server
 */
XBComm *
C2S_CreateComm (const CFGGameHost *cfg)
{
  XBSocket       *pSocket;
  XBCommToServer *toServer;

  assert (cfg != NULL);
  /* create connection to server */
  pSocket = Net_ConnectInet (cfg->name, cfg->port);
  if (NULL == pSocket) {
    Dbg_C2S("failed to connect stream to server!\n");
    return NULL;
  }
  Dbg_C2S("connected stream to server!\n");
  /* create communication data structure */
  toServer = calloc (1, sizeof (*toServer));
  assert (NULL != toServer);
  /* set values */
  Stream_CommInit (&toServer->stream, COMM_ToServer, pSocket, HandleTelegram, EventToServer, DeleteToServer);
  toServer->expect = XBFalse;
  /* that'S all */
  Dbg_C2S("handlers established!\n");
  return &toServer->stream.comm;
} /* CommCreateToServer */

/******************
 * get local data *
 ******************/

/*
 * return address of server in dot-representation
 */
const char *
C2S_ServerName (XBComm *comm)
{
  return Net_RemoteName (comm->socket);
} /* C2S_ServerName */

/*
 * return address of client (local host) in dot-representation
 */
const char *
C2S_ClientName (XBComm *comm)
{
  return Net_LocalName (comm->socket);
} /* C2S_ClientName */

/**************
 * queue data *
 **************/

/*
 * queue random seed to client
 */
void
C2S_SendDgramPort (XBComm *comm, unsigned short port)
{
  XBCommStream *stream = (XBCommStream *) comm;
  char          tmp[16];
  /* sanity check */
  assert (stream != NULL);
  assert (stream->sndQueue != NULL);
  /* send seed as ascii */
  sprintf (tmp, "%hu", port);
  /* send data */
  Socket_RegisterWrite (CommSocket (&stream->comm));
  Net_SendTelegram (stream->sndQueue,
                Net_CreateTelegram (XBT_COT_Activate, XBT_ID_DgramPort, 0, tmp, strlen (tmp) + 1) );
  Dbg_C2S("queued dgram port to server!\n");
} /* C2S_SendDgramPort */

/*
 * queue a DataNotAvailable response, local
 */
static void
DataNotAvailable (XBComm *comm, XBTeleID id, XBTeleIOB iob)
{
  XBCommStream *stream = (XBCommStream *) comm;
  Socket_RegisterWrite (CommSocket (&stream->comm));
  Net_SendTelegram (stream->sndQueue,
                Net_CreateTelegram (XBT_COT_DataNotAvailable, id, iob, NULL, 0) );
  Dbg_C2S("queued data not available to server\n");
} /* DataNotAvailable */

/*
 * queue game config not available
 */
void
C2S_GameDataNotAvailable(XBComm *comm)
{
  DataNotAvailable(comm, XBT_ID_GameConfig, 0);
} /* C2S_PlayerDataNotAvailable */

/*
 * queue game config to client
 */
XBBool
C2S_SendGameConfig (XBComm *comm, CFGType cfgType, XBAtom atom)
{
  XBCommStream *stream = (XBCommStream *) comm;
  /* sanity check */
  assert (stream != NULL);
  assert (stream->sndQueue != NULL);
  /* send data */
  if (! SendGameConfig(cfgType, stream->sndQueue, XBT_COT_DataAvailable, 0, atom)) {
    Dbg_C2S("failed to queue game config!\n");
    return XBFalse;
  }
  Socket_RegisterWrite (CommSocket (&stream->comm) );
  Dbg_C2S("queued game config to server!\n");
  return XBTrue;
} /* C2S_SendGameConfig */

/*
 * queue player config not available
 */
void
C2S_PlayerDataNotAvailable(XBComm *comm, unsigned id)
{
  DataNotAvailable(comm, XBT_ID_PlayerConfig, id);
} /* C2S_PlayerDataNotAvailable */

/*
 * queue player config to client
 */
XBBool
C2S_SendPlayerConfig (XBComm *comm, CFGType cfgType, XBAtom atom, unsigned player, XBBool how)
{
  XBCommStream *stream = (XBCommStream *) comm;
  /* sanity check */
  assert (stream != NULL);
  assert (stream->sndQueue != NULL);
  /* send data */
  if (! SendPlayerConfig(cfgType, stream->sndQueue, XBT_COT_DataAvailable, player, atom, how)) {
    Dbg_C2S("failed to queue player config!\n");
    return XBFalse;
  }
  Socket_RegisterWrite (CommSocket (&stream->comm) );
  Dbg_C2S("queued game config to server!\n");
  return XBTrue;
} /* C2S_SendPlayerConfig */

/*
 * queue host state to server
 * TODO: replace with requests below
 */
void
C2S_SendHostState (XBComm *comm, unsigned state)
{
  XBCommStream *stream = (XBCommStream *) comm;
  char tmp[16];
  /* sanity check */
  assert (stream != NULL);
  assert (stream->sndQueue != NULL);
  /* send state as ascii */
  sprintf (tmp, "%hu", state);
  Socket_RegisterWrite (CommSocket (&stream->comm));
  Net_SendTelegram (stream->sndQueue,
                Net_CreateTelegram (XBT_COT_Spontaneous, XBT_ID_HostChange, 0, tmp, strlen (tmp) + 1) );
  Dbg_C2S("queued host state to server!\n");
} /* C2S_SendHostState */

/*
 * queue host state request to server
 */
void
C2S_SendHostStateReq (XBComm *comm, unsigned host, unsigned state)
{
  XBCommStream *stream = (XBCommStream *) comm;
  char tmp[2];
  /* sanity check */
  assert (stream != NULL);
  assert (stream->sndQueue != NULL);
  tmp[0] = host & 0xff;
  tmp[1] = state & 0xff;
  Socket_RegisterWrite (CommSocket (&stream->comm));
  Net_SendTelegram (stream->sndQueue, Net_CreateTelegram (XBT_COT_Activate, XBT_ID_HostChangeReq, 0, tmp, sizeof (tmp)) );
  Dbg_C2S("queued host state request host #%u->%u to server!\n", host, state);
} /* C2S_SendHostStateReq */

/*
 * queue team state request to server
 */
void
C2S_SendTeamStateReq (XBComm *comm, unsigned host, unsigned player, unsigned team)
{
  XBCommStream *stream = (XBCommStream *) comm;
  char tmp[3];
  /* sanity check */
  assert (stream != NULL);
  assert (stream->sndQueue != NULL);
  tmp[0] = host & 0xff;
  tmp[1] = player & 0xff;
  tmp[2] = team & 0xff;
  Socket_RegisterWrite (CommSocket (&stream->comm));
  Net_SendTelegram (stream->sndQueue, Net_CreateTelegram (XBT_COT_Activate, XBT_ID_TeamChangeReq, 0, tmp, sizeof (tmp)) );
  Dbg_C2S("queued team state request host #%u(%u)->%u to server!\n", host, player, team);
} /* C2S_SendHostStateReq */

/*
 * send a chat line to server
 */
void
C2S_SendChat (XBComm *comm, XBChat *chat)
{
  XBCommStream *stream = (XBCommStream *) comm;
  unsigned iob;
  char *data;
  size_t len;
  /* sanity check */
  assert (stream != NULL);
  assert (stream->sndQueue != NULL);
  assert (chat != NULL);
  /* pack chat data */
  len = Chat_PackData(chat, &data, &iob);
  /* prepare for writing */
  Socket_RegisterWrite (CommSocket (&stream->comm) );
  Net_SendTelegram (stream->sndQueue, Net_CreateTelegram (XBT_COT_Spontaneous, XBT_ID_Chat, iob, data, len) );
  Dbg_C2S("queued chat to server\n");
} /* C2S_SendChat */

/*
 * queue sync to server
 */
void
C2S_Sync (XBComm *comm, XBNetworkEvent event)
{
  XBCommStream *stream = (XBCommStream *) comm;
  assert (stream != NULL);
  assert (stream->sndQueue != NULL);
  Net_SendTelegram (stream->sndQueue, Net_CreateTelegram (XBT_COT_Spontaneous, XBT_ID_Sync, (XBTeleIOB) event, NULL, 0) );
  Socket_RegisterWrite (CommSocket (&stream->comm) );
  Dbg_C2S("queued sync #%u to server!\n", event);
} /* C2S_Sync */

/*
 * queue level check result to server
 */
void
C2S_LevelCheck (XBComm *comm, XBBool rej)
{
  XBCommStream *stream = (XBCommStream *) comm;
  assert (stream != NULL);
  assert (stream->sndQueue != NULL);
  Net_SendTelegram (stream->sndQueue, Net_CreateTelegram (XBT_COT_Activate, XBT_ID_LevelConfig, rej? 0 : 1, NULL, 0) );
  Socket_RegisterWrite (CommSocket (&stream->comm) );
  Dbg_C2S("queued level check result to server = %s\n", rej? "reject" : "accept");
} /* C2S_LevelCheck */

/*
 * queue level winner to server
 */
void
C2S_SendWinner (XBComm *comm, unsigned team)
{
  XBCommStream *stream = (XBCommStream *) comm;
  assert (stream != NULL);
  assert (stream->sndQueue != NULL);
  Net_SendTelegram (stream->sndQueue, Net_CreateTelegram (XBT_COT_Activate, XBT_ID_WinnerTeam, team, NULL, 0) );
  Socket_RegisterWrite (CommSocket (&stream->comm) );
  Dbg_C2S("queued level winner to server = %u\n", team);
} /* C2S_SendWinner */

/*
 * end of file com_to_server.c
 */

Generated by  Doxygen 1.6.0   Back to index