[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[gnugo-devel] TCP/IP connection built into GNU Go?
From: |
Paul Pogonyshev |
Subject: |
[gnugo-devel] TCP/IP connection built into GNU Go? |
Date: |
Fri, 8 Oct 2004 23:14:04 -0200 |
User-agent: |
KMail/1.4.3 |
I tried to build TCP/IP connection via sockets into GNU Go.
The patch below is not ready yet. I'd like for someone to
look into it and maybe spot a problem I cannot track down.
The easiest way to test it is to run GNU Go like
$ ./interface/gnugo --mode gtp --gtp-listen 127.0.0.1:5000
and then
$ telnet 127.0.0.1 5000
to receieve a "remote" GNU Go terminal. The problem is that
when you type `quit' and then try to make GNU Go listen on
the same port again, it won't work. The system says the port
is still in use. It gets released in about a minute (on my
machine.) Clearly, something is not being closed, but I
don't understand what it is. I doubt it could be a problem
in `telnet'.
Also, `--gtp-connect' is not tested since I couldn't come up
with an easy way to test. The patch is completely non-
portable too.
Paul
Index: interface/gtp.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/interface/gtp.c,v
retrieving revision 1.19
diff -u -p -r1.19 gtp.c
--- interface/gtp.c 25 May 2004 03:13:47 -0000 1.19
+++ interface/gtp.c 8 Oct 2004 20:01:24 -0000
@@ -69,10 +69,17 @@ static gtp_transform_ptr vertex_transfor
*/
static int current_id;
+/* The file all GTP output goes to. This is made global for the user
+ * of this file may want to use functions other than gtp_printf() etc.
+ * Set by gtp_main_loop().
+ */
+FILE *gtp_output_file = NULL;
+
+
/* Read filehandle gtp_input linewise and interpret as GTP commands. */
void
-gtp_main_loop(struct gtp_command commands[], FILE *gtp_input,
- FILE *gtp_dump_commands)
+gtp_main_loop(struct gtp_command commands[],
+ FILE *gtp_input, FILE *gtp_output, FILE *gtp_dump_commands)
{
char line[GTP_BUFSIZE];
char command[GTP_BUFSIZE];
@@ -80,7 +87,9 @@ gtp_main_loop(struct gtp_command command
int i;
int n;
int status = GTP_OK;
-
+
+ gtp_output_file = gtp_output;
+
while (status == GTP_OK) {
/* Read a line from gtp_input. */
if (!fgets(line, GTP_BUFSIZE, gtp_input))
@@ -180,25 +189,25 @@ gtp_mprintf(const char *fmt, ...)
{
/* rules of promotion => passed as int, not char */
int c = va_arg(ap, int);
- putc(c, stdout);
+ putc(c, gtp_output_file);
break;
}
case 'd':
{
int d = va_arg(ap, int);
- fprintf(stdout, "%d", d);
+ fprintf(gtp_output_file, "%d", d);
break;
}
case 'f':
{
double f = va_arg(ap, double); /* passed as double, not float */
- fprintf(stdout, "%f", f);
+ fprintf(gtp_output_file, "%f", f);
break;
}
case 's':
{
char *s = va_arg(ap, char *);
- fputs(s, stdout);
+ fputs(s, gtp_output_file);
break;
}
case 'm':
@@ -212,20 +221,21 @@ gtp_mprintf(const char *fmt, ...)
{
int color = va_arg(ap, int);
if (color == WHITE)
- fputs("white", stdout);
+ fputs("white", gtp_output_file);
else if (color == BLACK)
- fputs("black", stdout);
+ fputs("black", gtp_output_file);
else
- fputs("empty", stdout);
+ fputs("empty", gtp_output_file);
break;
}
default:
- fprintf(stdout, "\n\nUnknown format character '%c'\n", *fmt);
+ /* FIXME: Should go to `stderr' instead? */
+ fprintf(gtp_output_file, "\n\nUnknown format character '%c'\n", *fmt);
break;
}
}
else
- putc(*fmt, stdout);
+ putc(*fmt, gtp_output_file);
}
va_end(ap);
}
@@ -237,7 +247,7 @@ gtp_printf(const char *format, ...)
{
va_list ap;
va_start(ap, format);
- vfprintf(stdout, format, ap);
+ vfprintf(gtp_output_file, format, ap);
va_end(ap);
}
@@ -278,7 +288,7 @@ gtp_success(const char *format, ...)
va_list ap;
gtp_start_response(GTP_SUCCESS);
va_start(ap, format);
- vfprintf(stdout, format, ap);
+ vfprintf(gtp_output_file, format, ap);
va_end(ap);
return gtp_finish_response();
}
@@ -291,7 +301,7 @@ gtp_failure(const char *format, ...)
va_list ap;
gtp_start_response(GTP_FAILURE);
va_start(ap, format);
- vfprintf(stdout, format, ap);
+ vfprintf(gtp_output_file, format, ap);
va_end(ap);
return gtp_finish_response();
}
Index: interface/gtp.h
===================================================================
RCS file: /cvsroot/gnugo/gnugo/interface/gtp.h,v
retrieving revision 1.15
diff -u -p -r1.15 gtp.h
--- interface/gtp.h 24 Jan 2004 04:04:56 -0000 1.15
+++ interface/gtp.h 8 Oct 2004 20:01:24 -0000
@@ -65,8 +65,8 @@ struct gtp_command {
gtp_fn_ptr function;
};
-void gtp_main_loop(struct gtp_command commands[], FILE *gtp_input,
- FILE *gtp_dump_commands);
+void gtp_main_loop(struct gtp_command commands[],
+ FILE *gtp_input, FILE *gtp_output, FILE *gtp_dump_commands);
void gtp_internal_set_boardsize(int size);
void gtp_set_vertex_transform_hooks(gtp_transform_ptr in,
gtp_transform_ptr out);
@@ -83,6 +83,8 @@ int gtp_decode_move(char *s, int *color,
void gtp_print_vertices(int n, int movei[], int movej[]);
void gtp_print_vertex(int i, int j);
+extern FILE *gtp_output_file;
+
/*
* Local Variables:
* tab-width: 8
Index: interface/interface.h
===================================================================
RCS file: /cvsroot/gnugo/gnugo/interface/interface.h,v
retrieving revision 1.15
diff -u -p -r1.15 interface.h
--- interface/interface.h 24 Jan 2004 04:04:56 -0000 1.15
+++ interface/interface.h 8 Oct 2004 20:01:24 -0000
@@ -35,7 +35,7 @@ void play_ascii(SGFTree *tree, Gameinfo
char *filename, char *until);
void play_ascii_emacs(SGFTree *tree, Gameinfo *gameinfo,
char *filename, char *until);
-void play_gtp(FILE *gtp_input, FILE *gtp_dump_commands,
+void play_gtp(FILE *gtp_input, FILE *gtp_output, FILE *gtp_dump_commands,
int gtp_initial_orientation);
void play_gmp(Gameinfo *gameinfo, int simplified);
void play_solo(Gameinfo *gameinfo, int benchmark);
Index: interface/main.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/interface/main.c,v
retrieving revision 1.103
diff -u -p -r1.103 main.c
--- interface/main.c 8 Sep 2004 17:03:42 -0000 1.103
+++ interface/main.c 8 Oct 2004 20:01:28 -0000
@@ -34,6 +34,10 @@
#include <io.h>
#endif
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
#if TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
@@ -74,6 +78,8 @@ enum {OPT_BOARDSIZE = 127,
OPT_OUTFILE,
OPT_QUIET,
OPT_GTP_INPUT,
+ OPT_GTP_CONNECT,
+ OPT_GTP_LISTEN,
OPT_GTP_DUMP_COMMANDS,
OPT_GTP_INITIAL_ORIENTATION,
OPT_GTP_VERSION,
@@ -189,6 +195,8 @@ static struct gg_option const long_optio
{"quiet", no_argument, 0, OPT_QUIET},
{"silent", no_argument, 0, OPT_QUIET},
{"gtp-input", required_argument, 0, OPT_GTP_INPUT},
+ {"gtp-connect", required_argument, 0, OPT_GTP_CONNECT},
+ {"gtp-listen", required_argument, 0, OPT_GTP_LISTEN},
{"gtp-dump-commands", required_argument, 0, OPT_GTP_DUMP_COMMANDS},
{"orientation", required_argument, 0, OPT_GTP_INITIAL_ORIENTATION},
{"gtp-initial-orientation",
@@ -311,6 +319,8 @@ main(int argc, char *argv[])
char *outflags = NULL;
char *gtpfile = NULL;
char *gtp_dump_commands_file = NULL;
+ int gtp_tcp_ip_mode = 0;
+ char *gtp_tcp_ip_address = NULL;
char *printsgffile = NULL;
@@ -319,8 +329,6 @@ main(int argc, char *argv[])
char debuginfluence_move[4] = "\0";
int benchmark = 0; /* benchmarking mode (-b) */
- FILE *gtp_input_FILE;
- FILE *gtp_dump_commands_FILE = NULL;
FILE *output_check;
int orientation = 0;
@@ -443,11 +451,25 @@ main(int argc, char *argv[])
case OPT_QUIET:
quiet = 1;
break;
-
+
case OPT_GTP_INPUT:
- gtpfile = gg_optarg;
+ case OPT_GTP_CONNECT:
+ case OPT_GTP_LISTEN:
+ if (gtp_tcp_ip_mode != 0 || gtpfile != NULL) {
+ fprintf(stderr, ("Options `--gtp-input', `--gtp-connect' and
`--gtp-listen' "
+ "are mutually-exclusive\n"));
+ exit(EXIT_FAILURE);
+ }
+
+ if (i == OPT_GTP_INPUT)
+ gtpfile = gg_optarg;
+ else {
+ gtp_tcp_ip_mode = i;
+ gtp_tcp_ip_address = gg_optarg;
+ }
+
break;
-
+
case OPT_GTP_DUMP_COMMANDS:
gtp_dump_commands_file = gg_optarg;
break;
@@ -1340,29 +1362,104 @@ main(int argc, char *argv[])
}
#endif
- case MODE_GTP:
- if (gtpfile != NULL) {
- gtp_input_FILE = fopen(gtpfile, "r");
- if (gtp_input_FILE == NULL) {
- fprintf(stderr, "gnugo: Cannot open file %s\n", gtpfile);
- return EXIT_FAILURE;
- }
- }
- else
- gtp_input_FILE = stdin;
+ case MODE_GTP:
+ {
+ FILE *gtp_input_FILE = stdin;
+ FILE *gtp_output_FILE = stdout;
+ FILE *gtp_dump_commands_FILE = NULL;
+
+ if (gtpfile != NULL) {
+ gtp_input_FILE = fopen(gtpfile, "r");
+ if (gtp_input_FILE == NULL) {
+ fprintf(stderr, "gnugo: Cannot open file %s\n", gtpfile);
+ return EXIT_FAILURE;
+ }
+ }
- if (gtp_dump_commands_file != NULL) {
- gtp_dump_commands_FILE = fopen(gtp_dump_commands_file, "w");
- if (gtp_dump_commands_FILE == NULL) {
- fprintf(stderr, "gnugo: Cannot open file %s\n",
- gtp_dump_commands_file);
- return EXIT_FAILURE;
- }
+ if (gtp_tcp_ip_mode != 0) {
+ struct sockaddr_in address;
+ char *port_string = strchr(gtp_tcp_ip_address, ':');
+ int port = -1;
+ int main_socket;
+
+ if (port_string) {
+ *port_string++ = 0;
+
+ if (!inet_aton(gtp_tcp_ip_address, &address.sin_addr)) {
+ fprintf(stderr, "Cannot parse IP address\n");
+ exit(EXIT_FAILURE);
+ }
+
+ sscanf(port_string, "%u", &port);
+ }
+
+ if (port < 0 || 65535 < port) {
+ fprintf(stderr, "A valid TCP/IP port number expected\n");
+ exit(EXIT_FAILURE);
+ }
+
+ address.sin_family = AF_INET;
+ address.sin_port = htons(port);
+ /* address.sin_addr is set by inet_aton() above. */
+
+ main_socket = socket(PF_INET, SOCK_STREAM, 0);
+ if (main_socket == -1) {
+ fprintf(stderr, "Unable to open a socket to %s:%d\n",
+ gtp_tcp_ip_address, port);
+ exit(EXIT_FAILURE);
+ }
+
+ if (gtp_tcp_ip_mode == OPT_GTP_CONNECT) {
+ if (connect(main_socket, (struct sockaddr *) &address,
+ sizeof address) == -1) {
+ fprintf(stderr, "Failed to connect to %s:%d\n",
+ gtp_tcp_ip_address, port);
+ close(main_socket);
+ exit(EXIT_FAILURE);
+ }
+ }
+ else {
+ /* gtp_tcp_ip_mode == OPT_GTP_LISTEN */
+
+ int connection_socket;
+ if (bind(main_socket, (struct sockaddr *) &address,
+ sizeof address) == -1
+ || listen(main_socket, 0) == -1
+ || (connection_socket = accept(main_socket, NULL, NULL)) == -1) {
+ close(main_socket);
+ fprintf(stderr, "Failed to receive a connection at %s:%d\n",
+ gtp_tcp_ip_address, port);
+ exit(EXIT_FAILURE);
+ }
+
+ close(main_socket);
+ main_socket = connection_socket;
+ }
+
+ gtp_input_FILE = fdopen(main_socket, "r");
+ gtp_output_FILE = fdopen(dup(main_socket), "w");
+ }
+
+ if (gtp_dump_commands_file != NULL) {
+ gtp_dump_commands_FILE = fopen(gtp_dump_commands_file, "w");
+ if (gtp_dump_commands_FILE == NULL) {
+ fprintf(stderr, "gnugo: Cannot open file %s\n",
+ gtp_dump_commands_file);
+ return EXIT_FAILURE;
+ }
+ }
+
+ play_gtp(gtp_input_FILE, gtp_output_FILE, gtp_dump_commands_FILE,
+ orientation);
+
+ if (gtp_input_FILE != stdin)
+ fclose(gtp_input_FILE);
+ if (gtp_output_FILE != stdout)
+ fclose(gtp_output_FILE);
+ if (gtp_dump_commands_FILE)
+ fclose(gtp_dump_commands_FILE);
}
- play_gtp(gtp_input_FILE, gtp_dump_commands_FILE, orientation);
- if (gtp_dump_commands_FILE)
- fclose(gtp_dump_commands_FILE);
break;
case MODE_ASCII_EMACS:
Index: interface/play_gtp.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/interface/play_gtp.c,v
retrieving revision 1.153
diff -u -p -r1.153 play_gtp.c
--- interface/play_gtp.c 19 Jul 2004 12:23:09 -0000 1.153
+++ interface/play_gtp.c 8 Oct 2004 20:01:33 -0000
@@ -337,12 +337,15 @@ static struct gtp_command commands[] = {
/* Start playing using the Go Text Protocol. */
void
-play_gtp(FILE *gtp_input, FILE *gtp_dump_commands, int gtp_initial_orientation)
+play_gtp(FILE *gtp_input, FILE *gtp_output, FILE *gtp_dump_commands,
+ int gtp_initial_orientation)
{
- /* Make sure stdout is unbuffered. (Line buffering is also okay but
- * not necessary. Block buffering breaks GTP mode.)
+ /* Make sure `gtp_output' is unbuffered. (Line buffering is also
+ * okay but not necessary. Block buffering breaks GTP mode.)
+ *
+ * FIXME: Maybe should go to `gtp.c'?
*/
- setbuf(stdout, NULL);
+ setbuf(gtp_output, NULL);
/* Inform the GTP utility functions about the board size. */
gtp_internal_set_boardsize(board_size);
@@ -355,7 +358,7 @@ play_gtp(FILE *gtp_input, FILE *gtp_dump
/* Prepare pattern matcher and reading code. */
reset_engine();
clearstats();
- gtp_main_loop(commands, gtp_input, gtp_dump_commands);
+ gtp_main_loop(commands, gtp_input, gtp_output, gtp_dump_commands);
if (showstatistics)
showstats();
}
@@ -2633,7 +2636,7 @@ gtp_move_reasons(char *s)
return gtp_failure("vertex must not be occupied");
gtp_start_response(GTP_SUCCESS);
- if (list_move_reasons(stdout, POS(i, j)) == 0)
+ if (list_move_reasons(gtp_output_file, POS(i, j)) == 0)
gtp_printf("\n");
gtp_printf("\n");
return GTP_OK;
@@ -3562,7 +3565,7 @@ gtp_showboard(char *s)
gtp_start_response(GTP_SUCCESS);
gtp_printf("\n");
- simple_showboard(stdout);
+ simple_showboard(gtp_output_file);
return gtp_finish_response();
}
@@ -4015,7 +4018,7 @@ gtp_dragon_data(char *s)
&& dragon[POS(m, n)].origin == POS(m, n))) {
gtp_print_vertex(m, n);
gtp_printf(":\n");
- report_dragon(stdout, POS(m, n));
+ report_dragon(gtp_output_file, POS(m, n));
}
}
gtp_printf("\n");
@@ -4281,7 +4284,7 @@ static int
gtp_echo_err(char *s)
{
fprintf(stderr, "%s", s);
- fflush(stdout);
+ fflush(gtp_output_file);
fflush(stderr);
return gtp_success("%s", s);
}
- [gnugo-devel] TCP/IP connection built into GNU Go?,
Paul Pogonyshev <=
- Re: [gnugo-devel] TCP/IP connection built into GNU Go?, Gunnar Farnebäck, 2004/10/08
- Re: [gnugo-devel] TCP/IP connection built into GNU Go?, Paul Pogonyshev, 2004/10/09
- Re: [gnugo-devel] TCP/IP connection built into GNU Go?, Gunnar Farnebäck, 2004/10/09
- Re: [gnugo-devel] TCP/IP connection built into GNU Go?, Paul Pogonyshev, 2004/10/09
- Re: [gnugo-devel] TCP/IP connection built into GNU Go?, Gunnar Farnebäck, 2004/10/09
- Re: [gnugo-devel] TCP/IP connection built into GNU Go?, Paul Pogonyshev, 2004/10/09
- Re: [gnugo-devel] TCP/IP connection built into GNU Go?, Arend Bayer, 2004/10/10
- Re: [gnugo-devel] TCP/IP connection built into GNU Go?, bump, 2004/10/10
- Re: [gnugo-devel] TCP/IP connection built into GNU Go?, Paul Pogonyshev, 2004/10/10
- Re: [gnugo-devel] TCP/IP connection built into GNU Go?, Paul Pogonyshev, 2004/10/10