Skip to content

Commit

Permalink
Merge pull request #19 from NosotrosNueces/sample-bot-r
Browse files Browse the repository at this point in the history
First Sample Bot
  • Loading branch information
jeversmann committed Oct 5, 2014
2 parents b94ed6d + a02f9bc commit 1ccbdc5
Show file tree
Hide file tree
Showing 9 changed files with 122 additions and 99 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
CC = clang
SA = scan-build
_LIB_FILES = marshal.c protocol.c bot.c
_LIB_FILES = marshal.c protocol.c bot.c client.c
_TEST_FILES = packet_test.c protocol_test.c test_runner.c
LIB_DIR = src
TEST_DIR = test
LIB_FILES= $(patsubst %,$(LIB_DIR)/%,$(_LIB_FILES))
TEST_FILES= $(patsubst %,$(TEST_DIR)/%,$(_TEST_FILES))
CFLAGS=-Wall --std=gnu99 -Wfatal-errors
CFLAGS=-Wall --std=gnu99 -Wfatal-errors -lpthread -g
tests: bin
$(CC) -o bin/tests $(LIB_FILES) $(TEST_FILES) -I $(LIB_DIR) $(CFLAGS)
./bin/tests
Expand Down
70 changes: 29 additions & 41 deletions src/bot.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,16 @@ bot_t *init_bot(char *name, void (*bot_main)(void *)){
// set the bot name
bot_t *bot = calloc(1, sizeof(bot_t));
bot->packet_threshold = DEFAULT_THRESHOLD;
bot->buf = calloc(1, DEFAULT_THRESHOLD);
size_t len = strlen(name);
bot->name = calloc(len + 1, sizeof(char));
strncpy(bot->name, name, len + 1);
bot->bot_main = bot_main;
// initialize the callback data structure
bot->callbacks = calloc(NUM_STATES, sizeof(function **));
bot->callbacks[HANDSHAKE] = calloc(HANDSHAKE_PACKETS, sizeof(function *));
bot->callbacks[LOGIN] = calloc(LOGIN_PACKETS, sizeof(function *));
bot->callbacks[PLAY] = calloc(PLAY_PACKETS, sizeof(function *));
bot->callbacks = calloc(NUM_STATES, sizeof(function *));
bot->callbacks[HANDSHAKE] = calloc(HANDSHAKE_PACKETS, sizeof(function));
bot->callbacks[LOGIN] = calloc(LOGIN_PACKETS, sizeof(function));
bot->callbacks[PLAY] = calloc(PLAY_PACKETS, sizeof(function));
return bot;
}

