mirror of https://github.com/dirtbags/tanks.git
Merge branch 'master' of /home/neale/projects/ctf/tanks
Conflicts: summary.awk
This commit is contained in:
commit
50752d3c8f
2
Makefile
2
Makefile
|
@ -1,4 +1,4 @@
|
||||||
BINARIES = forftanks designer.cgi
|
BINARIES = forftanks upload.cgi
|
||||||
HTML = forf.html procs.html intro.html designer.html
|
HTML = forf.html procs.html intro.html designer.html
|
||||||
WWW = style.css grunge.png designer.js figures.js tanks.js nav.html.inc
|
WWW = style.css grunge.png designer.js figures.js tanks.js nav.html.inc
|
||||||
|
|
||||||
|
|
4
TODO.txt
4
TODO.txt
|
@ -1,14 +1,10 @@
|
||||||
BUGS
|
BUGS
|
||||||
====
|
====
|
||||||
|
|
||||||
* Fix "random" bug
|
|
||||||
* Pull fuzzie tree
|
|
||||||
|
|
||||||
|
|
||||||
Requests
|
Requests
|
||||||
========
|
========
|
||||||
|
|
||||||
* Keep 12 hours of runs (720 runs)
|
|
||||||
* Merge devdsp fixes (https://github.com/devdsp/tanks/commits/master)
|
* Merge devdsp fixes (https://github.com/devdsp/tanks/commits/master)
|
||||||
* Fix leaderboard
|
* Fix leaderboard
|
||||||
* Read sensors from "sensors" and not "sensor[0-9]"
|
* Read sensors from "sensors" and not "sensor[0-9]"
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
""" Here's an example tank, in RFC822ish format:
|
||||||
|
|
||||||
|
From: Joe Cool <joe@cool.cc>
|
||||||
|
Password: swordfish
|
||||||
|
Tank-Name: Red Baron
|
||||||
|
Color: #c7e148
|
||||||
|
Sensor-0: 50 0 7 1
|
||||||
|
Sensor-1: 30 0 90 0
|
||||||
|
|
||||||
|
get-turret 12 + set-turret! ( Rotate turret )
|
||||||
|
37 40 set-speed! ( Go in circles )
|
||||||
|
0 sensor? { fire! } if ( Fire if turret sensor triggered )
|
||||||
|
1 sensor? { -50 50 set-speed! } if ( Turn if collision sensor triggered )
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import sys
|
||||||
|
import email
|
||||||
|
import requests
|
||||||
|
|
||||||
|
def parse_args():
|
||||||
|
parser = argparse.ArgumentParser(description="Upload forf tanks.",
|
||||||
|
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||||
|
parser.add_argument('--infile', '-i', nargs='?', metavar='FILE',
|
||||||
|
help="filename containing tank program",
|
||||||
|
type=argparse.FileType('r'), default=sys.stdin)
|
||||||
|
parser.add_argument('--url', '-u', nargs='?', metavar='URL',
|
||||||
|
help="URL to submit your tank to",
|
||||||
|
default='http://woozle.org/tanks/designer.cgi')
|
||||||
|
return parser.parse_args()
|
||||||
|
|
||||||
|
def read_tank(infile):
|
||||||
|
msg = email.message_from_file(infile)
|
||||||
|
headers = dict(msg.items())
|
||||||
|
return headers, msg.get_payload()
|
||||||
|
|
||||||
|
def post_tank(headers, code, url='http://woozle.org/tanks/designer.cgi'):
|
||||||
|
request = {}
|
||||||
|
request['token'] = headers.get('Password', '')
|
||||||
|
request['name'] = headers.get('Tank-Name', '')
|
||||||
|
request['author'] = headers.get('From', '')
|
||||||
|
request['color'] = headers.get('Color', '#c0c0c0')
|
||||||
|
for sn in xrange(0, 10):
|
||||||
|
sensor = 'Sensor-{}'.format(sn)
|
||||||
|
if sensor in headers:
|
||||||
|
sr, sa, sw, st = headers[sensor].split()
|
||||||
|
request['s{}r'.format(sn)] = sr
|
||||||
|
request['s{}a'.format(sn)] = sa
|
||||||
|
request['s{}w'.format(sn)] = sw
|
||||||
|
request['s{}t'.format(sn)] = st
|
||||||
|
request['program'] = code
|
||||||
|
r = requests.post(url, data=request, headers={'Accept': 'text/plain'})
|
||||||
|
print(r.text)
|
||||||
|
r.raise_for_status()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
args = parse_args()
|
||||||
|
headers, code = read_tank(args.infile)
|
||||||
|
post_tank(headers, code, args.url)
|
2
ctanks.c
2
ctanks.c
|
@ -317,7 +317,7 @@ tanks_move_tank(struct tanks_game *game,
|
||||||
to be a penalty for having the treads go in opposite directions.
|
to be a penalty for having the treads go in opposite directions.
|
||||||
This probably plays hell with precisely-planned tanks, which I
|
This probably plays hell with precisely-planned tanks, which I
|
||||||
find very ha ha. */
|
find very ha ha. */
|
||||||
friction = .75 * (fabsf(tank->speed.current[0] - tank->speed.current[1]) / 200);
|
friction = TANK_FRICTION * (fabsf(tank->speed.current[0] - tank->speed.current[1]) / 200);
|
||||||
v[0] = tank->speed.current[0] * (1 - friction) * (TANK_TOP_SPEED / 100.0);
|
v[0] = tank->speed.current[0] * (1 - friction) * (TANK_TOP_SPEED / 100.0);
|
||||||
v[1] = tank->speed.current[1] * (1 - friction) * (TANK_TOP_SPEED / 100.0);
|
v[1] = tank->speed.current[1] * (1 - friction) * (TANK_TOP_SPEED / 100.0);
|
||||||
|
|
||||||
|
|
1
ctanks.h
1
ctanks.h
|
@ -14,6 +14,7 @@
|
||||||
#define TANK_MAX_ACCEL 35
|
#define TANK_MAX_ACCEL 35
|
||||||
#define TANK_MAX_TURRET_ROT (TAU/8)
|
#define TANK_MAX_TURRET_ROT (TAU/8)
|
||||||
#define TANK_TOP_SPEED 7
|
#define TANK_TOP_SPEED 7
|
||||||
|
#define TANK_FRICTION 0.75
|
||||||
|
|
||||||
/* (tank radius + tank radius)^2 */
|
/* (tank radius + tank radius)^2 */
|
||||||
#define TANK_COLLISION_ADJ2 \
|
#define TANK_COLLISION_ADJ2 \
|
||||||
|
|
320
designer.cgi.c
320
designer.cgi.c
|
@ -1,320 +0,0 @@
|
||||||
/*
|
|
||||||
* This software has been authored by an employee or employees of Los
|
|
||||||
* Alamos National Security, LLC, operator of the Los Alamos National
|
|
||||||
* Laboratory (LANL) under Contract No. DE-AC52-06NA25396 with the U.S.
|
|
||||||
* Department of Energy. The U.S. Government has rights to use,
|
|
||||||
* reproduce, and distribute this software. The public may copy,
|
|
||||||
* distribute, prepare derivative works and publicly display this
|
|
||||||
* software without charge, provided that this Notice and any statement
|
|
||||||
* of authorship are reproduced on all copies. Neither the Government
|
|
||||||
* nor LANS makes any warranty, express or implied, or assumes any
|
|
||||||
* liability or responsibility for the use of this software. If
|
|
||||||
* software is modified to produce derivative works, such modified
|
|
||||||
* software should be clearly marked, so as not to confuse it with the
|
|
||||||
* version available from LANL.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
|
|
||||||
char *BASE_PATH = "";
|
|
||||||
|
|
||||||
struct {
|
|
||||||
char *name;
|
|
||||||
size_t size;
|
|
||||||
} entries[] = {
|
|
||||||
{"name", 20},
|
|
||||||
{"author", 40},
|
|
||||||
{"color", 10},
|
|
||||||
{"program", 8192},
|
|
||||||
{NULL, 0}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
size_t inlen;
|
|
||||||
|
|
||||||
int
|
|
||||||
read_char()
|
|
||||||
{
|
|
||||||
if (inlen) {
|
|
||||||
inlen -= 1;
|
|
||||||
return getchar();
|
|
||||||
}
|
|
||||||
return EOF;
|
|
||||||
}
|
|
||||||
|
|
||||||
char
|
|
||||||
tonum(int c)
|
|
||||||
{
|
|
||||||
if ((c >= '0') && (c <= '9')) {
|
|
||||||
return c - '0';
|
|
||||||
}
|
|
||||||
if ((c >= 'a') && (c <= 'f')) {
|
|
||||||
return 10 + c - 'a';
|
|
||||||
}
|
|
||||||
if ((c >= 'A') && (c <= 'F')) {
|
|
||||||
return 10 + c - 'A';
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
char
|
|
||||||
read_hex()
|
|
||||||
{
|
|
||||||
int a = read_char();
|
|
||||||
int b = read_char();
|
|
||||||
|
|
||||||
return tonum(a)*16 + tonum(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read a key or a value. Since & and = aren't supposed to appear
|
|
||||||
outside of boundaries, we can use the same function for both.
|
|
||||||
*/
|
|
||||||
size_t
|
|
||||||
read_item(char *str, size_t maxlen)
|
|
||||||
{
|
|
||||||
int c;
|
|
||||||
size_t pos = 0;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
c = read_char();
|
|
||||||
switch (c) {
|
|
||||||
case EOF:
|
|
||||||
case '=':
|
|
||||||
case '&':
|
|
||||||
str[pos] = '\0';
|
|
||||||
return pos;
|
|
||||||
case '%':
|
|
||||||
c = read_hex();
|
|
||||||
break;
|
|
||||||
case '+':
|
|
||||||
c = ' ';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (pos < maxlen - 1) {
|
|
||||||
str[pos] = c;
|
|
||||||
pos += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t
|
|
||||||
copy_item(char *filename, size_t maxlen)
|
|
||||||
{
|
|
||||||
FILE *f;
|
|
||||||
char path[132];
|
|
||||||
int c;
|
|
||||||
size_t pos = 0;
|
|
||||||
|
|
||||||
snprintf(path, sizeof(path),
|
|
||||||
"%s%05d.%s", BASE_PATH,
|
|
||||||
getpid(), filename);
|
|
||||||
f = fopen(path, "w");
|
|
||||||
if (! f) {
|
|
||||||
/* Just send it to the bit bucket */
|
|
||||||
maxlen = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
c = read_char();
|
|
||||||
switch (c) {
|
|
||||||
case EOF:
|
|
||||||
case '=':
|
|
||||||
case '&':
|
|
||||||
if (f) fclose(f);
|
|
||||||
return pos;
|
|
||||||
case '%':
|
|
||||||
c = read_hex();
|
|
||||||
break;
|
|
||||||
case '+':
|
|
||||||
c = ' ';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (pos < maxlen) {
|
|
||||||
fputc(c, f);
|
|
||||||
pos += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
croak(char *msg)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
char path[132];
|
|
||||||
|
|
||||||
for (i = 0; entries[i].name; i += 1) {
|
|
||||||
snprintf(path, sizeof(path),
|
|
||||||
"%s%05d.%s", BASE_PATH,
|
|
||||||
getpid(), entries[i].name);
|
|
||||||
unlink(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Content-type: text/html\n\n");
|
|
||||||
printf("<html><head>\n");
|
|
||||||
printf("<link rel=\"stylesheet\" href=\"style.css\" type=\"text/css\">\n");
|
|
||||||
printf("<title>Tank submission error</title>\n");
|
|
||||||
printf("</head><body><h1>Tank submission error</h1>\n");
|
|
||||||
if (msg) {
|
|
||||||
printf("<p>%s.</p>\n", msg);
|
|
||||||
} else {
|
|
||||||
printf("<p>Something went wrong.</p>.\n");
|
|
||||||
}
|
|
||||||
printf("<p>Sorry it didn't work out.</p>\n");
|
|
||||||
printf("<p>You could go back and try again, though.</p>\n");
|
|
||||||
printf("</body></html>\n");
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
int sensor[10][4];
|
|
||||||
char key[20];
|
|
||||||
char token[40];
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
memset(sensor, 0, sizeof(sensor));
|
|
||||||
token[0] = '\0';
|
|
||||||
|
|
||||||
BASE_PATH = getenv("BASE_PATH");
|
|
||||||
if (! BASE_PATH) {
|
|
||||||
BASE_PATH = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
char *rm = getenv("REQUEST_METHOD");
|
|
||||||
|
|
||||||
if (! (rm && (0 == strcmp(rm, "POST")))) {
|
|
||||||
printf("405 Method not allowed\n");
|
|
||||||
printf("Allow: POST\n");
|
|
||||||
printf("Content-type: text/html\n");
|
|
||||||
printf("\n");
|
|
||||||
printf("<h1>Method not allowed</h1>\n");
|
|
||||||
printf("<p>I only speak POST. Sorry.</p>\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inlen = atoi(getenv("CONTENT_LENGTH"));
|
|
||||||
}
|
|
||||||
|
|
||||||
while (inlen) {
|
|
||||||
len = read_item(key, sizeof(key));
|
|
||||||
if (0 == strcmp(key, "token")) {
|
|
||||||
read_item(token, sizeof(token));
|
|
||||||
} else if ((3 == len) && ('s' == key[0])) {
|
|
||||||
/* sensor dealie, key = "s[0-9][rawt]" */
|
|
||||||
char val[5];
|
|
||||||
int n = key[1] - '0';
|
|
||||||
int i;
|
|
||||||
int p;
|
|
||||||
|
|
||||||
read_item(val, sizeof(val));
|
|
||||||
|
|
||||||
if (! (n >= 0) && (n <= 9)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
i = atoi(val);
|
|
||||||
|
|
||||||
switch (key[2]) {
|
|
||||||
case 'r':
|
|
||||||
p = 0;
|
|
||||||
break;
|
|
||||||
case 'a':
|
|
||||||
p = 1;
|
|
||||||
break;
|
|
||||||
case 'w':
|
|
||||||
p = 2;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
p = 3;
|
|
||||||
i = (val[0] != '\0');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
sensor[n][p] = i;
|
|
||||||
} else {
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; entries[i].name; i += 1) {
|
|
||||||
if (0 == strcmp(key, entries[i].name)) {
|
|
||||||
len = copy_item(key, entries[i].size);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sanitize token */
|
|
||||||
{
|
|
||||||
char *p = token;
|
|
||||||
|
|
||||||
while (*p) {
|
|
||||||
if (! isalnum(*p)) {
|
|
||||||
*p = '_';
|
|
||||||
}
|
|
||||||
p += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('\0' == token[0]) {
|
|
||||||
token[0] = '_';
|
|
||||||
token[1] = '\0';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Move files into their directory */
|
|
||||||
{
|
|
||||||
char path[132];
|
|
||||||
char dest[132];
|
|
||||||
struct stat st;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
snprintf(path, sizeof(path), "%s%s/", BASE_PATH, token);
|
|
||||||
if (-1 == stat(path, &st)) return croak("Invalid token");
|
|
||||||
if (! S_ISDIR(st.st_mode)) return croak("Invalid token");
|
|
||||||
for (i = 0; entries[i].name; i += 1) {
|
|
||||||
snprintf(path, sizeof(path),
|
|
||||||
"%s%05d.%s", BASE_PATH,
|
|
||||||
getpid(), entries[i].name);
|
|
||||||
snprintf(dest, sizeof(dest),
|
|
||||||
"%s%s/%s", BASE_PATH,
|
|
||||||
token, entries[i].name);
|
|
||||||
rename(path, dest);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < 10; i += 1) {
|
|
||||||
FILE *f;
|
|
||||||
|
|
||||||
snprintf(dest, sizeof(dest),
|
|
||||||
"%s%s/sensor%d", BASE_PATH,
|
|
||||||
token, i);
|
|
||||||
f = fopen(dest, "w");
|
|
||||||
if (! f) break;
|
|
||||||
|
|
||||||
fprintf(f, "%d %d %d %d\n",
|
|
||||||
sensor[i][0],
|
|
||||||
sensor[i][1],
|
|
||||||
sensor[i][2],
|
|
||||||
sensor[i][3]);
|
|
||||||
fclose(f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Content-type: text/html\n\n");
|
|
||||||
printf("<!DOCTYPE html>\n");
|
|
||||||
printf("<html><head>\n");
|
|
||||||
printf("<link rel=\"stylesheet\" href=\"style.css\" type=\"text/css\">\n");
|
|
||||||
printf("<title>Tank submitted</title>\n");
|
|
||||||
printf("</head><body><h1>Tank submitted</h1>\n");
|
|
||||||
printf("<p>You just uploaded a tank!</p>\n");
|
|
||||||
printf("<p>Let's hope it doesn't suck.</p>\n");
|
|
||||||
printf("</body></html>\n");
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -64,8 +64,7 @@ cat <<EOF >>$fn
|
||||||
</html>
|
</html>
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
summary.awk $tanks > summary.html.$$
|
summary.awk $tanks > summary.html.$$ && mv summary.html.$$ summary.html
|
||||||
mv summary.html.$$ summary.html
|
|
||||||
|
|
||||||
echo "done."
|
echo "done."
|
||||||
|
|
||||||
|
|
34
summary.awk
34
summary.awk
|
@ -1,24 +1,24 @@
|
||||||
#! /usr/bin/awk -f
|
#! /usr/bin/awk -f
|
||||||
|
|
||||||
function esc(s) {
|
function esc(s) {
|
||||||
gsub(/&/, "&", s);
|
gsub(/&/, "&", s);
|
||||||
gsub(/</, "<", s);
|
gsub(/</, "<", s);
|
||||||
gsub(/>/, ">", s);
|
gsub(/>/, ">", s);
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
BEGIN {
|
BEGIN {
|
||||||
ngames = 20;
|
ngames = 20;
|
||||||
getline rounds < "next-round";
|
getline rounds < "next-round";
|
||||||
|
|
||||||
print "<!DOCTYPE html>";
|
print "<!DOCTYPE html>";
|
||||||
print "<html>";
|
print "<html>";
|
||||||
print " <head>";
|
print " <head>";
|
||||||
print " <title>Dirtbags Tanks</title>";
|
print " <title>Dirtbags Tanks</title>";
|
||||||
print " <link rel=\"stylesheet\" href=\"style.css\" type=\"text/css\">";
|
print " <link rel=\"stylesheet\" href=\"style.css\" type=\"text/css\">";
|
||||||
print " </head>";
|
print " </head>";
|
||||||
print " <body>";
|
print " <body>";
|
||||||
print " <h1>Dirtbags Tanks</h1>";
|
print " <h1>Dirtbags Tanks</h1>";
|
||||||
|
|
||||||
print " <p>New here? Read the <a href=\"intro.html\">introduction</a>.</p>";
|
print " <p>New here? Read the <a href=\"intro.html\">introduction</a>.</p>";
|
||||||
print " <p>New round every minute.</p>";
|
print " <p>New round every minute.</p>";
|
||||||
|
@ -68,10 +68,10 @@ BEGIN {
|
||||||
}
|
}
|
||||||
print " </ul>";
|
print " </ul>";
|
||||||
|
|
||||||
while (getline < ENVIRON["NAV_HTML_INC"]) {
|
while (getline < ENVIRON["NAV_HTML_INC"]) {
|
||||||
print;
|
print;
|
||||||
}
|
}
|
||||||
|
|
||||||
print " </body>";
|
print " </body>";
|
||||||
print "</html>";
|
print "</html>";
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,303 @@
|
||||||
|
/*
|
||||||
|
* This software has been authored by an employee or employees of Los
|
||||||
|
* Alamos National Security, LLC, operator of the Los Alamos National
|
||||||
|
* Laboratory (LANL) under Contract No. DE-AC52-06NA25396 with the U.S.
|
||||||
|
* Department of Energy. The U.S. Government has rights to use,
|
||||||
|
* reproduce, and distribute this software. The public may copy,
|
||||||
|
* distribute, prepare derivative works and publicly display this
|
||||||
|
* software without charge, provided that this Notice and any statement
|
||||||
|
* of authorship are reproduced on all copies. Neither the Government
|
||||||
|
* nor LANS makes any warranty, express or implied, or assumes any
|
||||||
|
* liability or responsibility for the use of this software. If
|
||||||
|
* software is modified to produce derivative works, such modified
|
||||||
|
* software should be clearly marked, so as not to confuse it with the
|
||||||
|
* version available from LANL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
char *BASE_PATH = "";
|
||||||
|
|
||||||
|
struct {
|
||||||
|
char *name;
|
||||||
|
size_t size;
|
||||||
|
} entries[] = {
|
||||||
|
{
|
||||||
|
"name", 20}, {
|
||||||
|
"author", 80}, {
|
||||||
|
"color", 10}, {
|
||||||
|
"program", 16384}, {
|
||||||
|
NULL, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
size_t inlen;
|
||||||
|
|
||||||
|
int
|
||||||
|
read_char()
|
||||||
|
{
|
||||||
|
if (inlen) {
|
||||||
|
inlen -= 1;
|
||||||
|
return getchar();
|
||||||
|
}
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
char
|
||||||
|
tonum(int c)
|
||||||
|
{
|
||||||
|
if ((c >= '0') && (c <= '9')) {
|
||||||
|
return c - '0';
|
||||||
|
}
|
||||||
|
if ((c >= 'a') && (c <= 'f')) {
|
||||||
|
return 10 + c - 'a';
|
||||||
|
}
|
||||||
|
if ((c >= 'A') && (c <= 'F')) {
|
||||||
|
return 10 + c - 'A';
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char
|
||||||
|
read_hex()
|
||||||
|
{
|
||||||
|
int a = read_char();
|
||||||
|
int b = read_char();
|
||||||
|
|
||||||
|
return tonum(a) * 16 + tonum(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read a key or a value. Since & and = aren't supposed to appear outside of boundaries, we can use the same function for both.
|
||||||
|
*/
|
||||||
|
size_t
|
||||||
|
read_item(char *str, size_t maxlen)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
size_t pos = 0;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
c = read_char();
|
||||||
|
switch (c) {
|
||||||
|
case EOF:
|
||||||
|
case '=':
|
||||||
|
case '&':
|
||||||
|
str[pos] = '\0';
|
||||||
|
return pos;
|
||||||
|
case '%':
|
||||||
|
c = read_hex();
|
||||||
|
break;
|
||||||
|
case '+':
|
||||||
|
c = ' ';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (pos < maxlen - 1) {
|
||||||
|
str[pos] = c;
|
||||||
|
pos += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
copy_item(char *filename, size_t maxlen)
|
||||||
|
{
|
||||||
|
FILE *f;
|
||||||
|
char path[132];
|
||||||
|
int c;
|
||||||
|
size_t pos = 0;
|
||||||
|
|
||||||
|
snprintf(path, sizeof(path), "%s%05d.%s", BASE_PATH, getpid(), filename);
|
||||||
|
f = fopen(path, "w");
|
||||||
|
if (!f) {
|
||||||
|
/*
|
||||||
|
* Just send it to the bit bucket
|
||||||
|
*/
|
||||||
|
maxlen = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
c = read_char();
|
||||||
|
switch (c) {
|
||||||
|
case EOF:
|
||||||
|
case '=':
|
||||||
|
case '&':
|
||||||
|
if (f)
|
||||||
|
fclose(f);
|
||||||
|
return pos;
|
||||||
|
case '%':
|
||||||
|
c = read_hex();
|
||||||
|
break;
|
||||||
|
case '+':
|
||||||
|
c = ' ';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (pos < maxlen) {
|
||||||
|
fputc(c, f);
|
||||||
|
pos += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
croak(int code, char *msg)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char path[132];
|
||||||
|
|
||||||
|
for (i = 0; entries[i].name; i += 1) {
|
||||||
|
snprintf(path, sizeof(path), "%s%05d.%s", BASE_PATH, getpid(), entries[i].name);
|
||||||
|
unlink(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Status: %d %s\n", code, msg);
|
||||||
|
printf("Content-type: text/plain\n");
|
||||||
|
printf("\n");
|
||||||
|
printf("Error: %s\n", msg);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int sensor[10][4];
|
||||||
|
char key[20];
|
||||||
|
char token[40];
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
memset(sensor, 0, sizeof(sensor));
|
||||||
|
token[0] = '\0';
|
||||||
|
|
||||||
|
BASE_PATH = getenv("BASE_PATH");
|
||||||
|
if (!BASE_PATH) {
|
||||||
|
BASE_PATH = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
char *rm = getenv("REQUEST_METHOD");
|
||||||
|
|
||||||
|
if (!(rm && (0 == strcmp(rm, "POST")))) {
|
||||||
|
printf("405 Method not allowed\n");
|
||||||
|
printf("Allow: POST\n");
|
||||||
|
printf("Content-type: text/plain\n");
|
||||||
|
printf("\n");
|
||||||
|
printf("Error: I only speak POST\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inlen = atoi(getenv("CONTENT_LENGTH"));
|
||||||
|
}
|
||||||
|
|
||||||
|
while (inlen) {
|
||||||
|
len = read_item(key, sizeof(key));
|
||||||
|
if (0 == strcmp(key, "token")) {
|
||||||
|
read_item(token, sizeof(token));
|
||||||
|
} else if ((3 == len) && ('s' == key[0])) {
|
||||||
|
/*
|
||||||
|
* sensor dealie, key = "s[0-9][rawt]"
|
||||||
|
*/
|
||||||
|
char val[5];
|
||||||
|
int n = key[1] - '0';
|
||||||
|
int i;
|
||||||
|
int p;
|
||||||
|
|
||||||
|
read_item(val, sizeof(val));
|
||||||
|
|
||||||
|
if (!(n >= 0) && (n <= 9)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i = atoi(val);
|
||||||
|
|
||||||
|
switch (key[2]) {
|
||||||
|
case 'r':
|
||||||
|
p = 0;
|
||||||
|
break;
|
||||||
|
case 'a':
|
||||||
|
p = 1;
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
p = 2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
p = 3;
|
||||||
|
i = (val[0] != '\0');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
sensor[n][p] = i;
|
||||||
|
} else {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; entries[i].name; i += 1) {
|
||||||
|
if (0 == strcmp(key, entries[i].name)) {
|
||||||
|
len = copy_item(key, entries[i].size);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sanitize token
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
char *p = token;
|
||||||
|
|
||||||
|
while (*p) {
|
||||||
|
if (!isalnum(*p)) {
|
||||||
|
*p = '_';
|
||||||
|
}
|
||||||
|
p += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('\0' == token[0]) {
|
||||||
|
token[0] = '_';
|
||||||
|
token[1] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Move files into their directory
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
char path[132];
|
||||||
|
char dest[132];
|
||||||
|
struct stat st;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
snprintf(path, sizeof(path), "%s%s/", BASE_PATH, token);
|
||||||
|
if (-1 == stat(path, &st))
|
||||||
|
return croak(422, "Invalid token");
|
||||||
|
if (!S_ISDIR(st.st_mode))
|
||||||
|
return croak(422, "Invalid token");
|
||||||
|
for (i = 0; entries[i].name; i += 1) {
|
||||||
|
snprintf(path, sizeof(path), "%s%05d.%s", BASE_PATH, getpid(), entries[i].name);
|
||||||
|
snprintf(dest, sizeof(dest), "%s%s/%s", BASE_PATH, token, entries[i].name);
|
||||||
|
rename(path, dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 10; i += 1) {
|
||||||
|
FILE *f;
|
||||||
|
|
||||||
|
snprintf(dest, sizeof(dest), "%s%s/sensor%d", BASE_PATH, token, i);
|
||||||
|
f = fopen(dest, "w");
|
||||||
|
if (!f)
|
||||||
|
break;
|
||||||
|
|
||||||
|
fprintf(f, "%d %d %d %d\n", sensor[i][0], sensor[i][1], sensor[i][2], sensor[i][3]);
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Content-type: text/plain\n");
|
||||||
|
printf("\n");
|
||||||
|
printf("OK: Tank submitted!\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue