Skip to content

Instantly share code, notes, and snippets.

@deoxxa
Created May 24, 2012 14:35
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save deoxxa/2781929 to your computer and use it in GitHub Desktop.
Save deoxxa/2781929 to your computer and use it in GitHub Desktop.
Silly zero-copy minecraft protocol parser idea!
CFLAGS += -std=c99 -Wall -Werror -Wextra -pedantic -O0 -g
all: test
parser.o: parser.c
$(CC) $(CFLAGS) $(LDFLAGS) -c -o parser.o parser.c
test.o: test.c
$(CC) $(CFLAGS) $(LDFLAGS) -c -o test.o test.c
test: parser.o test.o
$(CC) $(CFLAGS) $(LDFLAGS) -o test test.o parser.o
clean:
rm -f *.o test
#ifndef PARSER_PACKETS_H
#define PARSER_PACKETS_H
#include <stdint.h>
#define PACKET_LENGTH 1
typedef struct protocol_packet_s {
uint8_t type;
} protocol_packet_t;
#define PACKET_LENGTH_00 5
typedef struct protocol_packet_00_s {
uint8_t type;
int32_t id;
} protocol_packet_00_t;
#endif
#include <stdlib.h>
#include <sys/types.h>
#define __USE_BSD
#include <endian.h>
#include "parser.h"
#include "packets.h"
#define UNUSED(x) (void)(x)
#define PARSER_CASE(x) case 0x##x: { if (data_len < PACKET_LENGTH_##x) { return 0; } else { return protocol_parser_parse_##x(parser, settings, data, data_len); } }
size_t protocol_parser_execute(protocol_parser_t* parser, protocol_parser_settings_t* settings, char* data, size_t data_len) {
if (data_len < 1) {
return 0;
}
switch (data[0]) {
PARSER_CASE(00);
default: {
if (settings->on_error != NULL) {
settings->on_error(parser, -1);
}
return 0;
}
}
return 0;
}
size_t protocol_parser_parse_00(protocol_parser_t* parser, protocol_parser_settings_t* settings, char* data, size_t data_len) {
protocol_packet_00_t packet;
UNUSED(data_len);
packet.type = data[0];
packet.id = htobe32(*((int32_t*)(data + 1)));
if (settings->on_packet != NULL) {
settings->on_packet(parser, (protocol_packet_t*)&packet);
}
return 5;
}
#ifndef PARSER_H
#define PARSER_H
#include "packets.h"
typedef struct protocol_parser_s {
void* data;
} protocol_parser_t;
typedef void (*packet_cb)(protocol_parser_t* parser, protocol_packet_t* packet);
typedef void (*error_cb)(protocol_parser_t* parser, int err);
typedef struct protocol_parser_settings_s {
packet_cb on_packet;
error_cb on_error;
} protocol_parser_settings_t;
size_t protocol_parser_execute(protocol_parser_t* parser, protocol_parser_settings_t* settings, char* data, size_t data_len);
size_t protocol_parser_parse_00(protocol_parser_t* parser, protocol_parser_settings_t* settings, char* data, size_t data_len);
#endif
#include <stdio.h>
#include <stdlib.h>
#include "parser.h"
#include "packets.h"
void on_packet(protocol_parser_t* parser, protocol_packet_t* packet) {
printf("[%p] packet type: %02x\n", parser->data, packet->type);
if (packet->type == 0x00) {
protocol_packet_00_t* packet_00 = (protocol_packet_00_t*)packet;
printf("-> id: %d\n", packet_00->id);
}
}
void on_error(protocol_parser_t* parser, int err) {
printf("[%p] error %d\n", parser->data, err);
}
int main() {
protocol_parser_t parser = { .data = NULL };
protocol_parser_settings_t settings = { .on_packet = on_packet, .on_error = on_error };
char data[] = { 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02 };
size_t nparsed = 0, offset = 0;
while ((nparsed = protocol_parser_execute(&parser, &settings, data + offset, 10 - offset)) != 0) {
printf("parsed %d bytes\n", nparsed);
offset += nparsed;
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment