Logo Search packages:      
Sourcecode: blender version File versions  Download package

v_connection.c

/*
**
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "v_cmd_buf.h"
#include "v_network_in_que.h"
#include "v_network_out_que.h"
#include "v_cmd_gen.h"
#include "v_connection.h"
#include "v_encryption.h"
#include "v_util.h"

#if !defined(V_GENERATE_FUNC_MODE)
#include "verse.h"

#define CONNECTION_CHUNK_SIZE 16
#define V_MAX_CONNECT_PACKET_SIZE   1500
#define V_CON_MAX_MICROSECOND_BETWEEN_SENDS     100
#define V_RE_CONNECTON_TIME_OUT 4
#define V_CONNECTON_TIME_OUT 30

typedef struct {
      VNetOutQueue      *out_queue;
      VNetInQueue       in_queue;
      VNetworkAddress   network_address;
      boolean                 connected;
      unsigned int      avatar;
/*    unsigned int      packet_id;*/
      int32             timedelta_s;
      uint32                  timedelta_f;
      boolean                 destroy_flag;
      void              *ordered_storage;
      char              name[V_ENCRYPTION_LOGIN_KEY_SIZE / 2];
      char              pass[V_ENCRYPTION_LOGIN_KEY_SIZE / 2];
      VConnectStage     connect_stage;
      unsigned int      stage_atempts;
      uint8             key_my[V_ENCRYPTION_LOGIN_KEY_FULL_SIZE];
      uint8             key_other[V_ENCRYPTION_LOGIN_KEY_FULL_SIZE];
      uint8             key_data[V_ENCRYPTION_DATA_KEY_SIZE];
      uint8             *expected_key;
} VConnection;

static struct {
      VConnection       *con;
      unsigned int      con_count;
      unsigned int      current_connection;
      VNetworkAddress   *connect_address;
      void              *unified_func_storage;
      uint16                  connect_port;
      unsigned int      pending_packets;
      uint8             host_id[V_ENCRYPTION_LOGIN_KEY_FULL_SIZE];
} VConData;

extern void cmd_buf_init(void);

void v_con_init(void) /* since verse doesnt have an init function this function is runned over an ove ard starts whit a check it it has run before */
{
      static boolean v_con_initialized = FALSE;

      if(v_con_initialized)
            return;
      cmd_buf_init();
      v_con_initialized = TRUE;
      VConData.con = malloc(CONNECTION_CHUNK_SIZE * sizeof *VConData.con);
      memset(VConData.con, 0, CONNECTION_CHUNK_SIZE * sizeof *VConData.con);  /* Clear the memory. */
      VConData.con_count = 0;
      VConData.pending_packets = 0;
/*    v_e_connect_create_key(&VConData.host_id[V_ENCRYPTION_LOGIN_PRIVATE_START],
                   &VConData.host_id[V_ENCRYPTION_LOGIN_PUBLIC_START],
                   &VConData.host_id[V_ENCRYPTION_LOGIN_N_START]);*/ /* default host id if none is set by user */
}

void verse_set_port(uint16 port)
{
      v_n_set_port(port);
}

void verse_host_id_create(uint8 *id)
{
      v_e_connect_create_key(&id[V_ENCRYPTION_LOGIN_PRIVATE_START],
                         &id[V_ENCRYPTION_LOGIN_PUBLIC_START], &id[V_ENCRYPTION_LOGIN_N_START]);
}

void verse_host_id_set(uint8 *id)
{
      memcpy(VConData.host_id, id, V_ENCRYPTION_LOGIN_KEY_FULL_SIZE);
}

extern void *v_fs_create_func_storage(void);
extern void *v_create_ordered_storage(void);
extern void v_destroy_ordered_storage(void *data);

