aboutsummaryrefslogtreecommitdiff
path: root/rcon/rcon.c
blob: ea29ee9b8d97e07a51e1ebf7bfa87a45a1ae8a7c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/*
 * Adopted from mcrcon, Copyright (c) 2012-2020, Tiiffi <tiiffi at gmail>.
 * https://github.com/Tiiffi/mcrcon/tree/b02201d689b3032bc681b28f175fd3d83d167293
 */

#include "rcon.h"
#include "../common.h"

#include <sys/socket.h>
#include <sysexits.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

int rcon_send_packet(int sd, RconPacket *packet)
{
        int len;
        int total = 0;  // bytes we've sent
        int bytesleft;  // bytes left to send
        int ret = -1;

        bytesleft = len = packet->size + sizeof(int);

        while (total < len)
	{
                ret = send(sd, (char *) packet + total, bytesleft, 0);
                if(ret == -1)
		{
			fprintf(stderr, _("send(): %s.\n"), strerror(errno));
			return EX_IOERR;
		}
                total += ret;
                bytesleft -= ret;
        }

	return EX_OK;
}

int rcon_build_packet(RconPacket *out, int id, int cmd, char *s1)
{
        // size + id + cmd + s1 + s2 NULL terminator
        int s1_len = strlen(s1);
        if (s1_len > RCON_DATA_BUFFSIZE)
	{
                fprintf(stderr, _("Warning: Command string too long (%d). Maximum allowed: %d.\n"), s1_len, RCON_DATA_BUFFSIZE);
                return EX_DATAERR;
        }

        out->size = sizeof(int) * 2 + s1_len + 2;
        out->id = id;
        out->cmd = cmd;
        strncpy(out->data, s1, RCON_DATA_BUFFSIZE);

	return EX_OK;
}


void rcon_print_packet(RconPacket *packet)
{
	int i;

	for (i = 0; (unsigned char) packet->data[i] != 0; ++i)
	{
		if ((unsigned char) packet->data[i] == 0xc2 && (unsigned char) packet->data[i+1] == 0xa7)
		{
			i+=2;
                        continue;
                }
                putchar(packet->data[i]);
        }

        // print newline if string has no newline
        if (packet->data[i-1] != 10 && packet->data[i-1] != 13) putchar('\n');
}

int rcon_recv_packet(RconPacket *out, int sd)
{
        int psize;

        int ret = recv(sd, (char *) &psize, sizeof(int), 0);

        if (ret == 0)
	{
                fprintf(stderr, _("Connection lost.\n"));
                return EX_IOERR;
        }
	if(ret == -1)
	{
		fprintf(stderr, _("recv(): %d\n"), errno);
		return EX_IOERR;
	}

        if (ret != sizeof(int))
	{
                fprintf(stderr, _("Error: recv() failed. Invalid packet size (%d).\n"), ret);
                return EX_IOERR;
        }

        if (psize < 10 || psize > RCON_DATA_BUFFSIZE)
	{
                fprintf(stderr, _("Warning: invalid packet size (%d). Must over 10 and less than %d.\n"), psize, RCON_DATA_BUFFSIZE);

                if(psize > RCON_DATA_BUFFSIZE  || psize < 0) psize = RCON_DATA_BUFFSIZE;
		// Former net_clean_incoming.
		char tmp[psize];
		ret = recv(sd, tmp, psize, 0);

	        if(ret == 0)
		{
			fprintf(stderr, _("Connection lost.\n"));
		}

                return EX_DATAERR;
        }

        out->size = psize;

        int received = 0;
        while (received < psize)
	{
                ret = recv(sd, (char *) out + sizeof(int) + received, psize - received, 0);
                if (ret == 0) // connection closed before completing receving
		{
                        fprintf(stderr, _("Connection lost.\n"));
                        return EX_IOERR;
                }

                received += ret;
        }

        return EX_OK;
}