Ejemplo n.º 1
0
/**************************************************************** 
handle response (by the server) if the client has got hack or not.
*****************************************************************/ 
void handle_single_want_hack_reply(bool you_have_hack)
{
  /* remove challenge file */
  if (challenge_fullname[0] != '\0') {
    if (remove(challenge_fullname) == -1) {
      freelog(LOG_ERROR, "Couldn't remove temporary file: %s",
	      challenge_fullname);
    }
    challenge_fullname[0] = '\0';
  }

  if (you_have_hack) {
    output_window_append(FTC_CLIENT_INFO, NULL,
                         _("Established control over the server. "
                           "You have command access level 'hack'."));
    client_has_hack = TRUE;
  } else if (is_server_running()) {
    /* only output this if we started the server and we NEED hack */
    output_window_append(FTC_CLIENT_INFO, NULL,
                         _("Failed to obtain the required access "
                           "level to take control of the server. "
                           "The server will now be shutdown."));
    client_kill_server(TRUE);
  }
}
Ejemplo n.º 2
0
/****************************************************************************
  Callback for Connect button.
****************************************************************************/
void connectdlg_connect_callback(Widget w, XtPointer client_data,
                              XtPointer call_data)
{
  XtPointer pxp;
  char errbuf[512];
  struct packet_authentication_reply reply;

  switch (connection_status) {
  case LOGIN_TYPE:
    XtVaGetValues(connectdlg_host_text, XtNstring, &pxp, NULL);
    sz_strlcpy(server_host, (char *)pxp);
    XtVaGetValues(connectdlg_port_text, XtNstring, &pxp, NULL);
    sscanf((char *)pxp, "%d", &server_port);
    XtVaGetValues(connectdlg_login_text, XtNstring, &pxp, NULL);
    sz_strlcpy(user_name, (char *)pxp);
    if (connect_to_server(user_name, server_host, server_port,
                          errbuf, sizeof(errbuf)) != -1) {
      popup_start_page();
      connectdlg_destroy();
      XtSetSensitive(toplevel, True);
      return;
    } else {
      XtVaSetValues(connectdlg_message_label, XtNlabel, errbuf, NULL);
      output_window_append(ftc_client, errbuf);
    }
    break;
  case NEW_PASSWORD_TYPE:
    XtVaGetValues(connectdlg_password_text, XtNstring, &pxp, NULL);
    sz_strlcpy(password, (char *)pxp);
    XtVaGetValues(connectdlg_verify_text, XtNstring, &pxp, NULL);
    sz_strlcpy(reply.password, (char *)pxp);
    if (strncmp(reply.password, password, MAX_LEN_NAME) == 0) {
      password[0] = '\0';
      send_packet_authentication_reply(&client.conn, &reply);
      XtVaSetValues(connectdlg_message_label, XtNlabel, "", NULL);
      XtVaSetValues(connectdlg_password_text, XtNsensitive, False, NULL);
      XtVaSetValues(connectdlg_verify_text, XtNsensitive, False, NULL);
    } else {
      XtVaSetValues(connectdlg_password_text, XtNstring, "", NULL);
      XtVaSetValues(connectdlg_verify_text, XtNstring, "", NULL);
      XtVaSetValues(connectdlg_message_label, XtNlabel,
                    _("Passwords don't match, enter password."), NULL);
      output_window_append(ftc_client,
                           _("Passwords don't match, enter password."));
    }
    break;
  case ENTER_PASSWORD_TYPE:
    XtVaGetValues(connectdlg_verify_text, XtNstring, &pxp, NULL);
    sz_strlcpy(reply.password, (char *)pxp);
    send_packet_authentication_reply(&client.conn, &reply);

    XtVaSetValues(connectdlg_message_label, XtNlabel, "", NULL);
    XtVaSetValues(connectdlg_password_text, XtNsensitive, False, NULL);
    XtVaSetValues(connectdlg_verify_text, XtNsensitive, False, NULL);
    break;
  case WAITING_TYPE:
    break;
  }
}
Ejemplo n.º 3
0
/****************************************************************************
  Standard welcome message.
****************************************************************************/
void chat_welcome_message(void)
{
  output_window_append(ftc_any, _("Freeciv is free software and you are "
                                  "welcome to distribute copies of it "
                                  "under certain conditions;"));
  output_window_append(ftc_any, _("See the \"Copying\" item on the "
                                  "Help menu."));
  output_window_append(ftc_any, _("Now ... Go give 'em hell!"));
}
Ejemplo n.º 4
0
/**************************************************************************
  Popup a dialog to display connection message from server.
**************************************************************************/
void popup_connect_msg(const char *headline, const char *message)
{
  /* FIXME: Needs proper implementation.
   *        Now just puts to chat window so message is not completely lost. */

  output_window_append(ftc_client, message);
}
Ejemplo n.º 5
0
/**************************************************************************
  Add a line of text to the output ("chatline") window.  The text is
  constructed in printf style.
**************************************************************************/
void output_window_vprintf(const struct ft_color color,
                           const char *format, va_list args)
{
  char featured_text[MAX_LEN_MSG];

  fc_vsnprintf(featured_text, sizeof(featured_text), format, args);
  output_window_append(color, featured_text);
}
Ejemplo n.º 6
0
/**************************************************************************
  Writes the supplied string into the file defined by the variable
  'default_chat_logfile'.
**************************************************************************/
void write_chatline_content(const char *txt)
{
  FILE *fp = fc_fopen(default_chat_logfile, "w");
  char buf[512];

  fc_snprintf(buf, sizeof(buf), _("Exporting output window to '%s' ..."),
              default_chat_logfile);
  output_window_append(ftc_client, buf);

  if (fp) {
    fputs(txt, fp);
    fclose(fp);
    output_window_append(ftc_client, _("Export complete."));
  } else {
    output_window_append(ftc_client,
                         _("Export failed, couldn't write to file."));
  }
}
Ejemplo n.º 7
0
/**************************************************************************
...
**************************************************************************/
static void close_socket_callback(struct connection *pc)
{
  close_socket_nomessage(pc);
  /* If we lost connection to the internal server - kill him */
  client_kill_server(TRUE);
  freelog(LOG_ERROR, "Lost connection to server!");
  output_window_append(FTC_CLIENT_INFO, NULL,
                       _("Lost connection to server!"));
  if (with_ggz) {
    client_exit();
  }
}
Ejemplo n.º 8
0
/**************************************************************************
  Make an attempt to autoconnect to the server.
  It returns number of seconds it should be called again.
**************************************************************************/
double try_to_autoconnect(void)
{
  char errbuf[512];
  static int count = 0;
#ifndef WIN32_NATIVE
  static int warning_shown = 0;
#endif

  if (!autoconnecting) {
    return FC_INFINITY;
  }
  
  count++;

  if (count >= MAX_AUTOCONNECT_ATTEMPTS) {
    freelog(LOG_FATAL,
	    _("Failed to contact server \"%s\" at port "
	      "%d as \"%s\" after %d attempts"),
	    server_host, server_port, user_name, count);
    exit(EXIT_FAILURE);
  }

  switch (try_to_connect(user_name, errbuf, sizeof(errbuf))) {
  case 0:			/* Success! */
    /* Don't call me again */
    autoconnecting = FALSE;
    return FC_INFINITY;
#ifndef WIN32_NATIVE
  /* See PR#4042 for more info on issues with try_to_connect() and errno. */
  case ECONNREFUSED:		/* Server not available (yet) */
    if (!warning_shown) {
      freelog(LOG_ERROR, "Connection to server refused. "
                         "Please start the server.");
      output_window_append(FTC_CLIENT_INFO, NULL,
                           _("Connection to server refused. "
                             "Please start the server."));
      warning_shown = 1;
    }
    /* Try again in 0.5 seconds */
    return 0.001 * AUTOCONNECT_INTERVAL;
#endif
  default:			/* All other errors are fatal */
    freelog(LOG_FATAL,
	    _("Error contacting server \"%s\" at port %d "
	      "as \"%s\":\n %s\n"),
	    server_host, server_port, user_name, errbuf);
    exit(EXIT_FAILURE);
  }
}
Ejemplo n.º 9
0
/**************************************************************** 
handle response (by the server) if the client has got hack or not.
*****************************************************************/ 
void handle_single_want_hack_reply(bool you_have_hack)
{
  /* remove challenge file */
  if (challenge_fullname[0] != '\0') {
    if (fc_remove(challenge_fullname) == -1) {
      log_error("Couldn't remove temporary file: %s", challenge_fullname);
    }
    challenge_fullname[0] = '\0';
  }

  if (you_have_hack) {
    output_window_append(ftc_client,
                         _("Established control over the server. "
                           "You have command access level 'hack'."));
    client_has_hack = TRUE;
  } else if (is_server_running()) {
    /* only output this if we started the server and we NEED hack */
    output_window_append(ftc_client,
                         _("Failed to obtain the required access "
                           "level to take control of the server. "
                           "Attempting to shut down server."));
    client_kill_server(TRUE);
  }
}
Ejemplo n.º 10
0
/****************************************************************************
  Callback function for when there's an error in the server scan.
****************************************************************************/
void server_scan_error(struct server_scan *scan, const char *message)
{
  output_window_append(ftc_client, message);
  log_normal("%s", message);
  switch (server_scan_get_type(scan)) {
  case SERVER_SCAN_LOCAL:
    server_scan_finish(lan_scan);
    lan_scan = NULL;
    break;
  case SERVER_SCAN_GLOBAL:
    server_scan_finish(meta_scan);
    meta_scan = NULL;
    break;
  case SERVER_SCAN_LAST:
    break;
  }
}
Ejemplo n.º 11
0
/**************************************************************************
...
**************************************************************************/
void players_meet_callback(Widget w, XtPointer client_data, 
			      XtPointer call_data)
{
  XawListReturnStruct *ret = XawListShowCurrent(players_list);

  if (ret->list_index != XAW_LIST_NONE) {
    int player_index = list_index_to_player_index[ret->list_index];
    struct player *pplayer = player_by_number(player_index);

    if (can_meet_with_player(pplayer)) {
      dsend_packet_diplomacy_init_meeting_req(&client.conn, player_index);
    } else {
      output_window_append(ftc_client,
                           _("You need an embassy to establish"
                             " a diplomatic meeting."));
    }
  }
}
Ejemplo n.º 12
0
/**************************************************************************
...
**************************************************************************/
void disconnect_from_server(void)
{
  const bool force = !client.conn.used;

  attribute_flush();
  /* If it's internal server - kill him 
   * We assume that we are always connected to the internal server  */
  if (!force) {
    client_kill_server(FALSE);
  }
  close_socket_nomessage(&client.conn);
  if (force) {
    client_kill_server(TRUE);
  }
  output_window_append(ftc_client, _("Disconnected from server."));
  if (with_ggz) {
    client_exit();
  }
  if (save_options_on_exit) {
    options_save();
  }
}  
Ejemplo n.º 13
0
/**************************************************************************
...
**************************************************************************/
void
clear_output_window(void)
{
  SetWindowText(logoutput_win,"");
  output_window_append(ftc_client, _("Cleared output window."));
}
Ejemplo n.º 14
0
/**************************************************************************
  Make a chat link at the current position or make the current selection
  clickable.
**************************************************************************/
void inputline_make_chat_link(struct tile *ptile, bool unit)
{
  char buf[MAX_LEN_MSG];
  GtkWidget *entry = toolkit.entry;
  GtkEditable *editable = GTK_EDITABLE(entry);
  gint start_pos, end_pos;
  gchar *chars;
  struct unit *punit;

  /* Get the target. */
  if (unit) {
    punit = find_visible_unit(ptile);
    if (!punit) {
      output_window_append(ftc_client, _("No visible unit on this tile."));
      return;
    }
  } else {
    punit = NULL;
  }

  if (gtk_editable_get_selection_bounds(editable, &start_pos, &end_pos)) {
    /* There is a selection, make it clickable. */
    gpointer target;
    enum text_link_type type;

    chars = gtk_editable_get_chars(editable, start_pos, end_pos);
    if (punit) {
      type = TLT_UNIT;
      target = punit;
    } else if (tile_city(ptile)) {
      type = TLT_CITY;
      target = tile_city(ptile);
    } else {
      type = TLT_TILE;
      target = ptile;
    }

    if (0 != featured_text_apply_tag(chars, buf, sizeof(buf), TTT_LINK,
                                     0, FT_OFFSET_UNSET, type, target)) {
      /* Replace the selection. */
      gtk_editable_delete_text(editable, start_pos, end_pos);
      end_pos = start_pos;
      gtk_editable_insert_text(editable, buf, -1, &end_pos);
      gtk_widget_grab_focus(entry);
      gtk_editable_select_region(editable, start_pos, end_pos);
    }
  } else {
    /* Just insert the link at the current position. */
    start_pos = gtk_editable_get_position(editable);
    end_pos = start_pos;
    chars = gtk_editable_get_chars(editable, MAX(start_pos - 1, 0),
                                   start_pos + 1);
    if (punit) {
      sz_strlcpy(buf, unit_link(punit));
    } else if (tile_city(ptile)) {
      sz_strlcpy(buf, city_link(tile_city(ptile)));
    } else {
      sz_strlcpy(buf, tile_link(ptile));
    }

    if (start_pos > 0 && strlen(chars) > 0 && chars[0] != ' ') {
      /* Maybe insert an extra space. */
      gtk_editable_insert_text(editable, " ", 1, &end_pos);
    }
    gtk_editable_insert_text(editable, buf, -1, &end_pos);
    if (chars[start_pos > 0 ? 1 : 0] != '\0'
        && chars[start_pos > 0 ? 1 : 0] != ' ') {
      /* Maybe insert an extra space. */
      gtk_editable_insert_text(editable, " ", 1, &end_pos);
    }
    gtk_widget_grab_focus(entry);
    gtk_editable_set_position(editable, end_pos);
  }

  g_free(chars);
}
Ejemplo n.º 15
0
/**************************************************************************
...
**************************************************************************/
void
clear_output_window(void)
{
  SetWindowText(logoutput_win,"");
  output_window_append(FTC_CLIENT_INFO, NULL, _("Cleared output window."));
}
Ejemplo n.º 16
0
/**************************************************************************
  Click a link.
**************************************************************************/
static gboolean event_after(GtkWidget *text_view, GdkEventButton *event)
{
  GtkTextIter start, end, iter;
  GtkTextBuffer *buffer;
  GSList *tags, *tagp;
  gint x, y;
  struct tile *ptile = NULL;

  if (event->type != GDK_BUTTON_RELEASE || event->button != 1) {
    return FALSE;
  }

  buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view));

  /* We shouldn't follow a link if the user has selected something. */
  gtk_text_buffer_get_selection_bounds(buffer, &start, &end);
  if (gtk_text_iter_get_offset(&start) != gtk_text_iter_get_offset(&end)) {
    return FALSE;
  }

  gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW (text_view), 
                                        GTK_TEXT_WINDOW_WIDGET,
                                        event->x, event->y, &x, &y);

  gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(text_view), &iter, x, y);

  if ((tags = gtk_text_iter_get_tags(&iter))) {
    for (tagp = tags; tagp; tagp = tagp->next) {
      GtkTextTag *tag = tagp->data;
      enum text_link_type type =
        GPOINTER_TO_INT(g_object_get_data(G_OBJECT(tag), "type"));

      if (type != 0) {
        /* This is a link. */
        int id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(tag), "id"));
        ptile = NULL;

        /* Real type is type - 1.
         * See comment in apply_text_tag() for g_object_set_data(). */
        type--;

        switch (type) {
        case TLT_CITY:
          {
            struct city *pcity = game_city_by_number(id);

            if (pcity) {
              ptile = client_city_tile(pcity);
            } else {
              output_window_append(ftc_client, _("This city isn't known!"));
            }
          }
          break;
        case TLT_TILE:
          ptile = index_to_tile(id);

          if (!ptile) {
            output_window_append(ftc_client,
                                 _("This tile doesn't exist in this game!"));
          }
          break;
        case TLT_UNIT:
          {
            struct unit *punit = game_unit_by_number(id);

            if (punit) {
              ptile = unit_tile(punit);
            } else {
              output_window_append(ftc_client, _("This unit isn't known!"));
            }
          }
          break;
        }

        if (ptile) {
          center_tile_mapcanvas(ptile);
          link_mark_restore(type, id);
          gtk_widget_grab_focus(GTK_WIDGET(map_canvas));
        }
      }
    }
    g_slist_free(tags);
  }

  return FALSE;
}
Ejemplo n.º 17
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 */
}
Ejemplo n.º 18
0
/**************************************************************** 
forks a server if it can. returns FALSE is we find we couldn't start
the server.
This is so system-intensive that it's *nix only.  VMS and Windows 
code will come later 
*****************************************************************/ 
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 options[512];
  char cmdline1[512];
  char cmdline2[512];
  char cmdline3[512];
  char logcmdline[512];
  char scriptcmdline[512];