void *v_con_connect(uint32 ip, uint16 port, VConnectStage stage) /* creates a new connection slot */
{
      v_con_init(); /* init connections, if not done yet */
      if((VConData.con_count - 1) % CONNECTION_CHUNK_SIZE == 0) /* do we need more slots for connections, then reallocate more space */
            VConData.con = realloc(VConData.con, (sizeof *VConData.con) * (VConData.con_count + CONNECTION_CHUNK_SIZE));
      VConData.con[VConData.con_count].out_queue = v_noq_create_network_queue(); /* create a out queue fo all out going commands */
      v_niq_clear(&VConData.con[VConData.con_count].in_queue); /* clear and init the que of incomming packets.*/
      VConData.con[VConData.con_count].connected = FALSE; /* not yet propperly connected and should not accept commands yet */
      VConData.con[VConData.con_count].network_address.ip = ip; /* ip address of other side */
      VConData.con[VConData.con_count].network_address.port = port; /* port used by other side */
      VConData.con[VConData.con_count].avatar = 0; /* no avatar set yet*/
/*    VConData.con[VConData.con_count].packet_id = 2;*/
      VConData.con[VConData.con_count].destroy_flag = FALSE; /* this is a flag that is set once the connection is about to be destroyed.*/
      VConData.con[VConData.con_count].ordered_storage = v_create_ordered_storage();
      VConData.con[VConData.con_count].name[0] = 0; /* nouser name set yet */
      VConData.con[VConData.con_count].pass[0] = 0; /* no password set yet */
      VConData.con[VConData.con_count].connect_stage = stage; /* this is the stage of the connection, it show if the connection is ready, the init state depends if this is a client or host */
      VConData.con[VConData.con_count].stage_atempts = 0; /* each stage in the connection prosess is atempted multiple times to avoid failiure if packets get lost*/
      VConData.con[VConData.con_count].timedelta_s = 0; /* number of seconds since last incomming packet to the connection*/
      VConData.con[VConData.con_count].timedelta_f = 0; /* number of fractions of a second since last incomming packet to the connection*/
      VConData.con[VConData.con_count].expected_key = NULL; /* expected hist id if this is a client */
      VConData.current_connection = VConData.con_count; /* set the new connection to the current*/
      ++VConData.con_count; /* add one to the number of connections*/
      return VConData.con[VConData.current_connection].out_queue;
}

void verse_session_destroy(VSession session) /* a session can not be destroyed right away, because this function might be called inside a call back from the session it tryes tpo destroy, therfor it only markes it*/
{
      unsigned int i;
      for(i = 0; i < VConData.con_count && VConData.con[i].out_queue != session; i++);
      if(i < VConData.con_count)
      {
            VConData.con[i].destroy_flag = TRUE;
      }
}

void verse_session_set(VSession session) /* find a session and make it the current*/
{
      unsigned int i;
      for(i = 0; i < VConData.con_count && session != VConData.con[i].out_queue; i++);
      if(i < VConData.con_count)
            VConData.current_connection = i;
}

VSession verse_session_get(void)
{
      if(VConData.current_connection < VConData.con_count)
            return VConData.con[VConData.current_connection].out_queue;
      return NULL;
}

uint32 v_co_find_connection(uint32 ip, uint16 port) /* if a packet comes form a ip address what connection does it belong to? */
{
      unsigned int i;

      for(i = 0; i < VConData.con_count; i++)
      {
            if(ip == VConData.con[i].network_address.ip &&
               port == VConData.con[i].network_address.port &&
               VConData.con[i].destroy_flag == 0)
            {
                  return i;
            }
      }
      return -1;
}

boolean v_co_switch_connection(uint32 ip, uint16 port) /* switches to the current connection to one ip address if it exists */
{
      unsigned int i;
      for(i = 0; i < VConData.con_count; i++)
      {
            if(ip == VConData.con[i].network_address.ip && port == VConData.con[i].network_address.port)
            {
                  VConData.current_connection = i;
                  return TRUE;
            }
      }
      return FALSE;
}

void v_con_inqueue_timer_update(void)
{
      if(VConData.current_connection < VConData.con_count)
      {
            v_niq_timer_update(&VConData.con[VConData.current_connection].in_queue);
      }
}

