Skip to content

Commit 1ccbdc5

Browse files
committed
Merge pull request #19 from NosotrosNueces/sample-bot-r
First Sample Bot
2 parents b94ed6d + a02f9bc commit 1ccbdc5

9 files changed

Lines changed: 122 additions & 99 deletions

File tree

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
CC = clang
22
SA = scan-build
3-
_LIB_FILES = marshal.c protocol.c bot.c
3+
_LIB_FILES = marshal.c protocol.c bot.c client.c
44
_TEST_FILES = packet_test.c protocol_test.c test_runner.c
55
LIB_DIR = src
66
TEST_DIR = test
77
LIB_FILES= $(patsubst %,$(LIB_DIR)/%,$(_LIB_FILES))
88
TEST_FILES= $(patsubst %,$(TEST_DIR)/%,$(_TEST_FILES))
9-
CFLAGS=-Wall --std=gnu99 -Wfatal-errors
9+
CFLAGS=-Wall --std=gnu99 -Wfatal-errors -lpthread -g
1010
tests: bin
1111
$(CC) -o bin/tests $(LIB_FILES) $(TEST_FILES) -I $(LIB_DIR) $(CFLAGS)
1212
./bin/tests

src/bot.c

Lines changed: 29 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,16 @@ bot_t *init_bot(char *name, void (*bot_main)(void *)){
1919
// set the bot name
2020
bot_t *bot = calloc(1, sizeof(bot_t));
2121
bot->packet_threshold = DEFAULT_THRESHOLD;
22+
bot->buf = calloc(1, DEFAULT_THRESHOLD);
2223
size_t len = strlen(name);
2324
bot->name = calloc(len + 1, sizeof(char));
2425
strncpy(bot->name, name, len + 1);
2526
bot->bot_main = bot_main;
2627
// initialize the callback data structure
27-
bot->callbacks = calloc(NUM_STATES, sizeof(function **));
28-
bot->callbacks[HANDSHAKE] = calloc(HANDSHAKE_PACKETS, sizeof(function *));
29-
bot->callbacks[LOGIN] = calloc(LOGIN_PACKETS, sizeof(function *));
30-
bot->callbacks[PLAY] = calloc(PLAY_PACKETS, sizeof(function *));
28+
bot->callbacks = calloc(NUM_STATES, sizeof(function *));
29+
bot->callbacks[HANDSHAKE] = calloc(HANDSHAKE_PACKETS, sizeof(function));
30+
bot->callbacks[LOGIN] = calloc(LOGIN_PACKETS, sizeof(function));
31+
bot->callbacks[PLAY] = calloc(PLAY_PACKETS, sizeof(function));
3132
return bot;
3233
}
3334