# endif /* WIN32_NATIVE */

  /* 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_INFO, NULL, _("Starting server..."));

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

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

    /* inside the child */

    /* Set up the command-line parameters. */
    my_snprintf(port_buf, sizeof(port_buf), "%d", internal_server_port);
    argv[argc++] = "civserver";
    argv[argc++] = "-p";
    argv[argc++] = port_buf;
    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;
    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 civserver needs *something* */ 
    fclose(stdin);
    fd = open("/dev/null", O_RDONLY);
    if (fd != 0) {
      dup2(fd, 0);
    }

    /* these won't return on success */ 
    execvp("./ser", argv);
    execvp("./server/civserver", argv);
    execvp("civserver", argv);
    
    /* This line is only reached if civserver 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;

  if (logfile) {
    my_snprintf(logcmdline, sizeof(logcmdline), " --debug 3 --log %s",
		logfile);
  }
  if (scriptfile) {
    my_snprintf(scriptcmdline, sizeof(scriptcmdline),  " --read %s",
		scriptfile);
  }

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

  my_snprintf(options, sizeof(options), "-p %d -q 1 -e%s%s --saves \"%s\"",
	      internal_server_port, logcmdline, scriptcmdline, savesdir);
  my_snprintf(cmdline1, sizeof(cmdline1), "./ser %s", options);
  my_snprintf(cmdline2, sizeof(cmdline2), "./server/civserver %s", options);
  my_snprintf(cmdline3, sizeof(cmdline3), "civserver %s", options);

  if (!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) 
      && !CreateProcess(NULL, cmdline3, NULL, NULL, TRUE,
			DETACHED_PROCESS | NORMAL_PRIORITY_CLASS,
			NULL, NULL, &si, &pi)) {
    output_window_append(FTC_CLIENT_INFO, NULL,
                         _("Couldn't start the server."));
    output_window_append(FTC_CLIENT_INFO, NULL,
                         _("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) {
    myusleep(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_INFO, NULL,
                         _("Couldn't connect to the server."));
    output_window_append(FTC_CLIENT_INFO, NULL,
                         _("We probably couldn't start it from here."));
    output_window_append(FTC_CLIENT_INFO, NULL,
                         _("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. */
  send_chat_printf("/set topology %d",
                   (TF_WRAPX
                    | ((tileset_is_isometric(tileset)
                        && tileset_hex_height(tileset) == 0) ? TF_ISO : 0)
                    | ((tileset_hex_width(tileset) != 0
                        || tileset_hex_height(tileset) != 0) ? TF_HEX : 0)));

  return TRUE;
#endif /* HAVE_WORKING_FORK || WIN32_NATIVE */
}