4f9b942e1b4e18a3d63d0e759aa91dfa8ad03c6c
[capablanca.git] / lasker-2.2.3 / src / timeseal.c
1 /* 
2    Copyright 2002 Andrew Tridgell <tridge@samba.org>
3    
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2 of the License, or
7    (at your option) any later version.
8    
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13    
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.   
17  */
18
19 /*   glue code that connects the chess server to the external timeseal
20  *   decoder */
21
22 #include "includes.h"
23
24 /*
25   send a string to the decoder sub-process and return the modified (decoded) string 
26   the return value is the decoded timestamp. It will be zero if the decoder didn't
27   recognise the input as valid timeseal data
28  */
29 static unsigned decode(unsigned char *s)
30 {
31         char line[1024];
32         char *p;
33         unsigned t = 0;
34   
35         /* send the encoded data to the decoder process */
36         dprintf(timeseal_globals.decoder_conn, "%s\n", s);
37         
38         if (!fd_gets(line, sizeof(line), timeseal_globals.decoder_conn)) {
39                 d_printf("Bad result from timeseal decoder? (t=%u)\n", t);
40                 close(timeseal_globals.decoder_conn);
41                 timeseal_globals.decoder_conn = -1;
42                 return 0;
43         }
44         line[strlen(line)-1] = 0;
45
46         p = strchr(line, ':');
47         if (!p) {
48                 d_printf("Badly formed timeseal decoder line: [%s]\n", line);
49                 close(timeseal_globals.decoder_conn);
50                 timeseal_globals.decoder_conn = -1;
51                 return 0;
52         }
53         
54         t = atoi(line);
55         strcpy(s, p+2);
56         
57         return t;
58 }
59
60 /* 
61    initialise the timeseal decoder sub-process
62 */
63 void timeseal_init(const char *path)
64 {
65         int fd[2];
66         pid_t pid;
67         
68         /* use a socketpair to get a bi-directional pipe with large buffers */
69         if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) != 0) {
70                 d_printf("Failed to create socket pair!\n");
71                 exit(1);
72         }
73         
74         pid = fork();
75         
76         if (pid == 0) {
77                 close(fd[1]);
78                 close(0);
79                 close(1);
80                 close(2);
81                 dup2(fd[0], 0);
82                 dup2(fd[0], 1);
83                 open("/dev/null", O_WRONLY); /* stderr */
84                 execl(path, "[timeseal]", NULL);
85                 exit(1);
86         }
87         
88         timeseal_globals.decoder_conn = fd[1];
89         close(fd[0]);
90 }
91
92
93 /* 
94    parse a command line from a user on *con that may be timeseal encoded. 
95    return 1 if the command should be processed further, 0 if the command
96    should be discarded
97  */
98 int timeseal_parse(char *command, struct connection_t *con)
99 {
100         unsigned t;
101         
102         /* do we have a decoder sub-process? */
103         if (timeseal_globals.decoder_conn <= 0) return 1;
104         
105         /* are they using timeseal on this connection? */
106         if (!con->timeseal_init && !con->timeseal) return 1;
107         
108         t = decode(command);
109         
110         if (t == 0) {
111                 /* this wasn't encoded using timeseal */
112                 d_printf("Non-timeseal data [%s]\n", command);
113                 con->timeseal_init = 0;
114                 return 1;
115         }
116         
117         if (con->timeseal_init) {
118                 con->timeseal_init = 0;
119                 con->timeseal = 1;
120                 d_printf("Connected with timeseal %s\n", command);
121                 if (strncmp(command, "TIMESTAMP|", 10) == 0) {
122                         return 0;
123                 }
124         }
125         
126         con->time = t;
127         
128         /* now check for the special move time tag */
129         if (strcmp(command, "\ 29") == 0) {
130                 int p = player_find(con->fd);
131                 struct player *pp = &player_globals.parray[p];
132                 if (p >= 0 && pp->game >= 0) {
133                         int g = pp->game;
134                         if (game_globals.garray[g].game_state.onMove != 
135                             pp->side) {
136                                 return 0;
137                         }
138                         if (pp->side == WHITE) {
139                                 if (game_globals.garray[g].wTimeWhenReceivedMove == 0) {
140                                         game_globals.garray[g].wTimeWhenReceivedMove = t;
141                                 }
142                         } else {
143                                 if (game_globals.garray[g].bTimeWhenReceivedMove == 0) {
144                                         game_globals.garray[g].bTimeWhenReceivedMove = t;
145                                 }
146                         }
147                         if (game_globals.garray[g].flag_pending != FLAG_NONE) {
148                                 ExecuteFlagCmd(p, net_globals.con[pp->socket]);
149                         }
150                 }
151                 /* we have processed this special tag - don't process it further */
152                 return 0;
153         }
154         
155         return 1;
156 }
157
158 /*
159   used to call flag on players with timeseal
160  */
161 void ExecuteFlagCmd(int p, struct connection_t *con)
162 {
163         struct player *pp = &player_globals.parray[p];
164         struct game *gg;
165
166         if (pp->game == -1) {
167                 return;
168         }
169
170         gg = &game_globals.garray[pp->game];
171
172         if (pp->side == WHITE) {
173                 gg->wRealTime -= con->time - gg->wTimeWhenReceivedMove;
174                 gg->wTimeWhenReceivedMove = con->time;
175                 if (gg->wRealTime < 0) {
176                         pcommand(pp->opponent, "flag");
177                 }
178         } else if (pp->side == BLACK) {
179                 gg->bRealTime -= con->time - gg->wTimeWhenReceivedMove;
180                 gg->bTimeWhenReceivedMove = con->time;
181                 if (gg->bRealTime < 0) {
182                         pcommand(pp->opponent, "flag");
183                 }
184         }
185
186         game_update_time(pp->game);
187         gg->flag_pending = FLAG_NONE;
188 }