@@ -37,15 +38,15 @@ void free_bot(bot_t *bot){
3738
// unrolled outer loop just cuz
3839
int i;
3940
for(i = 0; i < HANDSHAKE_PACKETS; i++){
40-
function *func = bot->callbacks[HANDSHAKE][i];
41+
function *func = &bot->callbacks[HANDSHAKE][i];
4142
free_list(func);
4243
}
4344
for(i = 0; i < LOGIN_PACKETS; i++){
44-
function *func = bot->callbacks[LOGIN][i];
45+
function *func = &bot->callbacks[LOGIN][i];
4546
free_list(func);
4647
}
4748
for(i = 0; i < PLAY_PACKETS; i++){
48-
function *func = bot->callbacks[PLAY][i];
49+
function *func = &bot->callbacks[PLAY][i];
4950
free_list(func);
5051
}
5152
free(bot);
@@ -59,50 +60,33 @@ void free_list(function *list){
5960

6061

6162
void register_event(bot_t *bot, uint32_t state, uint32_t packet_id,
62-
void (*f)(void *)){
63-
function *current = bot->callbacks[state][packet_id];
64-
while(current)
65-
current = current->next;
66-
current = calloc(1, sizeof(function));
67-
current->f = f;
63+
void (*f)(bot_t *, void *)){
64+
function *parent = &bot->callbacks[state][packet_id];
65+
while(parent->next)
66+
parent = parent->next;
67+
function *child = calloc(1, sizeof(function));
68+
parent->f = f;
69+
parent->next = child;
6870
}
6971

7072
// initializes a bot structure with a socket. The socket is bound to the local address on
7173
// some port and is connected to the server specified by the server_host and server_port
7274
// the socket descriptor is returned by the function. If -1 is returned, then an error
7375
// occured, and a message will have been printed out.
7476

75-
int join_server(bot_t *your_bot, char *local_port, char* server_host,
76-
char* server_port){
77-
int status;
77+
int join_server(bot_t *your_bot, char* server_host, char* server_port){
7878
struct addrinfo hints, *res;
7979
int sockfd;
80-
memset(&hints, 0, sizeof(hints));
80+
// first, load up address structs with getaddrinfo():
81+
memset(&hints, 0, sizeof hints);
8182
hints.ai_family = AF_UNSPEC;
8283
hints.ai_socktype = SOCK_STREAM;
83-
if((status = getaddrinfo(NULL, local_port, &hints, &res))){
84-
fprintf(stderr, "Your computer is literally haunted: %s\n",
85-
gai_strerror(status));
86-
return -1;
87-
}
88-
if((sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1){
89-
fprintf(stderr, "Could not create socket for unknown reason.\n");
90-
return -1;
91-
}
92-
freeaddrinfo(res);
93-
// socket bound to local address/port
84+
getaddrinfo(server_host, server_port, &hints, &res);
9485

95-
memset(&hints, 0, sizeof(hints));
96-
hints.ai_family = AF_UNSPEC;
97-
hints.ai_socktype = SOCK_STREAM;
98-
if((status = getaddrinfo(server_host, server_port, &hints, &res))){
99-
fprintf(stderr, "Server could not be resolved: %s\n",
100-
gai_strerror(status));
101-
return -1;
102-
}
86+
// make a socket and connect
87+
sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
10388
connect(sockfd, res->ai_addr, res->ai_addrlen);
104-
freeaddrinfo(res);
105-
// connected to server
89+
10690
your_bot->socketfd = sockfd;
10791
return sockfd;
10892
}
@@ -148,7 +132,7 @@ int receive_packet(bot_t *bot) {
148132
assert(i != len);
149133

150134
packet_size += len;
151-
received = len + 1;
135+
received = i + 1;
152136
if (packet_size <= bot->packet_threshold) {
153137
while (received < packet_size) {
154138
ret = receive_raw(bot, bot->buf + received, packet_size - received);
@@ -160,13 +144,17 @@ int receive_packet(bot_t *bot) {
160144
ret = peek_packet(bot, bot->buf);
161145
return ret;
162146
} else {
163-
// read in a huge buffer, but throw it away
164-
while (received < packet_size) {
147+
// read in a huge buffer, packet_threshold at a time
148+
while (received < packet_size - bot->packet_threshold) {
165149
ret = receive_raw(bot, bot->buf, bot->packet_threshold);
166150
if (ret <= 0)
167151
return -1;
168152
received += ret;
169153
}
154+
// read the last portion of the packet
155+
ret = receive_raw(bot, bot->buf, packet_size - received);
156+
if (ret <= 0)
157+
return -1;
170158
return -2;
171159
}
172160
}

src/bot.h

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,24 @@
66

77
typedef enum {HANDSHAKE, LOGIN, STATUS, PLAY, NUM_STATES} state;
88

9-
typedef struct _function {
10-
void (*f)(void *);
11-
struct _function *next;
12-
} function;
9+
typedef struct bot bot_t;
10+
typedef struct _function function;
1311

14-
typedef struct bot {
12+
struct bot {
1513
int socketfd;
1614
size_t packet_threshold;
1715
char *buf;
1816
char *name;
1917
state current_state;
2018
/* registered callbacks */
2119
void (*bot_main)(void *);
22-
function ***callbacks; // triple indirection hooray!
23-
} bot_t;
20+
function **callbacks;
21+
};
22+
23+
struct _function {
24+
void (*f)(bot_t *, void *);
25+
struct _function *next;
26+
};
2427

2528
extern struct bot context;
2629

@@ -47,15 +50,13 @@ void free_bot(bot_t *);
4750
* is recieved.
4851
* Note: Currently there is no way to "un-register" a callback.
4952
*/
50-
void register_event(bot_t *bot, uint32_t state, uint32_t packet_id, void (*f)(void *));
53+
void register_event(bot_t *bot, uint32_t state, uint32_t packet_id, void (*f)(bot_t *, void *));
5154

5255
/** \brief Open a socket to the specified server
5356
*
54-
* Open a socket connection to a specific server for a particular bot. It is
55-
* possible, but not useful, to choose the local bind port. A local_port value
56-
* of NULL should choose a random, open port.
57+
* Open a socket connection to a specific server for a particular bot.
5758
*/
58-
int join_server(bot_t *bot, char *local_port, char* server_host, char* server_port);
59+
int join_server(bot_t *bot, char* server_host, char* server_port);
5960

6061
/** \brief Sends a string across the network using a bot's socket
6162
*

src/client.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,29 +31,41 @@ void *bot_thread(void *bot);
3131
void client_run(bot_t *bots, uint32_t num) {
3232
// create 1 thread for receiving packets, and 1 for each bot
3333
int i;
34-
bot_list = bots;
3534
num_bots = num;
35+
bot_list = bots;
3636
pthread_key_create(&bot_key, NULL);
37-
37+
3838
// create & start listener thread
3939
pthread_t event_listener;
4040
pthread_create(&event_listener, NULL, receiver, NULL);
4141

4242
// create all the bot threads
43+
bot_threads = calloc(num_bots, sizeof(pthread_t));
4344
for(i = 0; i < num; i++) {
44-
pthread_create(bot_threads + i, NULL, bot_thread, bot_list + i);
45+
pthread_create(bot_threads + i, NULL, bot_thread, bot_list + i);
4546
}
46-
47+
4748
// wait for all threads to finish
4849
// TODO: support for exit codes
4950
pthread_join(event_listener, NULL);
5051
for(i = 0; i < num; i++) {
5152
pthread_join(bot_threads[i], NULL);
5253
}
54+
free(bot_threads);
5355
}
5456

5557
void *bot_thread(void *bot) {
5658
pthread_setspecific(bot_key, bot);
59+
60+
struct sigaction sa;
61+
sa.sa_handler = signal_handler;
62+
sa.sa_flags = SA_RESTART;
63+
sigemptyset(&sa.sa_mask);
64+
if (sigaction(SIGUSR1, &sa, NULL) == -1) {
65+
perror("sigaction");
66+
exit(1);
67+
}
68+
5769
((bot_t *)bot)->bot_main(bot);
5870
return NULL;
5971
}

src/client.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,4 @@
11
#include "bot.h"
2-
#include <pthread.h>
3-
#include <poll.h>
4-
#include <unistd.h>
5-
#include <signal.h>
6-
#include "protocol.h"
7-
#include <errno.h>
8-
#include <stdio.h>
92

103
void client_run(bot_t *, uint32_t);
114

src/marshal.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include <string.h>
22
#include <stdio.h>
33
#include <stdlib.h>
4+
#include <assert.h>
45
#include "marshal.h"
56
#include "bot.h"
67
#include "protocol.h"
@@ -181,7 +182,6 @@ int format_packet(bot_t *bot, void *packet_data, void **packet_raw_ptr){
181182
break;
182183
default:
183184
;
184-
size_t size = format_sizeof(*fmt);
185185
if(index + size > len)
186186
return -1; // TODO: compression
187187
memcpy(packet_raw + index, packet_data, size);
@@ -208,10 +208,11 @@ int decode_packet(bot_t *bot, void *packet_raw, void *packet_data){
208208
// packet_data = struct containing packet data
209209
uint32_t len;
210210
vint32_t value;
211-
uint32_t arr_len;
211+
uint32_t arr_len = -1;
212212
size_t size;
213213

214214
char *fmt = *((char **)packet_data);
215+
assert(fmt != 0);
215216
packet_data += sizeof(void *);
216217

217218
int32_t packet_size;
@@ -239,6 +240,10 @@ int decode_packet(bot_t *bot, void *packet_raw, void *packet_data){
239240
case '*':
240241
fmt++;
241242
size_t size_elem = format_sizeof(*fmt);
243+
assert(arr_len != -1);
244+
if(arr_len != 0) {
245+
break;
246+
}
242247
void *arr = calloc(arr_len, size_elem);
243248
for(int i = 0; i < arr_len * size_elem; i += size_elem){
244249
memcpy(arr + i, packet_raw + i, size_elem);

src/protocol.c

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
1+
#include <stdio.h>
22
#include "protocol.h"
33
#include "marshal.h"
44
#include "bot.h"
@@ -16,8 +16,8 @@
1616
// Macro to fill structs in the callback switch
1717
#define _render_callback(NAME) { \
1818
recv_struct = recv_ ## NAME(bot); \
19-
while(func) { \
20-
((void (*)(NAME ## _t *))func->f)((NAME ## _t *) recv_struct); \
19+
while(func->next) { \
20+
(func->f)(bot, recv_struct); \
2121
func = func->next; \
2222
} \
2323
break; \
@@ -629,7 +629,6 @@ _render_recv(play_clientbound_chunk_bulk, "vbvwwh*b", 0x26);
629629
_render_recv(play_clientbound_explosion, "vwwwww*wwww", 0x27);
630630
_render_recv(play_clientbound_effect, "vwlwb", 0x28);
631631
_render_recv(play_clientbound_sound_effect, "vswwwwb", 0x29);
632-
_render_recv(play_clientbound_particle, "vvbwwwwwwww*v", 0x2A);
633632
_render_recv(play_clientbound_entity_spawn_global, "vvbwww", 0x2C);
634633
_render_recv(play_clientbound_update_sign, "vlssss", 0x33);
635634
_render_recv(play_clientbound_plugin_message, "vs*b", 0x3F);
@@ -638,8 +637,12 @@ _render_recv(play_clientbound_plugin_difficulty, "vb", 0x41);
638637
_render_recv(play_clientbound_set_compression, "vv", 0x46);
639638

640639
void callback_decode(bot_t *bot) {
641-
uint32_t pid = receive_packet(bot);
642-
function *func = bot->callbacks[bot->current_state][pid];
640+
int32_t pid = receive_packet(bot);
641+
if (pid < 0) {
642+
if (pid == -1) exit(123);
643+
return;
644+
}
645+
function *func = &bot->callbacks[bot->current_state][pid];
643646
void *recv_struct;
644647
switch (bot->current_state) {
645648
case HANDSHAKE:
@@ -702,7 +705,6 @@ void callback_decode(bot_t *bot) {
702705
case 0x27: _render_callback(play_clientbound_explosion);
703706
case 0x28: _render_callback(play_clientbound_effect);
704707
case 0x29: _render_callback(play_clientbound_sound_effect);
705-
case 0x2A: _render_callback(play_clientbound_particle);
706708
case 0x2C: _render_callback(play_clientbound_entity_spawn_global);
707709
case 0x33: _render_callback(play_clientbound_update_sign);
708710
case 0x3F: _render_callback(play_clientbound_plugin_message);

src/protocol.h

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -531,23 +531,6 @@ typedef struct play_clientbound_sound_effect {
531531
uint8_t pitch;
532532
} play_clientbound_sound_effect_t;
533533

534-
typedef struct play_clientbound_particle {
535-
char* format;
536-
vint32_t packet_id;
537-
538-
vint32_t particle_id;
539-
bool long_distance;
540-
float x;
541-
float y;
542-
float z;
543-
float dx;
544-
float dy;
545-
float dz;
546-
float particle_data;
547-
int32_t count;
548-
vint32_t* data;
549-
} play_clientbound_particle_t;
550-
551534
typedef struct play_clientbound_entity_spawn_global {
552535
char* format;
553536
vint32_t packet_id;
@@ -1096,9 +1079,6 @@ recv_play_clientbound_effect(bot_t* bot);
10961079
play_clientbound_sound_effect_t*
10971080
recv_play_clientbound_sound_effect(bot_t* bot);
10981081

1099-
play_clientbound_particle_t*
1100-
recv_play_clientbound_particle(bot_t* bot);
1101-
11021082
play_clientbound_entity_spawn_global_t*
11031083
recv_play_clientbound_entity_spawn_global(bot_t* bot);
11041084

0 commit comments

Comments
 (0)