[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: 2 Player mode



On 07.10.2006 10:26, Jens Granseuer wrote:
> Anyway, I'm currently working on getting proper net infrastructure
> support into the code.

I feel very much like I'm moving in baby steps. Does this look sane
so far?

Jens

// Crimson Fields -- a game of tactical warfare
// Copyright (C) 2000-2006 Jens Granseuer
//
// 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 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY 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.
//

////////////////////////////////////////////////////////////////////////
// network.cpp - networking
////////////////////////////////////////////////////////////////////////

#include "network.h"

////////////////////////////////////////////////////////////////////////
// NAME       : NetBuffer::NetBuffer
// DESCRIPTION: Create a new buffer in memory.
// PARAMETERS : size - desired buffer size
// RETURNS    : -
////////////////////////////////////////////////////////////////////////

NetBuffer::NetBuffer( int size ) : size(size) {
  buffer = new char[size];
  fh = SDL_RWFromMem( buffer, size );
}

////////////////////////////////////////////////////////////////////////
// NAME       : NetBuffer::~NetBuffer
// DESCRIPTION: Free the buffer.
// PARAMETERS : -
// RETURNS    : -
////////////////////////////////////////////////////////////////////////

NetBuffer::~NetBuffer( void ) {
  delete buffer;
  SDL_FreeRW( fh );
}


extern "C" {
  struct PacketHeader {
    Uint32 id;
    Uint16 type;
    Uint8 version;
    Uint8 reserved;
    Uint32 size;
    Uint32 crc;
  };
}

////////////////////////////////////////////////////////////////////////
// NAME       : TCPConnection::TCPConnection
// DESCRIPTION: Create a new TCP/IP client connection.
// PARAMETERS : server - IP address or name of server to connect to
//              port   - port to connect to
// RETURNS    : -
////////////////////////////////////////////////////////////////////////

TCPConnection::TCPConnection( const string &server, Uint16 port ) : client(0), server(false) {
  Init( server.c_str(), port );
}

////////////////////////////////////////////////////////////////////////
// NAME       : TCPConnection::TCPConnection
// DESCRIPTION: Create a new TCP/IP server connection.
// PARAMETERS : port - port to accept clients on
// RETURNS    : -
////////////////////////////////////////////////////////////////////////

TCPConnection::TCPConnection( Uint16 port ) : client(0), server(true) {
  Init( NULL, port );
}

////////////////////////////////////////////////////////////////////////
// NAME       : TCPConnection::~TCPConnection
// DESCRIPTION: Destroy the connection.
// PARAMETERS : -
// RETURNS    : -
////////////////////////////////////////////////////////////////////////

TCPConnection::~TCPConnection( void ) {
  Close();
  if (socket) SDLNet_TCP_Close( socket );
}

////////////////////////////////////////////////////////////////////////
// NAME       : TCPConnection::Init
// DESCRIPTION: Initialize the connection.
// PARAMETERS : ipaddr - IP address/name of server for client connection
//                       NULL for server connection
//              port   - port to acceptr clients on
// RETURNS    : -
////////////////////////////////////////////////////////////////////////

int TCPConnection:Init( const char *ipaddr, Uint16 port ) {
  IPaddress ip;

  // create the socket
  if ( !SDLNet_ResolveHost( &ip, ipaddr, port ) ) {
    socket = SDLNet_TCP_Open( &ip );

    if (!socket) {
      printf( "SDLNet_TCP_Open: %s\n", SDLNet_GetError() );
    }
  } else {
    printf( "SDLNet_ResolveHost: %s\n", SDLNet_GetError() );
  }
}

////////////////////////////////////////////////////////////////////////
// NAME       : TCPConnection::Open
// DESCRIPTION: Open the connection. For a server this means wait for
//              client connection. For a client, this is almost a no-op.
// PARAMETERS : -
// RETURNS    : TRUE if open succeeded, FALSE on error
////////////////////////////////////////////////////////////////////////

bool TCPConnection:Open( void ) {
  bool rc = false;

  if ( socket != NULL ) {
    if ( server )  {
      client = SDLNet_TCP_Accept( socket );
      if ( client) rc = true;
      else printf( "SDLNet_Accept: %s\n", SDLNet_GetError() );
    } else rc = true;
  }

  return rc;
}

////////////////////////////////////////////////////////////////////////
// NAME       : TCPConnection::Close
// DESCRIPTION: Close the connection.
// PARAMETERS : -
// RETURNS    : -
////////////////////////////////////////////////////////////////////////

void TCPConnection:Close( void ) {
  if (client) {
    SDLNet_TCP_Close( client );
    client = NULL;
  }
}

////////////////////////////////////////////////////////////////////////
// NAME       : TCPConnection::Send
// DESCRIPTION: Send a buffer over the network.
// PARAMETERS : buf - buffer to send
// RETURNS    : TRUE if buffer was sent successfully, FALSE on error
////////////////////////////////////////////////////////////////////////

bool TCPConnection::Send( const NetBuffer &buf, Uint16 type ) {
  bool rc = false;
  TCPSocket dest = NULL;

  if (server && (client || Open())) {
    dest = client;
  } else {
    dest = socket;
  }

  if (dest) {
    int len;
    struct PacketHeader hdr;

    hdr.id = SDL_SwapLE32(0xdeadbeef); // FIXME
    hdr.type = SDL_SwapLE16(type);
    hdr.version = 0;
    hdr.reserved = 0;
    hdr.size = SDL_SwapLE32(buf.size);
    hdr.crc = SDL_SwapLE32(0);         // FIXME

    len = SDLNet_TCP_Send( dest, &hdr, sizeof(struct PacketHeader) );
    if ( len < sizeof(struct PacketHeader) )
      printf( "SDLNet_TCP_Send (header): %s\n", SDLNet_GetError() );
    else
    {
      len = SDLNet_TCP_Send( dest, buf.GetData(), buf.Size() );
      if ( len < buf.Size() )
        printf( "SDLNet_TCP_Send (data): %s\n", SDLNet_GetError() );
      else
        rc = true;
    }
  }

  return rc;
}

////////////////////////////////////////////////////////////////////////
// NAME       : TCPConnection::Receive
// DESCRIPTION: Receive a buffer over the network. If a buffer is
//              returned, it must be freed by the caller after use.
// PARAMETERS : -
// RETURNS    : received buffer or NULL on error
////////////////////////////////////////////////////////////////////////

NetBuffer *TCPConnection::Receive( void ) {
  NetBuffer *buf = NULL;
  TCPsocket src = NULL;

  if (server &&  (client || Open())) {
    src = client;
  } else {
    src = socket;
  }

  if (src) {
    struct PacketHeader hdr;
    char *buf = (char *)&hdr;
    int len, read = 0;

    do  {
      len = SDLNet_TCP_Recv( src, buf, sizeof(struct PacketHeader) - read );

      if ( len <= 0 ) {
        printf( "SDLNet_TCP_Recv (header): %s\n", SDLNet_GetError() );
        return NULL;
      }

      read += len;
    } while (read < sizeof(struct PacketHeader));

    hdr.id = SDL_SwapLE32(hdr.id);
    hdr.type = SDL_SwapLE16(hdr.type);
    hdr.size = SDL_SwapLE32(hdr.size);
    hdr.crc = SDL_SwapLE32(hdr.crc);

    if (hdr.id != 0xdeadbeef)  {   // FIXME
      printf( "TCP_Receive: Received unknown ID %ld\n", hdr.id );
      return NULL;
    }

    // FIXME: check crc

    buf = new NetBuffer( hdr.size );

    read = 0;
    do  {
      len = SDLNet_TCP_Recv( src, buf.GetData(), hdr.size - read );

      if ( len <= 0 ) {
        printf( "SDLNet_TCP_Recv (data): %s\n", SDLNet_GetError() );
        delete buf;
        return NULL;
      }

      read += len;
    } while (read < hdr.size);
  }

  return buf;
}

// Crimson Fields -- a game of tactical warfare
// Copyright (C) 2000-2006 Jens Granseuer
//
// 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 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY 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.
//

///////////////////////////////////////////////////////////////
// network.h - networking
///////////////////////////////////////////////////////////////

#ifndef _INCLUDE_NETWORK_H
#define _INCLUDE_NETWORK_H

#include <string>
#include <vector>
using namespace std;

#include "SDL_net.h"

#include "fileio.h"

class NetBuffer : public MemBuffer {
public:
  NetBuffer( int size );
  ~NetBuffer( void );

  int Size( void ) const { return size; }
  void *GetData( void ) const { return buffer; }

private:
  int size;
  void *buffer;
}

class TCPConnection {
public:
  TCPConnection( const string &server, Uint16 port );
  TCPConnection( Uint16 port );
  ~TCPConnection( void );

  bool Open( void );
  void Close( void );

  bool Send( const NetBuffer &buf );
  NetBuffer *Receive( void );

private:
  int Init( const char *ipaddr, Uint16 port );

  TCPsocket socket;
  TCPsocket client;
  bool server;
};

#endif  /* _INCLUDE_NETWORK_H */