/*
extern void v_fs_buf_unpack(const uint8 *data, unsigned int length);
extern void v_fs_buf_store_pack(uint8 *data, unsigned int length);
extern boolean    v_fs_buf_unpack_stored(void);
*/
extern void v_unpack_connection(const char *buf, unsigned int buffer_length);

extern void verse_send_packet_nak(uint32 packet_id);
extern void v_callback_connect_terminate(const char *bye);
extern boolean    v_connect_unpack_ping(const char *buf, size_t buffer_length, uint32 ip, uint16 port);
extern void v_ping_update(void);
void v_fs_unpack_beginning(uint8 *data, unsigned int length);

/* Main function that receives and distributes all incoming packets. */
boolean v_con_network_listen(void)
{
      VNetworkAddress address;
      uint8 buf[V_MAX_CONNECT_PACKET_SIZE], *store;
      int size = 0;
      unsigned int connection;
      uint32 packet_id;
      boolean ret = FALSE;

      v_con_init(); /* Init if needed. */
      connection = VConData.current_connection; /* Store current connection in a local variable so that we can restore it later. */
      size = v_n_receive_data(&address, buf, sizeof buf); /* Ask for incoming data from the network. */
      while(size != -1 && size != 0) /* Did we get any data? */
      {
            VConData.current_connection = v_co_find_connection(address.ip, address.port); /* Is there a connection matching the IP and port? */
            vnp_raw_unpack_uint32(buf, &packet_id); /* Unpack the ID of the packet. */
/*          printf("got packet ID %u, %d bytes, connection %u\n", packet_id, size, VConData.current_connection);*/
            if(VConData.current_connection < VConData.con_count &&
               !(VConData.con[VConData.current_connection].connect_stage == V_CS_CONNECTED && packet_id == 0)) /* If this isn't a packet from an existing connection, disregard it. */
            {
                  if(VConData.con[VConData.current_connection].connect_stage == V_CS_CONNECTED) /* Is this connection initialized? */
                  {
                        store = v_niq_store(&VConData.con[VConData.current_connection].in_queue, size, packet_id); /* Store the packet. */
                        if(store != NULL)
                        {
                              VConData.pending_packets++; /* We now have one more packet pending unpack. */
                              v_e_data_decrypt_packet(store, buf, size, VConData.con[VConData.current_connection].key_data); /* Decrypt the packet. */
                              v_fs_unpack_beginning(store, size);
                        }
                  }
                  else
                  {
                        v_unpack_connection(buf, size); /* This is an ongoing connecton-attempt. */
                        v_niq_timer_update(&VConData.con[VConData.current_connection].in_queue);
                  }
            }
            else if(v_connect_unpack_ping(buf, size, address.ip, address.port))     /* Ping handled. */
                  ;
            else if(v_fs_func_accept_connections()) /* Do we accept connection-attempts? */
            {
                  if(VConData.current_connection >= VConData.con_count ||
                     V_RE_CONNECTON_TIME_OUT < v_niq_time_out(&VConData.con[VConData.current_connection].in_queue)) /* Is it a new client, or an old client that we haven't heard form in some time? */
                  {
                        if(VConData.current_connection < VConData.con_count)
                        {
                              VConData.con[VConData.current_connection].network_address.ip = 0;
                              VConData.con[VConData.current_connection].destroy_flag = TRUE; /* Destroy old connection if there is one. */
                        }
                        v_con_connect(address.ip, address.port, V_CS_IDLE); /* Create a new connection. */
                        v_unpack_connection(buf, size); /* Unpack the connection-attempt. */
                  }
            }
            else
            {
                  fprintf(stderr, __FILE__ ": Unhandled packet--dropping\n");
                  if(VConData.con_count > 0)
                  {
                        fprintf(stderr, __FILE__ ": State: connections=%u, current=%u (stage %u), packet_id=%u\n",
                              VConData.con_count,
                              VConData.current_connection,
                              (VConData.current_connection < VConData.con_count) ? VConData.con[VConData.current_connection].connect_stage : 0,
                              packet_id);
                  }
            }
            size = v_n_receive_data(&address, buf, sizeof buf); /* See if there are more incoming packets. */
            ret = TRUE;
      }
      VConData.current_connection = connection; /* Reset the current connection. */

      return ret;
}

extern void v_update_connection_pending(boolean resend);

boolean v_con_callback_update(void)
{
      static unsigned int seconds;
      boolean     output = FALSE;
      size_t      size; 
      unsigned int connection, s;
      VNetInPacked      *p;

      v_n_get_current_time(&s, NULL);
      connection = VConData.current_connection;
      for(VConData.current_connection = 0; VConData.current_connection < VConData.con_count; VConData.current_connection++)
            if(VConData.con[VConData.current_connection].connect_stage != V_CS_CONNECTED)
                  v_update_connection_pending(s != seconds);
      seconds = s;
      VConData.current_connection = connection;
      if(VConData.pending_packets == 0)
            return FALSE;
      if(VConData.con[VConData.current_connection].connect_stage == V_CS_CONNECTED)
      {
            while((p = v_niq_get(&VConData.con[VConData.current_connection].in_queue, &size)) != NULL)
            {
                  VConData.pending_packets--;
                  v_fs_unpack(p->data, size);
                  v_niq_release(&VConData.con[VConData.current_connection].in_queue, p);
                  output = TRUE;
            }
            v_con_network_listen();
      }
      return output;
}

void verse_callback_update(unsigned int microseconds)
{
      unsigned int connection, passed;

      v_ping_update();  /* Deliver any pending pings. */
      connection = VConData.current_connection;
      for(VConData.current_connection = 0; VConData.current_connection < VConData.con_count; VConData.current_connection++)
      {
            if(VConData.con[VConData.current_connection].connect_stage == V_CS_CONNECTED)
                  v_noq_send_queue(VConData.con[VConData.current_connection].out_queue, &VConData.con[VConData.current_connection].network_address);
            if(VConData.con[VConData.current_connection].destroy_flag == TRUE)
            {
                  v_noq_destroy_network_queue(VConData.con[VConData.current_connection].out_queue);
                  VConData.pending_packets -= v_niq_free(&VConData.con[VConData.current_connection].in_queue);
                  v_destroy_ordered_storage(VConData.con[VConData.current_connection].ordered_storage);
                  if(VConData.con[VConData.current_connection].expected_key != NULL)
                        free(VConData.con[VConData.current_connection].expected_key);
                  if(VConData.con_count - 1 != VConData.current_connection)
                        VConData.con[VConData.current_connection] = VConData.con[VConData.con_count - 1];
                  VConData.con_count--;
                  if(connection >= VConData.con_count)
                        VConData.current_connection = 0;
                  return;
            }
      }
      VConData.current_connection = connection;

      if(VConData.con_count > 0)
      {
/*          printf("checking timeout of stage %d connection %u\n",
                   VConData.con[VConData.current_connection].connect_stage, VConData.current_connection);
*/          if(V_CONNECTON_TIME_OUT < v_niq_time_out(&VConData.con[VConData.current_connection].in_queue))
            {
                  if(VConData.con[VConData.current_connection].connect_stage != V_CS_CONNECTED)
                  {
                        VConData.con[VConData.current_connection].destroy_flag = TRUE;
                  }
                  else
                        v_callback_connect_terminate("connection timed out");
            }
      }

      v_con_network_listen();
      if(VConData.con_count > 0)
            if(v_con_callback_update())
                  return;
      for(passed = 0; passed < microseconds && VConData.pending_packets == 0;)
      {
            boolean     update;
            if(microseconds - passed > V_CON_MAX_MICROSECOND_BETWEEN_SENDS)   /* Still a long way to go? */
                  passed += v_n_wait_for_incoming(V_CON_MAX_MICROSECOND_BETWEEN_SENDS);
            else
                  passed += v_n_wait_for_incoming(microseconds - passed);
            do
            {
                  update = v_con_network_listen();
                  connection = VConData.current_connection;
                  for(VConData.current_connection = 0; VConData.current_connection < VConData.con_count; VConData.current_connection++)
                  {
                        if(VConData.con[VConData.current_connection].connect_stage == V_CS_CONNECTED)
                        {
                              if(v_noq_send_queue(VConData.con[VConData.current_connection].out_queue, &VConData.con[VConData.current_connection].network_address))
                                    update = TRUE;
                        }
                  }
                  VConData.current_connection = connection;
            } while(update);
      }
      if(VConData.con_count > 0)
            v_con_callback_update();
}