Expand All @@ -37,15 +38,15 @@ void free_bot(bot_t *bot){
// unrolled outer loop just cuz
int i;
for(i = 0; i < HANDSHAKE_PACKETS; i++){
function *func = bot->callbacks[HANDSHAKE][i];
function *func = &bot->callbacks[HANDSHAKE][i];
free_list(func);
}
for(i = 0; i < LOGIN_PACKETS; i++){
function *func = bot->callbacks[LOGIN][i];
function *func = &bot->callbacks[LOGIN][i];
free_list(func);
}
for(i = 0; i < PLAY_PACKETS; i++){
function *func = bot->callbacks[PLAY][i];
function *func = &bot->callbacks[PLAY][i];
free_list(func);
}
free(bot);
Expand All @@ -59,50 +60,33 @@ void free_list(function *list){


void register_event(bot_t *bot, uint32_t state, uint32_t packet_id,
void (*f)(void *)){
function *current = bot->callbacks[state][packet_id];
while(current)
current = current->next;
current = calloc(1, sizeof(function));
current->f = f;
void (*f)(bot_t *, void *)){
function *parent = &bot->callbacks[state][packet_id];
while(parent->next)
parent = parent->next;
function *child = calloc(1, sizeof(function));
parent->f = f;
parent->next = child;
}

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

int join_server(bot_t *your_bot, char *local_port, char* server_host,
char* server_port){
int status;
int join_server(bot_t *your_bot, char* server_host, char* server_port){
struct addrinfo hints, *res;
int sockfd;
memset(&hints, 0, sizeof(hints));
// first, load up address structs with getaddrinfo():
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if((status = getaddrinfo(NULL, local_port, &hints, &res))){
fprintf(stderr, "Your computer is literally haunted: %s\n",
gai_strerror(status));
return -1;
}
if((sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1){
fprintf(stderr, "Could not create socket for unknown reason.\n");
return -1;
}
freeaddrinfo(res);
// socket bound to local address/port
getaddrinfo(server_host, server_port, &hints, &res);

memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if((status = getaddrinfo(server_host, server_port, &hints, &res))){
fprintf(stderr, "Server could not be resolved: %s\n",
gai_strerror(status));
return -1;
}
// make a socket and connect
sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
connect(sockfd, res->ai_addr, res->ai_addrlen);
freeaddrinfo(res);
// connected to server

your_bot->socketfd = sockfd;
return sockfd;
}
Expand Down Expand Up @@ -148,7 +132,7 @@ int receive_packet(bot_t *bot) {
assert(i != len);

packet_size += len;
received = len + 1;
received = i + 1;
if (packet_size <= bot->packet_threshold) {
while (received < packet_size) {
ret = receive_raw(bot, bot->buf + received, packet_size - received);
Expand All @@ -160,13 +144,17 @@ int receive_packet(bot_t *bot) {
ret = peek_packet(bot, bot->buf);
return ret;
} else {
// read in a huge buffer, but throw it away
while (received < packet_size) {
// read in a huge buffer, packet_threshold at a time
while (received < packet_size - bot->packet_threshold) {
ret = receive_raw(bot, bot->buf, bot->packet_threshold);
if (ret <= 0)
return -1;
received += ret;
}
// read the last portion of the packet
ret = receive_raw(bot, bot->buf, packet_size - received);
if (ret <= 0)
return -1;
return -2;
}
}
25 changes: 13 additions & 12 deletions src/bot.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,24 @@

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

typedef struct _function {
void (*f)(void *);
struct _function *next;
} function;
typedef struct bot bot_t;
typedef struct _function function;

typedef struct bot {
struct bot {
int socketfd;
size_t packet_threshold;
char *buf;
char *name;
state current_state;
/* registered callbacks */
void (*bot_main)(void *);
function ***callbacks; // triple indirection hooray!
} bot_t;
function **callbacks;
};

struct _function {
void (*f)(bot_t *, void *);
struct _function *next;
};

extern struct bot context;

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

/** \brief Open a socket to the specified server
*
* Open a socket connection to a specific server for a particular bot. It is
* possible, but not useful, to choose the local bind port. A local_port value
* of NULL should choose a random, open port.
* Open a socket connection to a specific server for a particular bot.
*/
int join_server(bot_t *bot, char *local_port, char* server_host, char* server_port);
int join_server(bot_t *bot, char* server_host, char* server_port);

/** \brief Sends a string across the network using a bot's socket
*
Expand Down
20 changes: 16 additions & 4 deletions src/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,29 +31,41 @@ void *bot_thread(void *bot);
void client_run(bot_t *bots, uint32_t num) {
// create 1 thread for receiving packets, and 1 for each bot
int i;
bot_list = bots;
num_bots = num;
bot_list = bots;
pthread_key_create(&bot_key, NULL);

// create & start listener thread
pthread_t event_listener;
pthread_create(&event_listener, NULL, receiver, NULL);

// create all the bot threads
bot_threads = calloc(num_bots, sizeof(pthread_t));
for(i = 0; i < num; i++) {
pthread_create(bot_threads + i, NULL, bot_thread, bot_list + i);
pthread_create(bot_threads + i, NULL, bot_thread, bot_list + i);
}

// wait for all threads to finish
// TODO: support for exit codes
pthread_join(event_listener, NULL);
for(i = 0; i < num; i++) {
pthread_join(bot_threads[i], NULL);
}
free(bot_threads);
}

void *bot_thread(void *bot) {
pthread_setspecific(bot_key, bot);

struct sigaction sa;
sa.sa_handler = signal_handler;
sa.sa_flags = SA_RESTART;
sigemptyset(&sa.sa_mask);
if (sigaction(SIGUSR1, &sa, NULL) == -1) {
perror("sigaction");
exit(1);
}

((bot_t *)bot)->bot_main(bot);
return NULL;
}
Expand Down
7 changes: 0 additions & 7 deletions src/client.h
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
#include "bot.h"
#include <pthread.h>
#include <poll.h>
#include <unistd.h>
#include <signal.h>
#include "protocol.h"
#include <errno.h>
#include <stdio.h>

void client_run(bot_t *, uint32_t);

Expand Down
9 changes: 7 additions & 2 deletions src/marshal.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "marshal.h"
#include "bot.h"
#include "protocol.h"
Expand Down Expand Up @@ -181,7 +182,6 @@ int format_packet(bot_t *bot, void *packet_data, void **packet_raw_ptr){
break;
default:
;
size_t size = format_sizeof(*fmt);
if(index + size > len)
return -1; // TODO: compression
memcpy(packet_raw + index, packet_data, size);
Expand All @@ -208,10 +208,11 @@ int decode_packet(bot_t *bot, void *packet_raw, void *packet_data){
// packet_data = struct containing packet data
uint32_t len;
vint32_t value;
uint32_t arr_len;
uint32_t arr_len = -1;
size_t size;

char *fmt = *((char **)packet_data);
assert(fmt != 0);
packet_data += sizeof(void *);

int32_t packet_size;
Expand Down Expand Up @@ -239,6 +240,10 @@ int decode_packet(bot_t *bot, void *packet_raw, void *packet_data){
case '*':
fmt++;
size_t size_elem = format_sizeof(*fmt);
assert(arr_len != -1);
if(arr_len != 0) {
break;
}
void *arr = calloc(arr_len, size_elem);
for(int i = 0; i < arr_len * size_elem; i += size_elem){
memcpy(arr + i, packet_raw + i, size_elem);
Expand Down
16 changes: 9 additions & 7 deletions src/protocol.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@

#include <stdio.h>
#include "protocol.h"
#include "marshal.h"
#include "bot.h"
Expand All @@ -16,8 +16,8 @@
// Macro to fill structs in the callback switch
#define _render_callback(NAME) { \
recv_struct = recv_ ## NAME(bot); \
while(func) { \
((void (*)(NAME ## _t *))func->f)((NAME ## _t *) recv_struct); \
while(func->next) { \
(func->f)(bot, recv_struct); \
func = func->next; \
} \
break; \
Expand Down Expand Up @@ -629,7 +629,6 @@ _render_recv(play_clientbound_chunk_bulk, "vbvwwh*b", 0x26);
_render_recv(play_clientbound_explosion, "vwwwww*wwww", 0x27);
_render_recv(play_clientbound_effect, "vwlwb", 0x28);
_render_recv(play_clientbound_sound_effect, "vswwwwb", 0x29);
_render_recv(play_clientbound_particle, "vvbwwwwwwww*v", 0x2A);
_render_recv(play_clientbound_entity_spawn_global, "vvbwww", 0x2C);
_render_recv(play_clientbound_update_sign, "vlssss", 0x33);
_render_recv(play_clientbound_plugin_message, "vs*b", 0x3F);
Expand All @@ -638,8 +637,12 @@ _render_recv(play_clientbound_plugin_difficulty, "vb", 0x41);
_render_recv(play_clientbound_set_compression, "vv", 0x46);

void callback_decode(bot_t *bot) {
uint32_t pid = receive_packet(bot);
function *func = bot->callbacks[bot->current_state][pid];
int32_t pid = receive_packet(bot);
if (pid < 0) {
if (pid == -1) exit(123);
return;
}
function *func = &bot->callbacks[bot->current_state][pid];
void *recv_struct;
switch (bot->current_state) {
case HANDSHAKE:
Expand Down Expand Up @@ -702,7 +705,6 @@ void callback_decode(bot_t *bot) {
case 0x27: _render_callback(play_clientbound_explosion);
case 0x28: _render_callback(play_clientbound_effect);
case 0x29: _render_callback(play_clientbound_sound_effect);
case 0x2A: _render_callback(play_clientbound_particle);
case 0x2C: _render_callback(play_clientbound_entity_spawn_global);
case 0x33: _render_callback(play_clientbound_update_sign);
case 0x3F: _render_callback(play_clientbound_plugin_message);
Expand Down
20 changes: 0 additions & 20 deletions src/protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -531,23 +531,6 @@ typedef struct play_clientbound_sound_effect {
uint8_t pitch;
} play_clientbound_sound_effect_t;

typedef struct play_clientbound_particle {
char* format;
vint32_t packet_id;

vint32_t particle_id;
bool long_distance;
float x;
float y;
float z;
float dx;
float dy;
float dz;
float particle_data;
int32_t count;
vint32_t* data;
} play_clientbound_particle_t;

typedef struct play_clientbound_entity_spawn_global {
char* format;
vint32_t packet_id;
Expand Down Expand Up @@ -1096,9 +1079,6 @@ recv_play_clientbound_effect(bot_t* bot);
play_clientbound_sound_effect_t*
recv_play_clientbound_sound_effect(bot_t* bot);

play_clientbound_particle_t*
recv_play_clientbound_particle(bot_t* bot);

play_clientbound_entity_spawn_global_t*
recv_play_clientbound_entity_spawn_global(bot_t* bot);

Expand Down
Loading

0 comments on commit 1ccbdc5

Please sign in to comment.