Merge branch 'master' of thejh.net:quakecontrol
[quakecontrol.git] / common.c
1 // Copyright (2013) Jann Horn <jann@thejh.net>
2 // This code is licensed under the AGPLv3.
3
4 #include "common.h"
5
6 #include <unistd.h>
7 #include <strings.h>
8 #include <sys/types.h>
9 #include <sys/socket.h>
10 #include <netinet/in.h>
11 #include <arpa/inet.h>
12
13 extern char *rcon_host, *rcon_port, *rcon_pass, *map;
14
15 void senderr(char *errmsg, bool myfault) {
16   if (myfault) {
17     puts("Status: 500 CGI error");
18   } else {
19     puts("Status: 400 CGI error");
20   }
21   puts("Content-Type: text/plain;charset=utf8");
22   puts("X-Frame-Options: DENY");
23   puts("");
24   puts("An error occured while processing your request:");
25   puts(errmsg);
26   exit(0);
27 }
28
29 struct inifile *get_config(void) {
30   static struct inifile *res = NULL;
31   if (!res) res = slurp_inifile(CONFIG_PATH);
32   if (!res) {
33     // error!
34     senderr("can't fetch config", true);
35   }
36   return res;
37 }
38
39 char *getcval(char *key) {
40   char *r = inifile_lookup(get_config(), key);
41   if (!r) {
42     // error!
43     senderr("config value missing", true);
44   }
45   return r;
46 }
47
48 void rcon_send(char *data) {
49   // get config
50   char *host = getcval("rcon_host");
51   char *port = getcval("rcon_port");
52   char *pass = getcval("rcon_pass");
53   
54   // construct packet
55   size_t pass_len = strlen(pass);
56   size_t data_len = strlen(data);
57   size_t packet_len = 4+4+1+pass_len+1+data_len +1;
58   char buf[packet_len];
59   char *p = buf;
60   memcpy(p, "\xff\xff\xff\xffrcon ", 9); p += 9;
61   memcpy(p, pass, pass_len); p += pass_len;
62   *(p++) = ' ';
63   memcpy(p, data, data_len); p += data_len;
64   *(p++) = '\0';
65   
66   // connect
67   int fd = socket(AF_INET, SOCK_DGRAM, 0);
68   if (fd == -1) senderr("can't create UDP socket", true);
69   struct sockaddr_in addr;
70   bzero(&addr, sizeof(addr));
71   addr.sin_family = AF_INET;
72   addr.sin_port = htons(atoi(port));
73   if (!inet_aton(host, &addr.sin_addr)) senderr("bad ipv4 addr in config", true);
74   if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)))
75     senderr("can't connect UDP socket", true);
76   
77   // send
78   if (write(fd, buf, packet_len) != packet_len)
79     senderr("incomplete packet sent or write error", true);
80   
81   close(fd);
82 }