Exemple #1
0
/****************************************************************************
  Set the packet header field lengths used after the login protocol,
  after the capability of the connection could be checked.
****************************************************************************/
static inline void packet_header_set(struct packet_header *packet_header)
{
  /* Ensure we have values initialized in packet_header_init(). */
  fc_assert(packet_header->length == DIOT_UINT16);
  fc_assert(packet_header->type == DIOT_UINT8);

  packet_header->length = DIOT_UINT16;
  packet_header->type = DIOT_UINT16;
}
Exemple #2
0
/*****************************************************************************
  Closes a lua console.
*****************************************************************************/
static void luaconsole_dialog_destroy(struct luaconsole_data *pdialog)
{
  fc_assert_ret(NULL != pdialog);

  if (pdialog->shell) {
    gui_dialog_destroy(pdialog->shell);
    fc_assert(NULL == pdialog->shell);
  }
  fc_assert(NULL == pdialog->message_area);
}
Exemple #3
0
/**************************************************************************
  Initialise the unit data from the ruleset for the advisors.
**************************************************************************/
void adv_units_ruleset_init(void)
{
  bv_special special;
  bv_bases bases;
  bv_roads roads;

  BV_CLR_ALL(special);
  BV_CLR_ALL(bases);
  BV_CLR_ALL(roads); /* Can it move even without road */

  unit_class_iterate(pclass) {
    bool move_land_enabled  = FALSE; /* Can move at some land terrains */
    bool move_land_disabled = FALSE; /* Cannot move at some land terrains */
    bool move_sea_enabled   = FALSE; /* Can move at some ocean terrains */
    bool move_sea_disabled  = FALSE; /* Cannot move at some ocean terrains */

    terrain_type_iterate(pterrain) {
      if (is_native_to_class(pclass, pterrain, special, bases, roads)) {
        /* Can move at terrain */
        if (is_ocean(pterrain)) {
          move_sea_enabled = TRUE;
        } else {
          move_land_enabled = TRUE;
        }
      } else {
        /* Cannot move at terrain */
        if (is_ocean(pterrain)) {
          move_sea_disabled = TRUE;
        } else {
          move_land_disabled = TRUE;
        }
      }
    } terrain_type_iterate_end;

    if (move_land_enabled && !move_land_disabled) {
      pclass->adv.land_move = MOVE_FULL;
    } else if (move_land_enabled && move_land_disabled) {
      pclass->adv.land_move = MOVE_PARTIAL;
    } else {
      fc_assert(!move_land_enabled);
      pclass->adv.land_move = MOVE_NONE;
    }

    if (move_sea_enabled && !move_sea_disabled) {
      pclass->adv.sea_move = MOVE_FULL;
    } else if (move_sea_enabled && move_sea_disabled) {
      pclass->adv.sea_move = MOVE_PARTIAL;
    } else {
      fc_assert(!move_sea_enabled);
      pclass->adv.sea_move = MOVE_NONE;
    }

  } unit_class_iterate_end;
}
Exemple #4
0
/****************************************************************************
  Initializes all player research structure.
****************************************************************************/
void player_researches_init(void)
{
  int i;

  /* Ensure we have enough space for players or teams. */
  fc_assert(ARRAY_SIZE(research_array) >= team_slot_count());
  fc_assert(ARRAY_SIZE(research_array) >= player_slot_count());

  memset(research_array, 0, sizeof(*research_array));
  for (i = 0; i < ARRAY_SIZE(research_array); i++) {
    research_array[i].tech_goal = A_UNSET;
    research_array[i].researching = A_UNSET;
    research_array[i].researching_saved = A_UNKNOWN;
  }
}
Exemple #5
0
/**************************************************************************
  Measure the time between the calls.  Used to see where in the AI too
  much CPU is being used.
**************************************************************************/
void TIMING_LOG(enum ai_timer timer, enum ai_timer_activity activity)
{
  static int turn = -1;
  int i;

  if (turn == -1) {
    for (i = 0; i < AIT_LAST; i++) {
      aitimer[i][0] = timer_new(TIMER_CPU, TIMER_ACTIVE);
      aitimer[i][1] = timer_new(TIMER_CPU, TIMER_ACTIVE);
      recursion[i] = 0;
    }
  }

  if (game.info.turn != turn) {
    turn = game.info.turn;
    for (i = 0; i < AIT_LAST; i++) {
      timer_clear(aitimer[i][0]);
    }
    fc_assert(activity == TIMER_START);
  }

  if (activity == TIMER_START && recursion[timer] == 0) {
    timer_start(aitimer[timer][0]);
    timer_start(aitimer[timer][1]);
    recursion[timer]++;
  } else if (activity == TIMER_STOP && recursion[timer] == 1) {
    timer_stop(aitimer[timer][0]);
    timer_stop(aitimer[timer][1]);
    recursion[timer]--;
  }
}
Exemple #6
0
/*****************************************************************************
  Mark any, if exported, full userdata representing 'object' in
  the current script state as 'Nonexistent'.
  This changes the type of the lua variable.
*****************************************************************************/
void luascript_remove_exported_object(struct fc_lua *fcl, void *object)
{
  if (fcl && fcl->state) {
    fc_assert_ret(object != NULL);

    /* The following is similar to tolua_release(..) in src/lib/tolua_map.c */
    /* Find the userdata representing 'object' */
    lua_pushstring(fcl->state,"tolua_ubox");
    /* stack: ubox */
    lua_rawget(fcl->state, LUA_REGISTRYINDEX);
    /* stack: ubox u */
    lua_pushlightuserdata(fcl->state, object);
    /* stack: ubox ubox[u] */
    lua_rawget(fcl->state, -2);

    if (!lua_isnil(fcl->state, -1)) {
      fc_assert(object == tolua_tousertype(fcl->state, -1, NULL));
      /* Change API type to 'Nonexistent' */
      /* stack: ubox ubox[u] mt */
      tolua_getmetatable(fcl->state, "Nonexistent");
      lua_setmetatable(fcl->state, -2);
      /* Set the userdata payload to NULL */
      *((void **)lua_touserdata(fcl->state, -1)) = NULL;
      /* Remove from ubox */
      /* stack: ubox ubox[u] u */
      lua_pushlightuserdata(fcl->state, object);
      /* stack: ubox ubox[u] u nil */
      lua_pushnil(fcl->state);
      lua_rawset(fcl->state, -4);
    }
    lua_pop(fcl->state, 2);
  }
}
Exemple #7
0
/**************************************************************************
 This function is called when the client received a new input from the
 server.
**************************************************************************/
void input_from_server(int fd)
{
  int nb;

  fc_assert_ret(fd == client.conn.sock);

  nb = read_from_connection(&client.conn, FALSE);
  if (0 <= nb) {
    enum packet_type type;

    agents_freeze_hint();
    while (client.conn.used) {
      bool result;
      void *packet = get_packet_from_connection(&client.conn,
						&type, &result);

      if (result) {
        fc_assert_action(packet != NULL, break);
	client_packet_input(packet, type);
	free(packet);
      } else {
        fc_assert(packet == NULL);
	break;
      }
    }
    if (client.conn.used) {
      agents_thaw_hint();
    }
  } else if (-2 == nb) {
Exemple #8
0
/**************************************************************************
  Test and log for sending player attribute_block
**************************************************************************/
void pre_send_packet_player_attribute_chunk(struct connection *pc,
                                            struct packet_player_attribute_chunk
                                            *packet)
{
  fc_assert(packet->total_length > 0
            && packet->total_length < MAX_ATTRIBUTE_BLOCK);
  /* 500 bytes header, just to be sure */
  fc_assert(packet->chunk_length > 0
            && packet->chunk_length < MAX_LEN_PACKET - 500);
  fc_assert(packet->chunk_length <= packet->total_length);
  fc_assert(packet->offset >= 0 && packet->offset < packet->total_length);

  log_packet("sending attribute chunk %d/%d %d",
             packet->offset, packet->total_length, packet->chunk_length);

}
Exemple #9
0
/***************************************************************************
  Look up the service at hostname:port.
***************************************************************************/
struct fc_sockaddr_list *net_lookup_service(const char *name, int port,
					    enum fc_addr_family family)
{
  /* IPv6-enabled Freeciv always has HAVE_GETADDRINFO, IPv4-only Freeciv not
   * necessarily */
#ifdef HAVE_GETADDRINFO
  return net_lookup_getaddrinfo(name, port, family);
#else  /* HAVE_GETADDRINFO */

  struct sockaddr_in *sock4;
  struct hostent *hp;
  struct fc_sockaddr_list *addrs = fc_sockaddr_list_new();
  union fc_sockaddr *result = fc_malloc(sizeof(result));

  sock4 = &result->saddr_in4;

  fc_assert(family != FC_ADDR_IPV6);

  result->saddr.sa_family = AF_INET;
  sock4->sin_port = htons(port);

  if (!name) {
    sock4->sin_addr.s_addr = htonl(INADDR_ANY);
    fc_sockaddr_list_append(addrs, result);

    return addrs;
  }

#if defined(HAVE_INET_ATON)
  if (inet_aton(name, &sock4->sin_addr) != 0) {
    fc_sockaddr_list_append(addrs, result);

    return addrs;
  }
#else  /* HAVE_INET_ATON */
  if ((sock4->sin_addr.s_addr = inet_addr(name)) != INADDR_NONE) {
    fc_sockaddr_list_append(addrs, result);

    return addrs;
  }
#endif /* HAVE_INET_ATON */
  hp = gethostbyname(name);
  if (!hp || hp->h_addrtype != AF_INET) {
    FC_FREE(result);

    return addrs;
  }

  memcpy(&sock4->sin_addr, hp->h_addr, hp->h_length);
  fc_sockaddr_list_append(addrs, result);

  return addrs;

#endif /* !HAVE_GETADDRINFO */

}
Exemple #10
0
/****************************************************************************
  Thaw the drawing of the map.
****************************************************************************/
void mapview_thaw(void)
{
  if (1 < mapview_frozen_level) {
    mapview_frozen_level--;
  } else {
    fc_assert(0 < mapview_frozen_level);
    mapview_frozen_level = 0;
    dirty_all();
  }
}
Exemple #11
0
/**************************************************************************
  Initialize base audio system. Note that this function is called very
  early at the client startup. So for example logging isn't available.
**************************************************************************/
void audio_init(void)
{
  audio_none_init();
  fc_assert(num_plugins_used == 1);
  selected_plugin = 0;

#ifdef AUDIO_SDL
  audio_sdl_init();
#endif
}
Exemple #12
0
/**************************************************************************
  Returns the extra help text of the command (translated).
  The caller must free this string.
**************************************************************************/
char *command_extra_help(const struct command *pcommand)
{
    if (pcommand->extra_help_func) {
        fc_assert(pcommand->extra_help == NULL);
        return pcommand->extra_help_func();
    } else if (pcommand->extra_help) {
        return fc_strdup(_(pcommand->extra_help));
    } else {
        return NULL;
    }
}
Exemple #13
0
/***************************************************************************
  Look up the service at hostname:port using getaddrinfo().
***************************************************************************/
static struct fc_sockaddr_list *net_lookup_getaddrinfo(const char *name,
						       int port,
						       enum fc_addr_family family)
{
  struct addrinfo hints;
  struct addrinfo *res;
  int err;
  char servname[8];
  int gafam;
  struct fc_sockaddr_list *addrs = fc_sockaddr_list_new();

  switch (family) {
    case FC_ADDR_IPV4:
      gafam = AF_INET;
      break;
    case FC_ADDR_IPV6:
      gafam = AF_INET6;
      break;
    case FC_ADDR_ANY:
      gafam = AF_UNSPEC;
      break;
    default:
      fc_assert(FALSE);

      return addrs;
  }

  /* Convert port to string for getaddrinfo() */
  fc_snprintf(servname, sizeof(servname), "%d", port);

  /* Use getaddrinfo() to lookup IPv6 addresses */
  memset(&hints, 0, sizeof(hints));
  hints.ai_family = gafam;
  hints.ai_socktype = SOCK_DGRAM; /* any type that uses sin6_port */
  hints.ai_flags = AI_PASSIVE | FC_AI_NUMERICSERV;
  err = getaddrinfo(name, servname, &hints, &res);

  if (err == 0) {
    struct addrinfo *current = res;

    while (current != NULL) {
      union fc_sockaddr *caddr = fc_malloc(sizeof(*caddr));

      memcpy(caddr, current->ai_addr, MIN(sizeof(*caddr), current->ai_addrlen));

      fc_sockaddr_list_append(addrs, caddr);

      current = current->ai_next;
    }
  }

  return addrs;
}
/****************************************************************************
  Return a pointer to the given "terrain" color.

  Each terrain has a color associated.  This is usually used to draw the
  overview.
****************************************************************************/
struct color *get_terrain_color(const struct tileset *t,
				const struct terrain *pterrain)
{
  if (pterrain) {
    struct color_system *colors = get_color_system(t);

    return ensure_color(&colors->terrain_colors[terrain_index(pterrain)]);
  } else {
    /* Always fails. */
    fc_assert(NULL != pterrain);
    return NULL;
  }
}
/**********************************************************************
  Not sure which module to put this in...
  It used to be that each nation had a color, when there was
  fixed number of nations.  Now base on player number instead,
  since still limited to less than 14.  Could possibly improve
  to allow players to choose their preferred color etc.
  A hack added to avoid returning more that COLOR_STD_RACE13.
  But really there should be more colors available -- jk.
***********************************************************************/
struct color *get_player_color(const struct tileset *t,
			       const struct player *pplayer)
{
  if (pplayer) {
    struct color_system *colors = get_color_system(t);
    int index = player_index(pplayer);

    fc_assert_ret_val(index >= 0 && colors->num_player_colors > 0, NULL);
    index %= colors->num_player_colors;
    return ensure_color(&colors->player_colors[index]);
  } else {
    /* Always fails. */
    fc_assert(NULL != pplayer);
    return NULL;
  }
}
Exemple #16
0
/***************************************************************************
  Gets size of address to fc_sockaddr. IPv6/IPv4 must be selected before
  calling this.
***************************************************************************/
int sockaddr_size(union fc_sockaddr *addr)
{
#ifdef IPV6_SUPPORT
  if (addr->saddr.sa_family == AF_INET6) {
    return sizeof(addr->saddr_in6);
  } else
#endif /* IPV6_SUPPORT */
  if (addr->saddr.sa_family == AF_INET) {
    return sizeof(addr->saddr_in4);
  } else {
    fc_assert(FALSE);

    log_error("Unsupported address family in socaddr_size()");

    return 0;
  }
}
Exemple #17
0
static int number_of_columns(int n)
{
#if 0
  /* This would require libm, which isn't worth it for this one little
   * function.  Since MAX_SELECT_UNITS is 100 already, the ifs
   * work fine.  */
  double sqrt(); double ceil();
  return ceil(sqrt((double)n/5.0));
#else
  fc_assert(MAX_SELECT_UNITS == 100);
  if(n<=5) return 1;
  else if(n<=20) return 2;
  else if(n<=45) return 3;
  else if(n<=80) return 4;
  else return 5;
#endif
}
Exemple #18
0
/*****************************************************************************
  Create citizens dialog
*****************************************************************************/
static struct citizens_dialog
  *citizens_dialog_create(const struct city *pcity)
{
  GtkWidget *frame, *sw;
  struct citizens_dialog *pdialog = fc_malloc(sizeof(struct citizens_dialog));
  int i;

  pdialog->pcity = pcity;
  pdialog->store = citizens_dialog_store_new();
  pdialog->sort
    = gtk_tree_model_sort_new_with_model(GTK_TREE_MODEL(pdialog->store));
  g_object_unref(pdialog->store);

  gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(pdialog->sort),
                                       citizens_dialog_default_sort_column(),
                                       GTK_SORT_DESCENDING);

  pdialog->list
    = gtk_tree_view_new_with_model(GTK_TREE_MODEL(pdialog->sort));
  gtk_widget_set_halign(pdialog->list, GTK_ALIGN_CENTER);
  g_object_unref(pdialog->sort);

  for (i = 0; i < num_citizens_cols; i++) {
    struct citizens_column *pcol;
    GtkCellRenderer *renderer;
    GtkTreeViewColumn *col;

    pcol = &citizens_cols[i];
    col = NULL;

    switch (pcol->type) {
    case COL_FLAG:
      renderer = gtk_cell_renderer_pixbuf_new();
      col = gtk_tree_view_column_new_with_attributes(_(pcol->title), renderer,
              "pixbuf", i, NULL);
      break;
    case COL_TEXT:
      renderer = gtk_cell_renderer_text_new();
      g_object_set(renderer, "style-set", TRUE, "weight-set", TRUE, NULL);

      col = gtk_tree_view_column_new_with_attributes(_(pcol->title), renderer,
              "text", i,
              "style", CITIZENS_DLG_COL_STYLE,
              "weight", CITIZENS_DLG_COL_WEIGHT,
              NULL);
      gtk_tree_view_column_set_sort_column_id(col, i);
      break;
    case COL_RIGHT_TEXT:
      renderer = gtk_cell_renderer_text_new();
      g_object_set(renderer, "style-set", TRUE, "weight-set", TRUE, NULL);

      col = gtk_tree_view_column_new_with_attributes(_(pcol->title), renderer,
              "text", i,
              "style", CITIZENS_DLG_COL_STYLE,
              "weight", CITIZENS_DLG_COL_WEIGHT,
              NULL);
      gtk_tree_view_column_set_sort_column_id(col, i);
      g_object_set(renderer, "xalign", 1.0, NULL);
      gtk_tree_view_column_set_alignment(col, 1.0);
      break;
    case COL_COLOR:
    case COL_BOOLEAN:
      /* These are not used. */
      fc_assert(pcol->type != COL_COLOR && pcol->type != COL_BOOLEAN);
      continue;
    }

    if (col) {
      gtk_tree_view_append_column(GTK_TREE_VIEW(pdialog->list), col);
    }
  }

  gtk_widget_set_hexpand(GTK_WIDGET(pdialog->list), TRUE);
  gtk_widget_set_vexpand(GTK_WIDGET(pdialog->list), TRUE);

  sw = gtk_scrolled_window_new(NULL, NULL);
  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
                                 GTK_POLICY_AUTOMATIC,
                                 GTK_POLICY_AUTOMATIC);
  gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
                                      GTK_SHADOW_NONE);
  gtk_container_add(GTK_CONTAINER(sw), pdialog->list);

  frame = gtk_frame_new(_("Citizens"));
  gtk_container_add(GTK_CONTAINER(frame), sw);

  pdialog->shell = frame;

  dialog_list_prepend(dialog_list, pdialog);

  citizens_dialog_refresh(pcity);

  return pdialog;
}
Exemple #19
0
/************************************************************************** 
  Finds the next (lowest) free port.
**************************************************************************/ 
int find_next_free_port(int starting_port, enum fc_addr_family family)
{
  int port;
  int s;
  int gafamily;
  bool found = FALSE;

#ifndef IPV6_SUPPORT
  fc_assert(family == FC_ADDR_IPV4 || family == FC_ADDR_ANY);
#endif

  switch (family) {
   case FC_ADDR_IPV4:
     gafamily = AF_INET;
     break;
#ifdef IPV6_SUPPORT
   case FC_ADDR_IPV6:
     gafamily = AF_INET6;
     break;
#endif /* IPV6_SUPPORT */
   case FC_ADDR_ANY:
     gafamily = AF_UNSPEC;
     break;
   default:
     fc_assert(FALSE);

     return -1;
  }

  s = socket(gafamily, SOCK_STREAM, 0);

  for (port = starting_port; !found ; port++) {
    /* HAVE_GETADDRINFO implies IPv6 support */
#ifdef HAVE_GETADDRINFO
    struct addrinfo hints;
    int err;
    char servname[8];
    struct addrinfo *res;

    fc_snprintf(servname, sizeof(servname), "%d", port);

    memset(&hints, 0, sizeof(hints));
    hints.ai_family = gafamily;
    hints.ai_socktype = SOCK_DGRAM;
    hints.ai_flags = AI_PASSIVE | FC_AI_NUMERICSERV;

    err = getaddrinfo(NULL, servname, &hints, &res);
    if (!err) {
      struct addrinfo *current = res;

      while (current != NULL && !found) {
        if (bind(s, current->ai_addr, current->ai_addrlen) == 0) {
          found = TRUE;
        }
        current = current->ai_next;
      }

      freeaddrinfo(res);
    }
#else /* HAVE_GETADDRINFO */
    union fc_sockaddr tmp;
    struct sockaddr_in *sock4;

    sock4 = &tmp.saddr_in4;
    memset(&tmp, 0, sizeof(tmp));
    sock4->sin_family = AF_INET;
    sock4->sin_port = htons(port);
    sock4->sin_addr.s_addr = htonl(INADDR_ANY);

    if (bind(s, &tmp.saddr, sockaddr_size(&tmp)) == 0) {
      found = TRUE;
    }
#endif /* HAVE_GETADDRINFO */
  }

  fc_closesocket(s);
  
  return port;
}
Exemple #20
0
/************************************************************************** 
  Finds the next (lowest) free port.
**************************************************************************/ 
int find_next_free_port(int starting_port, int highest_port,
                        enum fc_addr_family family,
                        char *net_interface, bool not_avail_ok)
{
  int port;
  int s;
  int gafamily;
  bool found = FALSE;

#ifndef IPV6_SUPPORT
  fc_assert(family == FC_ADDR_IPV4 || family == FC_ADDR_ANY);
#endif

  switch (family) {
   case FC_ADDR_IPV4:
     gafamily = AF_INET;
     break;
#ifdef IPV6_SUPPORT
   case FC_ADDR_IPV6:
     gafamily = AF_INET6;
     break;
#endif /* IPV6_SUPPORT */
   case FC_ADDR_ANY:
     gafamily = AF_UNSPEC;
     break;
   default:
     fc_assert(FALSE);
     log_error("Port from unsupported address family requested!");

     return -1;
  }

  for (port = starting_port; !found && highest_port > port; port++) {
    /* HAVE_GETADDRINFO implies IPv6 support */
#ifdef HAVE_GETADDRINFO
    struct addrinfo hints;
    int err;
    char servname[8];
    struct addrinfo *res;

    fc_snprintf(servname, sizeof(servname), "%d", port);

    memset(&hints, 0, sizeof(hints));
    hints.ai_family = gafamily;
    hints.ai_socktype = SOCK_DGRAM;
    hints.ai_flags = AI_PASSIVE | FC_AI_NUMERICSERV;

    err = getaddrinfo(net_interface, servname, &hints, &res);
    if (!err) {
      struct addrinfo *current = res;
      bool unusable = FALSE;

      while (current != NULL && !unusable) {
        s = socket(current->ai_family, SOCK_STREAM, 0);

        if (s == -1) {
          log_error("socket(): %s", fc_strerror(fc_get_errno()));
        } else {
          if (bind(s, current->ai_addr, current->ai_addrlen) != 0) {
            if (!not_avail_ok || fc_get_errno() != EADDRNOTAVAIL) {
              unusable = TRUE;
            }
          }
        }
        current = current->ai_next;
        fc_closesocket(s);
      }

      freeaddrinfo(res);

      if (!unusable && res != NULL) {
        found = TRUE;
      }
    }
#else /* HAVE_GETADDRINFO */
    union fc_sockaddr tmp;
    struct sockaddr_in *sock4;

    s = socket(gafamily, SOCK_STREAM, 0);

    sock4 = &tmp.saddr_in4;
    memset(&tmp, 0, sizeof(tmp));
    sock4->sin_family = AF_INET;
    sock4->sin_port = htons(port);
    if (net_interface != NULL) {
#if defined(HAVE_INET_ATON)
      if (inet_aton(net_interface, &sock4->sin_addr) == 0) {
#else /* HAVE_INET_ATON */
      sock4->sin_addr.s_addr = inet_addr(net_interface);
      if (sock4->sin_addr.s_addr == INADDR_NONE) {
#endif /* HAVE_INET_ATON */
        struct hostent *hp;

        hp = gethostbyname(net_interface);
        if (hp == NULL) {
          log_error("No hostent for %s!", net_interface);

          return -1;
        }
        if (hp->h_addrtype != AF_INET) {
          log_error("Requested IPv4 address for %s, got something else! (%d)",
                    net_interface, hp->h_addrtype);

          return -1;
        }

        memcpy(&sock4->sin_addr, hp->h_addr, hp->h_length);
      }
    } else {
      sock4->sin_addr.s_addr = htonl(INADDR_ANY);
    }

    if (bind(s, &tmp.saddr, sockaddr_size(&tmp)) == 0) {
      found = TRUE;
    }

    fc_closesocket(s);
#endif /* HAVE_GETADDRINFO */
  }

  if (!found) {
    log_error("None of the ports %d - %d is available.",
              starting_port, highest_port);

    return -1;
  }

  /* Rollback the last increment from the loop, back to the port
   * number found to be free. */
  port--;

  return port;
}
Exemple #21
0
/****************************************************************************
  Free the vision source.
****************************************************************************/
void vision_free(struct vision *vision)
{
  fc_assert(-1 == vision->radius_sq[V_MAIN]);
  fc_assert(-1 == vision->radius_sq[V_INVIS]);
  free(vision);
}
Exemple #22
0
/**************************************************************** 
forks a server if it can. returns FALSE is we find we couldn't start
the server.
*****************************************************************/ 
bool client_start_server(void)
{
#if !defined(HAVE_WORKING_FORK) && !defined(WIN32_NATIVE)
  /* Can't do much without fork */
  return FALSE;
#else /* HAVE_WORKING_FORK || WIN32_NATIVE */
  char buf[512];
  int connect_tries = 0;
# ifdef WIN32_NATIVE
  STARTUPINFO si;
  PROCESS_INFORMATION pi;

  char savesdir[MAX_LEN_PATH];
  char scensdir[MAX_LEN_PATH];
  char options[512];
  char cmdline1[512];
  char cmdline2[512];
  char cmdline3[512];
  char cmdline4[512];
  char logcmdline[512];
  char scriptcmdline[512];
  char savescmdline[512];
  char scenscmdline[512];
# endif /* WIN32_NATIVE */

#ifdef IPV6_SUPPORT
  /* We want port that is free in IPv4 even if we (the client) have
   * IPv6 support. In the unlikely case that local server is IPv4-only
   * (meaning that it has to be from different build than client) we
   * have to give port that it can use. IPv6-enabled client would first
   * try same port in IPv6 and if that fails, fallback to IPv4 too. */
  enum fc_addr_family family = FC_ADDR_IPV4;
#else
  enum fc_addr_family family = FC_ADDR_IPV4;
#endif /* IPV6_SUPPORT */

  /* only one server (forked from this client) shall be running at a time */
  /* This also resets client_has_hack. */
  client_kill_server(TRUE);

  output_window_append(ftc_client, _("Starting server..."));

  /* find a free port */
  internal_server_port = find_next_free_port(DEFAULT_SOCK_PORT, family);

# ifdef HAVE_WORKING_FORK
  server_pid = fork();
  
  if (server_pid == 0) {
    int fd, argc = 0;
    const int max_nargs = 18;
    char *argv[max_nargs + 1], port_buf[32];

    /* inside the child */

    /* Set up the command-line parameters. */
    fc_snprintf(port_buf, sizeof(port_buf), "%d", internal_server_port);
    argv[argc++] = "freeciv-server";
    argv[argc++] = "-p";
    argv[argc++] = port_buf;
    argv[argc++] = "--bind";
    argv[argc++] = "localhost";
    argv[argc++] = "-q";
    argv[argc++] = "1";
    argv[argc++] = "-e";
    argv[argc++] = "--saves";
    argv[argc++] = "~/.freeciv/saves";
    argv[argc++] = "--scenarios";
    argv[argc++] = "~/.freeciv/scenarios";
    if (logfile) {
      argv[argc++] = "--debug";
      argv[argc++] = "3";
      argv[argc++] = "--log";
      argv[argc++] = logfile;
    }
    if (scriptfile) {
      argv[argc++] = "--read";
      argv[argc++] = scriptfile;
    }
    argv[argc] = NULL;
    fc_assert(argc <= max_nargs);

    /* avoid terminal spam, but still make server output available */ 
    fclose(stdout);
    fclose(stderr);

    /* FIXME: include the port to avoid duplication? */
    if (logfile) {
      fd = open(logfile, O_WRONLY | O_CREAT | O_APPEND, 0644);

      if (fd != 1) {
        dup2(fd, 1);
      }
      if (fd != 2) {
        dup2(fd, 2);
      }
      fchmod(1, 0644);
    }

    /* If it's still attatched to our terminal, things get messed up, 
      but freeciv-server needs *something* */ 
    fclose(stdin);
    fd = open("/dev/null", O_RDONLY);
    if (fd != 0) {
      dup2(fd, 0);
    }

    /* these won't return on success */
#ifdef DEBUG
    /* Search under current directory (what ever that happens to be)
     * only in debug builds. This allows running freeciv directly from build
     * tree, but could be considered security risk in release builds. */
    execvp("./fcser", argv);
    execvp("./server/freeciv-server", argv);
#endif /* DEBUG */
    execvp(BINDIR "/freeciv-server", argv);
    execvp("freeciv-server", argv);

    /* This line is only reached if freeciv-server cannot be started, 
     * so we kill the forked process.
     * Calling exit here is dangerous due to X11 problems (async replies) */ 
    _exit(1);
  } 
# else /* HAVE_WORKING_FORK */
#  ifdef WIN32_NATIVE
  if (logfile) {
    loghandle = CreateFile(logfile, GENERIC_WRITE,
                           FILE_SHARE_READ | FILE_SHARE_WRITE,
                           NULL,
			   OPEN_ALWAYS, 0, NULL);
  }

  ZeroMemory(&si, sizeof(si));
  si.cb = sizeof(si);
  si.hStdOutput = loghandle;
  si.hStdInput = INVALID_HANDLE_VALUE;
  si.hStdError = loghandle;
  si.dwFlags = STARTF_USESTDHANDLES;

  /* Set up the command-line parameters. */
  logcmdline[0] = 0;
  scriptcmdline[0] = 0;

  /* the server expects command line arguments to be in local encoding */ 
  if (logfile) {
    char *logfile_in_local_encoding =
        internal_to_local_string_malloc(logfile);

    fc_snprintf(logcmdline, sizeof(logcmdline), " --debug 3 --log %s",
                logfile_in_local_encoding);
    free(logfile_in_local_encoding);
  }
  if (scriptfile) {
    char *scriptfile_in_local_encoding =
        internal_to_local_string_malloc(scriptfile);

    fc_snprintf(scriptcmdline, sizeof(scriptcmdline),  " --read %s",
                scriptfile_in_local_encoding);
    free(scriptfile_in_local_encoding);
  }

  interpret_tilde(savesdir, sizeof(savesdir), "~/.freeciv/saves");
  internal_to_local_string_buffer(savesdir, savescmdline, sizeof(savescmdline));

  interpret_tilde(scensdir, sizeof(scensdir), "~/.freeciv/scenarios");
  internal_to_local_string_buffer(scensdir, scenscmdline, sizeof(scenscmdline));

  fc_snprintf(options, sizeof(options),
              "-p %d --bind localhost -q 1 -e%s%s --saves \"%s\" "
              "--scenarios \"%s\"",
              internal_server_port, logcmdline, scriptcmdline, savescmdline,
              scenscmdline);
  fc_snprintf(cmdline1, sizeof(cmdline1), "./fcser %s", options);
  fc_snprintf(cmdline2, sizeof(cmdline2),
              "./server/freeciv-server %s", options);
  fc_snprintf(cmdline3, sizeof(cmdline3),
              BINDIR "/freeciv-server %s", options);
  fc_snprintf(cmdline4, sizeof(cmdline4),
              "freeciv-server %s", options);

  if (
#ifdef DEBUG
      !CreateProcess(NULL, cmdline1, NULL, NULL, TRUE,
                     DETACHED_PROCESS | NORMAL_PRIORITY_CLASS,
                     NULL, NULL, &si, &pi)
      && !CreateProcess(NULL, cmdline2, NULL, NULL, TRUE,
                        DETACHED_PROCESS | NORMAL_PRIORITY_CLASS,
                        NULL, NULL, &si, &pi)
      &&
#endif /* DEBUG */
      !CreateProcess(NULL, cmdline3, NULL, NULL, TRUE,
                     DETACHED_PROCESS | NORMAL_PRIORITY_CLASS,
                     NULL, NULL, &si, &pi)
      && !CreateProcess(NULL, cmdline4, NULL, NULL, TRUE,
                        DETACHED_PROCESS | NORMAL_PRIORITY_CLASS,
                        NULL, NULL, &si, &pi)) {
    output_window_append(ftc_client, _("Couldn't start the server."));
    output_window_append(ftc_client,
                         _("You'll have to start one manually. Sorry..."));
    return FALSE;
  }

  server_process = pi.hProcess;

#  endif /* WIN32_NATIVE */
# endif /* HAVE_WORKING_FORK */
 
  /* a reasonable number of tries */ 
  while (connect_to_server(user_name, "localhost", internal_server_port, 
                           buf, sizeof(buf)) == -1) {
    fc_usleep(WAIT_BETWEEN_TRIES);
#ifdef HAVE_WORKING_FORK
#ifndef WIN32_NATIVE
    if (waitpid(server_pid, NULL, WNOHANG) != 0) {
      break;
    }
#endif /* WIN32_NATIVE */
#endif /* HAVE_WORKING_FORK */
    if (connect_tries++ > NUMBER_OF_TRIES) {
      break;
    }
  }

  /* weird, but could happen, if server doesn't support new startup stuff
   * capabilities won't help us here... */ 
  if (!client.conn.used) {
    /* possible that server is still running. kill it */ 
    client_kill_server(TRUE);

    output_window_append(ftc_client, _("Couldn't connect to the server."));
    output_window_append(ftc_client,
                         _("We probably couldn't start it from here."));
    output_window_append(ftc_client,
                         _("You'll have to start one manually. Sorry..."));
    return FALSE;
  }

  /* We set the topology to match the view.
   *
   * When a typical player launches a game, he wants the map orientation to
   * match the tileset orientation.  So if you use an isometric tileset you
   * get an iso-map and for a classic tileset you get a classic map.  In
   * both cases the map wraps in the X direction by default.
   *
   * This works with hex maps too now.  A hex map always has
   * tileset_is_isometric(tileset) return TRUE.  An iso-hex map has
   * tileset_hex_height(tileset) != 0, while a non-iso hex map
   * has tileset_hex_width(tileset) != 0.
   *
   * Setting the option here is a bit of a hack, but so long as the client
   * has sufficient permissions to do so (it doesn't have HACK access yet) it
   * is safe enough.  Note that if you load a savegame the topology will be
   * set but then overwritten during the load.
   *
   * Don't send it now, it will be sent to the server when receiving the
   * server setting infos. */
  {
    char buf[16];

    fc_strlcpy(buf, "WRAPX", sizeof(buf));
    if (tileset_is_isometric(tileset) && 0 == tileset_hex_height(tileset)) {
      fc_strlcat(buf, "|ISO", sizeof(buf));
    }
    if (0 < tileset_hex_width(tileset) || 0 < tileset_hex_height(tileset)) {
      fc_strlcat(buf, "|HEX", sizeof(buf));
    }
    desired_settable_option_update("topology", buf, FALSE);
  }

  return TRUE;
#endif /* HAVE_WORKING_FORK || WIN32_NATIVE */
}
Exemple #23
0
/**************************************************************************
  Read and return a packet from the connection 'pc'. The type of the
  packet is written in 'ptype'. On error, the connection is closed and
  the function returns NULL.
**************************************************************************/
void *get_packet_from_connection(struct connection *pc,
                                 enum packet_type *ptype)
{
  int len_read;
  int whole_packet_len;
  struct {
    enum packet_type type;
    int itype;
  } utype;
  struct data_in din;
#ifdef USE_COMPRESSION
  bool compressed_packet = FALSE;
  int header_size = 0;
#endif
  void *data;

  if (!pc->used) {
    return NULL;		/* connection was closed, stop reading */
  }
  
  if (pc->buffer->ndata < data_type_size(pc->packet_header.length)) {
    /* Not got enough for a length field yet */
    return NULL;
  }

  dio_input_init(&din, pc->buffer->data, pc->buffer->ndata);
  dio_get_type(&din, pc->packet_header.length, &len_read);

  /* The non-compressed case */
  whole_packet_len = len_read;

#ifdef USE_COMPRESSION
  /* Compression signalling currently assumes a 2-byte packet length; if that
   * changes, the protocol should probably be changed */
  fc_assert(data_type_size(pc->packet_header.length) == 2);
  if (len_read == JUMBO_SIZE) {
    compressed_packet = TRUE;
    header_size = 6;
    if (dio_input_remaining(&din) >= 4) {
      dio_get_uint32(&din, &whole_packet_len);
      log_compress("COMPRESS: got a jumbo packet of size %d",
                   whole_packet_len);
    } else {
      /* to return NULL below */
      whole_packet_len = 6;
    }
  } else if (len_read >= COMPRESSION_BORDER) {
    compressed_packet = TRUE;
    header_size = 2;
    whole_packet_len = len_read - COMPRESSION_BORDER;
    log_compress("COMPRESS: got a normal packet of size %d",
                 whole_packet_len);
  }
#endif /* USE_COMPRESSION */

  if ((unsigned)whole_packet_len > pc->buffer->ndata) {
    return NULL;		/* not all data has been read */
  }

#ifdef USE_COMPRESSION
  if (whole_packet_len < header_size) {
    log_verbose("The packet size is reported to be less than header alone. "
                "The connection will be closed now.");
    connection_close(pc, _("illegal packet size"));

    return NULL;
  }

  if (compressed_packet) {
    uLong compressed_size = whole_packet_len - header_size;
    /* 
     * We don't know the decompressed size. We assume a bad case
     * here: an expansion by an factor of 100. 
     */
    unsigned long int decompressed_size = 100 * compressed_size;
    void *decompressed = fc_malloc(decompressed_size);
    int error;
    struct socket_packet_buffer *buffer = pc->buffer;
    
    error =
	uncompress(decompressed, &decompressed_size,
		   ADD_TO_POINTER(buffer->data, header_size), 
		   compressed_size);
    if (error != Z_OK) {
      log_verbose("Uncompressing of the packet stream failed. "
                  "The connection will be closed now.");
      connection_close(pc, _("decoding error"));
      return NULL;
    }

    buffer->ndata -= whole_packet_len;
    /* 
     * Remove the packet with the compressed data and shift all the
     * remaining data to the front. 
     */
    memmove(buffer->data, buffer->data + whole_packet_len, buffer->ndata);

    if (buffer->ndata + decompressed_size > buffer->nsize) {
      buffer->nsize += decompressed_size;
      buffer->data = fc_realloc(buffer->data, buffer->nsize);
    }

    /*
     * Make place for the uncompressed data by moving the remaining
     * data.
     */
    memmove(buffer->data + decompressed_size, buffer->data, buffer->ndata);

    /* 
     * Copy the uncompressed data.
     */
    memcpy(buffer->data, decompressed, decompressed_size);

    free(decompressed);

    buffer->ndata += decompressed_size;
    
    log_compress("COMPRESS: decompressed %ld into %ld",
                 compressed_size, decompressed_size);

    return get_packet_from_connection(pc, ptype);
  }
#endif /* USE_COMPRESSION */

  /*
   * At this point the packet is a plain uncompressed one. These have
   * to have to be at least the header bytes in size.
   */
  if (whole_packet_len < (data_type_size(pc->packet_header.length)
                          + data_type_size(pc->packet_header.type))) {
    log_verbose("The packet stream is corrupt. The connection "
                "will be closed now.");
    connection_close(pc, _("decoding error"));
    return NULL;
  }

  dio_get_type(&din, pc->packet_header.type, &utype.itype);
  utype.type = utype.itype;

  log_packet("got packet type=(%s)%d len=%d from %s",
             packet_name(utype.type), utype.itype, whole_packet_len,
             is_server() ? pc->username : "******");

  *ptype = utype.type;

  if (pc->incoming_packet_notify) {
    pc->incoming_packet_notify(pc, utype.type, whole_packet_len);
  }

#if PACKET_SIZE_STATISTICS 
  {
    static struct {
      int counter;
      int size;
    } packets_stats[PACKET_LAST];
    static int packet_counter = 0;

    int packet_type = utype.itype;
    int size = whole_packet_len;

    if (!packet_counter) {
      int i;

      for (i = 0; i < PACKET_LAST; i++) {
	packets_stats[i].counter = 0;
	packets_stats[i].size = 0;
      }
    }

    packets_stats[packet_type].counter++;
    packets_stats[packet_type].size += size;

    packet_counter++;
    if (packet_counter % 100 == 0) {
      int i, sum = 0;

      log_test("Received packets:");
      for (i = 0; i < PACKET_LAST; i++) {
	if (packets_stats[i].counter == 0)
	  continue;
	sum += packets_stats[i].size;
        log_test("  [%-25.25s %3d]: %6d packets; %8d bytes total; "
                 "%5d bytes/packet average",
                 packet_name(i), i, packets_stats[i].counter,
                 packets_stats[i].size,
                 packets_stats[i].size / packets_stats[i].counter);
      }
      log_test("received %d bytes in %d packets;average size "
               "per packet %d bytes",
               sum, packet_counter, sum / packet_counter);
    }
  }
#endif /* PACKET_SIZE_STATISTICS */
  data = get_packet_from_connection_helper(pc, utype.type);
  if (!data) {
    connection_close(pc, _("incompatible packet contents"));
    return NULL;
  } else {
    return data;
  }
}
Exemple #24
0
/****************************************************************
  Refresh worklist info
*****************************************************************/
void refresh_worklist(GtkWidget *editor)
{
  struct worklist_data *ptr;
  const struct global_worklist *pgwl = NULL;
  struct worklist queue;
  struct universal targets[MAX_NUM_PRODUCTION_TARGETS];
  int i, targets_used;
  struct item items[MAX_NUM_PRODUCTION_TARGETS];
  bool selected;
  gint id;
  GtkTreeIter it;
  GtkTreePath *path;
  GtkTreeModel *model;
  gboolean exists;

  ptr = g_object_get_data(G_OBJECT(editor), "data");

  if (!ptr->pcity
      && !(pgwl = global_worklist_by_id(ptr->global_worklist_id))) {
  }

  /* refresh source tasks. */
  if (gtk_tree_selection_get_selected(ptr->src_selection, NULL, &it)) {
    gtk_tree_model_get(GTK_TREE_MODEL(ptr->src), &it, 0, &id, -1);
    selected = TRUE;
  } else {
    selected = FALSE;
  }
  gtk_list_store_clear(ptr->src);

  targets_used = collect_eventually_buildable_targets(targets, ptr->pcity,
                                                      ptr->future);
  name_and_sort_items(targets, targets_used, items, FALSE, ptr->pcity);

  path = NULL;
  for (i = 0; i < targets_used; i++) {
    gtk_list_store_append(ptr->src, &it);
    gtk_list_store_set(ptr->src, &it, 0, (gint) cid_encode(items[i].item), -1);

    if (selected && cid_encode(items[i].item) == id) {
      path = gtk_tree_model_get_path(GTK_TREE_MODEL(ptr->src), &it);
    }
  }
  if (path) {
    gtk_tree_view_set_cursor(GTK_TREE_VIEW(ptr->src_view), path, NULL, FALSE);
    gtk_tree_path_free(path);
  }


  /* refresh target worklist. */
  model = GTK_TREE_MODEL(ptr->dst);
  exists = gtk_tree_model_get_iter_first(model, &it);

  /* dance around worklist braindamage. */
  if (ptr->pcity) {
    city_get_queue(ptr->pcity, &queue);
  } else {
    fc_assert(NULL != pgwl);
    worklist_copy(&queue, global_worklist_get(pgwl));
  }

  for (i = 0; i < worklist_length(&queue); i++) {
    struct universal target = queue.entries[i];

    if (!exists) {
      gtk_list_store_append(ptr->dst, &it);
    }

    gtk_list_store_set(ptr->dst, &it, 0, (gint) cid_encode(target), -1);

    if (exists) {
      exists = gtk_tree_model_iter_next(model, &it);
    }
  }

  if (exists) {
    GtkTreeIter it_next;
    bool more;

    do {
      it_next = it;
      more = gtk_tree_model_iter_next(model, &it_next);

      gtk_list_store_remove(ptr->dst, &it);
      it = it_next;
    } while (more);
  }

  /* update widget sensitivity. */
  if (ptr->pcity) {
    if ((can_client_issue_orders() &&
	 city_owner(ptr->pcity) == client.conn.playing)) {
      gtk_widget_set_sensitive(ptr->add_cmd, TRUE);
      gtk_widget_set_sensitive(ptr->dst_view, TRUE);
    } else {
      gtk_widget_set_sensitive(ptr->add_cmd, FALSE);
      gtk_widget_set_sensitive(ptr->dst_view, FALSE);
    }
  } else {
    gtk_widget_set_sensitive(ptr->add_cmd, TRUE);
    gtk_widget_set_sensitive(ptr->dst_view, TRUE);
  }
}
Exemple #25
0
/****************************************************************************
  Initializes the attribute module.
****************************************************************************/
void attribute_init(void)
{
    fc_assert(NULL == attribute_hash);
    attribute_hash = attribute_hash_new();
}
Exemple #26
0
/**********************************************************************
  Finds and reads the toplevel themespec file based on given name.
  Sets global variables, including tile sizes and full names for
  intro files.
***********************************************************************/
struct theme *theme_read_toplevel(const char *theme_name)
{
  struct section_file *file;
  char *fname;
  int i;
  size_t num_spec_files;
  const char **spec_filenames;
  const char *file_capstr;
  bool duplicates_ok;
  struct theme *t = theme_new();
  const char *langname;
  const char *filename, *c;

  fname = themespec_fullname(theme_name);
  if (!fname) {
    log_error("Can't find theme \"%s\".", theme_name); 
    theme_free(t);
    return NULL;
  }
  log_verbose("themespec file is \"%s\".", fname);

  if (!(file = secfile_load(fname, TRUE))) {
    log_error("Could not open '%s':\n%s", fname, secfile_error());
    FC_FREE(fname);
    theme_free(t);
    return NULL;
  }

  if (!check_themespec_capabilities(file, "themespec",
                                    THEMESPEC_CAPSTR, fname)) {
    secfile_destroy(file);
    FC_FREE(fname);
    theme_free(t);
    return NULL;
  }
  
  file_capstr = secfile_lookup_str(file, "themespec.options");
  duplicates_ok = has_capabilities("+duplicates_ok", file_capstr);

  (void) secfile_entry_by_path(file, "themespec.name"); /* currently unused */

  sz_strlcpy(t->name, theme_name);
  t->priority = secfile_lookup_int_default(file, 0, "themespec.priority");
  
  langname = get_langname();
  if (langname) {
    if (strstr(langname, "zh_CN") != NULL) {
      c = secfile_lookup_str(file, "themespec.font_file_zh_CN");
    } else if (strstr(langname, "ja") != NULL) {
      c = secfile_lookup_str(file, "themespec.font_file_ja");
    } else if (strstr(langname, "ko") != NULL) {
      c = secfile_lookup_str(file, "themespec.font_file_ko");
    } else {
      c = secfile_lookup_str(file, "themespec.font_file");
    }
  } else {
    c = secfile_lookup_str(file, "themespec.font_file");
  }
  if ((filename = fileinfoname(get_data_dirs(), c))) {
    t->font_filename = fc_strdup(filename);
  } else {
    log_fatal("Could not open font: %s", c);
    secfile_destroy(file);
    FC_FREE(fname);
    theme_free(t);
    return NULL;
  }
  log_debug("theme font file %s", t->font_filename);

  t->default_font_size = secfile_lookup_int_default(file, 10, "themespec.default_font_size");
  log_debug("theme default font size %d", t->default_font_size);

  spec_filenames = secfile_lookup_str_vec(file, &num_spec_files,
                                          "themespec.files");
  if (NULL == spec_filenames || 0 == num_spec_files) {
    log_error("No theme graphics files specified in \"%s\"", fname);
    secfile_destroy(file);
    FC_FREE(fname);
    theme_free(t);
    return NULL;
  }

  fc_assert(t->sprite_hash == NULL);
  t->sprite_hash = small_sprite_hash_new();
  for (i = 0; i < num_spec_files; i++) {
    struct specfile *sf = fc_malloc(sizeof(*sf));

    log_debug("spec file %s", spec_filenames[i]);

    sf->big_sprite = NULL;
    filename = fileinfoname(get_data_dirs(), spec_filenames[i]);
    if (!filename) {
      log_error("Can't find spec file \"%s\".", spec_filenames[i]);
      secfile_destroy(file);
      FC_FREE(fname);
      theme_free(t);
      return NULL;
    }
    sf->file_name = fc_strdup(filename);
    scan_specfile(t, sf, duplicates_ok);

    specfile_list_prepend(t->specfiles, sf);
  }
  FC_FREE(spec_filenames);

  t->background_system = theme_background_system_read(file);
  t->color_system = theme_color_system_read(file);  
  
  secfile_check_unused(file);
  
  secfile_destroy(file);
  log_verbose("finished reading \"%s\".", fname);
  FC_FREE(fname);

  return t;
}