void v_con_set_name_pass(const char *name, const char *pass)
{
      v_strlcpy(VConData.con[VConData.current_connection].name, name, sizeof VConData.con[VConData.current_connection].name);
      v_strlcpy(VConData.con[VConData.current_connection].pass, pass, sizeof VConData.con[VConData.current_connection].pass);
}

const char * v_con_get_name(void)
{
      return VConData.con[VConData.current_connection].name;
}

const char * v_con_get_pass(void)
{
      return VConData.con[VConData.current_connection].pass;
}

void v_con_set_connect_stage(VConnectStage stage)
{
      VConData.con[VConData.current_connection].connect_stage = stage;
      VConData.con[VConData.current_connection].stage_atempts = 0;
}

VConnectStage v_con_get_connect_stage(void)
{
      return VConData.con[VConData.current_connection].connect_stage;
}

uint8 *v_con_get_my_key(void)
{
      return VConData.con[VConData.current_connection].key_my;
}

uint8 *v_con_get_other_key(void)
{
      return VConData.con[VConData.current_connection].key_other;
}

uint8 **v_con_get_expected_key(void)
{
      return &VConData.con[VConData.current_connection].expected_key;
}

uint8 * v_con_get_host_id(void)
{
      return VConData.host_id;
}

void v_con_set_data_key(const uint8 *key)
{
      memcpy(VConData.con[VConData.current_connection].key_data, key, V_ENCRYPTION_DATA_KEY_SIZE);
}

const uint8 * v_con_get_data_key(void)
{
      return VConData.con[VConData.current_connection].key_data;
}

void * v_con_get_network_queue(void)
{
      return VConData.con[VConData.current_connection].out_queue;
}

VNetworkAddress * v_con_get_network_address(void)
{
      return &VConData.con[VConData.current_connection].network_address;
}

void * v_con_get_ordered_storage(void)
{
      return VConData.con[VConData.current_connection].ordered_storage;
}

void v_con_set_avatar(uint32 avatar)
{
      VConData.con[VConData.current_connection].avatar = avatar;
}

uint32 verse_session_get_avatar(void)
{
      return VConData.con[VConData.current_connection].avatar;
}

void verse_session_get_time(uint32 *seconds, uint32 *fractions)
{
      uint32 s, f;
      v_n_get_current_time(&s, &f);
      if((uint32)~0 - f < VConData.con[VConData.current_connection].timedelta_f)
            s++;
      if(seconds != NULL) 
      {
            if(VConData.con[VConData.current_connection].timedelta_s < 0)
                  *seconds = s - (uint32)(-VConData.con[VConData.current_connection].timedelta_s);
            else
                  *seconds = s + VConData.con[VConData.current_connection].timedelta_s;
      }
      if(fractions != NULL)
            *fractions = f + VConData.con[VConData.current_connection].timedelta_f;
}

void v_con_set_time(uint32 seconds, uint32 fractions)
{
      uint32 s, f;
      v_n_get_current_time(&s, &f);

      if(f < fractions)
            s--;
      if (s < seconds)
            VConData.con[VConData.current_connection].timedelta_s = -(int)(seconds - s);
      else
            VConData.con[VConData.current_connection].timedelta_s = (int)(s - seconds);
      VConData.con[VConData.current_connection].timedelta_f = f - fractions;
}

#endif

Generated by  Doxygen 1.6.0   Back to index