Skip to content

Commit

Permalink
add tcptron
Browse files Browse the repository at this point in the history
  • Loading branch information
grogers0 committed Mar 13, 2010
1 parent e8457fc commit 127a08f
Show file tree
Hide file tree
Showing 2 changed files with 196 additions and 0 deletions.
Binary file added tcptron
Binary file not shown.
196 changes: 196 additions & 0 deletions tcptron.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
/*
* Connects your local bot to a remote map server for one game.
* The map server connects random available bots on random maps,
* updating the map and enforcing the rules.
*
* gcc -o tcptron tcptron.c
* ./tcptron 213.3.30.106 9999 username ./MyTronBot
*
* See http://www.benzedrine.cx/tron.html for ELO ratings.
*
* History
* 1.3 20100225 fix bug (terminate buffers) on large maps
* 1.2 20100225 fix line splitting issue
* 1.1 20100225 support passing of user name
* 1.0 20100224 first version
*
* Copyright (c) 2010 Daniel Hartmeier <daniel@benzedrine.cx>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/

#include <arpa/inet.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

static int
tcp_connect(const char *host, unsigned port)
{
int fd;
struct sockaddr_in sa;

if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("socket: %s\n", strerror(errno));
return (-1);
}
memset(&sa, 0, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = inet_addr(host);
sa.sin_port = htons(port);
if (connect(fd, (struct sockaddr *)&sa, sizeof(sa))) {
printf("connect: %s\n", strerror(errno));
close(fd);
return (-1);
}
return (fd);
}

static pid_t
bpopen(char *cmd, int *fdr, int *fdw)
{
int p2c[2], c2p[2];
pid_t pid;
char *argv[] = { NULL, NULL };

argv[0] = cmd;
if (pipe(p2c) || pipe(c2p)) {
printf("pipe: %s\n", strerror(errno));
return (0);
}
if ((pid = fork()) < 0) {
printf("fork: %s\n", strerror(errno));
return (0);
}
if (!pid) {
close(c2p[0]);
close(p2c[1]);
dup2(c2p[1], STDOUT_FILENO);
dup2(p2c[0], STDIN_FILENO);
execv(argv[0], argv);
fprintf(stderr, "execv: %s: failed\n", argv[0]);
exit(1);
}
close(c2p[1]);
close(p2c[0]);
*fdw = p2c[1];
*fdr = c2p[0];
return (pid);
}

static void
split_lines(const char *s, char *d, unsigned len, int fd)
{
unsigned off = strlen(d);
while (*s && off + 2 < len) {
if ((d[off] = *s++) == '\n') {
d[off + 1] = 0;
if (!strncmp(d, "INFO ", 5))
printf("%s", d + 5);
else {
printf("%s", d);
write(fd, d, off + 1);
}
*d = 0;
off = 0;
} else
off++;
}
d[off] = 0;
}

int main(int argc, char *argv[])
{
int fd[3] = { -1, -1, -1 };
pid_t child = 0;
int i, r, len;
fd_set read_fds;
struct timeval tv;
char buf[1024], line[2][1024];

if (argc != 5) {
printf("usage: %s ip port username command\n", argv[0]);
return (1);
}

if (!(child = bpopen(argv[4], &fd[1], &fd[2])))
goto done;
sleep(3); /* allow child to properly startup... */

if ((fd[0] = tcp_connect(argv[1], atoi(argv[2]))) < 0)
goto done;
snprintf(buf, sizeof(buf), "USER %s\n", argv[3]);
write(fd[0], buf, strlen(buf));

printf("connected to %s:%s, waiting for game\n", argv[1], argv[2]);
line[0][0] = line[1][0] = 0;
while (1) {
FD_ZERO(&read_fds);
FD_SET(fd[0], &read_fds);
FD_SET(fd[1], &read_fds);
tv.tv_sec = 0;
tv.tv_usec = 1000;
r = select(((fd[0] > fd[1]) ? fd[0] : fd[1]) + 1, &read_fds,
NULL, NULL, &tv);
if (r < 0) {
if (errno != EINTR) {
printf("select: %s\n", strerror(errno));
goto done;
}
continue;
}
if (r == 0)
continue;
for (i = 0; i < 2; ++i) {
if (!FD_ISSET(fd[i], &read_fds))
continue;
len = read(fd[i], buf, sizeof(buf) - 1);
if (len < 0) {
if (errno != EINTR) {
printf("read: %s\n", strerror(errno));
goto done;
}
continue;
}
if (len == 0)
goto done;
buf[len] = 0;
split_lines(buf, line[i], sizeof(line[i]),
i ? fd[0] : fd[2]);
}
}

done:
for (i = 0; i < 3; ++i)
if (fd[i] != -1)
close(fd[i]);
if (child)
wait(NULL);
return (0);
}

0 comments on commit 127a08f

Please sign in to comment.